From 87a7fca8a3db019e191447526b3e291514aa0725 Mon Sep 17 00:00:00 2001 From: "waqas.ikram" Date: Fri, 29 Jan 2021 15:24:07 +0000 Subject: [PATCH] Adding endpoints to SDC simulator for ETSI NFVO NS LCM Usecase Change-Id: I1a626dce2a24364a81076e4a860a9b658edf2d59 Issue-ID: INT-1839 Signed-off-by: waqas.ikram --- .../sdcsimulator/controller/CatalogController.java | 46 +++- .../org/onap/so/sdcsimulator/models/Artifact.java | 234 ++++++++++++++++++ .../{ResourceArtifact.java => AssetInfo.java} | 65 ++--- .../org/onap/so/sdcsimulator/models/AssetType.java | 31 +++ .../org/onap/so/sdcsimulator/models/Metadata.java | 104 ++++++++ .../org/onap/so/sdcsimulator/models/Resource.java | 198 +++++++++++++++ .../so/sdcsimulator/models/ResourceAssetInfo.java | 81 ++++++ .../so/sdcsimulator/models/ServiceAssetInfo.java | 82 ++++++ .../{ResourceProvider.java => AssetProvider.java} | 14 +- .../sdcsimulator/providers/AssetProviderImpl.java | 274 +++++++++++++++++++++ .../providers/ResourceProviderImpl.java | 174 ------------- .../org/onap/so/sdcsimulator/utils/Constants.java | 6 +- .../73522444-e8e9-49c1-be29-d355800aa349.csar | Bin .../73522444-e8e9-49c1-be29-d355800aa349.json | 116 +++++++++ .../9bb8c882-44a1-4b67-a12c-5a998e18d6ba.csar} | Bin 116913 -> 147743 bytes .../9bb8c882-44a1-4b67-a12c-5a998e18d6ba.json | 62 +++++ .../src/main/resources/csar/default_csar_file.csar | Bin 3982 -> 0 bytes .../controller/CatalogControllerTest.java | 80 ++++-- ...derImplTest.java => AssetProviderImplTest.java} | 33 +-- 19 files changed, 1351 insertions(+), 249 deletions(-) create mode 100644 plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/Artifact.java rename plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/{ResourceArtifact.java => AssetInfo.java} (81%) create mode 100644 plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/AssetType.java create mode 100644 plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/Metadata.java create mode 100644 plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/Resource.java create mode 100644 plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/ResourceAssetInfo.java create mode 100644 plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/ServiceAssetInfo.java rename plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/providers/{ResourceProvider.java => AssetProvider.java} (69%) create mode 100644 plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/providers/AssetProviderImpl.java delete mode 100644 plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/providers/ResourceProviderImpl.java rename plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/resources/csar/{ => RESOURCES}/73522444-e8e9-49c1-be29-d355800aa349.csar (100%) create mode 100644 plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/resources/csar/RESOURCES/73522444-e8e9-49c1-be29-d355800aa349.json rename plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/resources/csar/{ba1c0c0e-9fb8-4b83-97bb-5e9af1e73393.csar => SERVICES/9bb8c882-44a1-4b67-a12c-5a998e18d6ba.csar} (57%) create mode 100644 plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/resources/csar/SERVICES/9bb8c882-44a1-4b67-a12c-5a998e18d6ba.json delete mode 100644 plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/resources/csar/default_csar_file.csar rename plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/test/java/org/onap/so/sdcsimulator/providers/{ResourceProviderImplTest.java => AssetProviderImplTest.java} (67%) diff --git a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/controller/CatalogController.java b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/controller/CatalogController.java index eff63b84..f22bcf69 100644 --- a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/controller/CatalogController.java +++ b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/controller/CatalogController.java @@ -22,7 +22,9 @@ package org.onap.so.sdcsimulator.controller; import static org.onap.so.sdcsimulator.utils.Constants.CATALOG_URL; import java.util.Optional; import javax.ws.rs.core.MediaType; -import org.onap.so.sdcsimulator.providers.ResourceProvider; +import org.onap.so.sdcsimulator.models.AssetType; +import org.onap.so.sdcsimulator.models.Metadata; +import org.onap.so.sdcsimulator.providers.AssetProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -42,23 +44,23 @@ import org.springframework.web.bind.annotation.RequestMapping; public class CatalogController { private static final Logger LOGGER = LoggerFactory.getLogger(CatalogController.class); - private ResourceProvider resourceProvider; + private AssetProvider resourceProvider; @Autowired - public CatalogController(final ResourceProvider resourceProvider) { + public CatalogController(final AssetProvider resourceProvider) { this.resourceProvider = resourceProvider; } @GetMapping(value = "/resources", produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public ResponseEntity getResources() { LOGGER.info("Running getResources ..."); - return ResponseEntity.ok().body(resourceProvider.getResource()); + return ResponseEntity.ok().body(resourceProvider.getAssetInfo(AssetType.RESOURCES)); } @GetMapping(value = "/resources/{csarId}/toscaModel", produces = MediaType.APPLICATION_OCTET_STREAM) public ResponseEntity getCsar(@PathVariable("csarId") final String csarId) { LOGGER.info("Running getCsar for {} ...", csarId); - final Optional resource = resourceProvider.getResource(csarId); + final Optional resource = resourceProvider.getAsset(csarId, AssetType.RESOURCES); if (resource.isPresent()) { return new ResponseEntity<>(resource.get(), HttpStatus.OK); } @@ -67,4 +69,38 @@ public class CatalogController { return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } + @GetMapping(value = "/resources/{csarId}/metadata", + produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public ResponseEntity getResourceMetadata(@PathVariable("csarId") final String csarId) { + LOGGER.info("Running getResourceMetadata for {} ...", csarId); + final Optional resource = resourceProvider.getMetadata(csarId, AssetType.RESOURCES); + if (resource.isPresent()) { + return new ResponseEntity<>(resource.get(), HttpStatus.OK); + } + LOGGER.error("Unable to find metadata for csarId: {}", csarId); + + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + + + @GetMapping(value = "/services", produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public ResponseEntity getServices() { + LOGGER.info("Running getServices ..."); + return ResponseEntity.ok().body(resourceProvider.getAssetInfo(AssetType.SERVICES)); + } + + @GetMapping(value = "/services/{csarId}/metadata", + produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public ResponseEntity getServiceMetadata(@PathVariable("csarId") final String csarId) { + LOGGER.info("Running getServiceMetadata for {} ...", csarId); + final Optional resource = resourceProvider.getMetadata(csarId, AssetType.SERVICES); + if (resource.isPresent()) { + return new ResponseEntity<>(resource.get(), HttpStatus.OK); + } + LOGGER.error("Unable to find metadata for csarId: {}", csarId); + + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + + } diff --git a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/Artifact.java b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/Artifact.java new file mode 100644 index 00000000..51bd18b1 --- /dev/null +++ b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/Artifact.java @@ -0,0 +1,234 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.sdcsimulator.models; + +import java.io.Serializable; +import org.springframework.util.ObjectUtils; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class Artifact implements Serializable { + + private static final long serialVersionUID = 4106531921550274666L; + + @JsonProperty("artifactName") + private String artifactName; + + @JsonProperty("artifactType") + private String artifactType; + + @JsonProperty("artifactURL") + private String artifactUrl; + + @JsonProperty("artifactDescription") + private String artifactDescription; + + @JsonProperty("artifactChecksum") + private String artifactChecksum; + + @JsonProperty("artifactUUID") + private String artifactUuid; + + @JsonProperty("artifactVersion") + private String artifactVersion; + + @JsonProperty("artifactLabel") + private String artifactLabel; + + @JsonProperty("artifactGroupType") + private String artifactGroupType; + + public String getArtifactName() { + return artifactName; + } + + public void setArtifactName(final String artifactName) { + this.artifactName = artifactName; + } + + public Artifact artifactName(final String artifactName) { + this.artifactName = artifactName; + return this; + } + + public String getArtifactType() { + return artifactType; + } + + public void setArtifactType(final String artifactType) { + this.artifactType = artifactType; + } + + public Artifact artifactType(final String artifactType) { + this.artifactType = artifactType; + return this; + } + + public String getArtifactUrl() { + return artifactUrl; + } + + public void setArtifactUrl(final String artifactUrl) { + this.artifactUrl = artifactUrl; + } + + public Artifact artifactUrl(final String artifactURL) { + this.artifactUrl = artifactURL; + return this; + } + + public String getArtifactDescription() { + return artifactDescription; + } + + public void setArtifactDescription(final String artifactDescription) { + this.artifactDescription = artifactDescription; + } + + public Artifact artifactDescription(final String artifactDescription) { + this.artifactDescription = artifactDescription; + return this; + } + + public String getArtifactChecksum() { + return artifactChecksum; + } + + public void setArtifactChecksum(final String artifactChecksum) { + this.artifactChecksum = artifactChecksum; + } + + public Artifact artifactChecksum(final String artifactChecksum) { + this.artifactChecksum = artifactChecksum; + return this; + } + + public String getArtifactUuid() { + return artifactUuid; + } + + public void setArtifactUuid(final String artifactUuid) { + this.artifactUuid = artifactUuid; + } + + public Artifact artifactUuid(final String artifactUuid) { + this.artifactUuid = artifactUuid; + return this; + } + + public String getArtifactVersion() { + return artifactVersion; + } + + public void setArtifactVersion(final String artifactVersion) { + this.artifactVersion = artifactVersion; + } + + public Artifact artifactVersion(final String artifactVersion) { + this.artifactVersion = artifactVersion; + return this; + } + + public String getArtifactLabel() { + return artifactLabel; + } + + public void setArtifactLabel(final String artifactLabel) { + this.artifactLabel = artifactLabel; + } + + public Artifact artifactLabel(final String artifactLabel) { + this.artifactLabel = artifactLabel; + return this; + } + + public String getArtifactGroupType() { + return artifactGroupType; + } + + public void setArtifactGroupType(final String artifactGroupType) { + this.artifactGroupType = artifactGroupType; + } + + public Artifact artifactGroupType(final String artifactGroupType) { + this.artifactGroupType = artifactGroupType; + return this; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((artifactChecksum == null) ? 0 : artifactChecksum.hashCode()); + result = prime * result + ((artifactDescription == null) ? 0 : artifactDescription.hashCode()); + result = prime * result + ((artifactGroupType == null) ? 0 : artifactGroupType.hashCode()); + result = prime * result + ((artifactLabel == null) ? 0 : artifactLabel.hashCode()); + result = prime * result + ((artifactName == null) ? 0 : artifactName.hashCode()); + result = prime * result + ((artifactType == null) ? 0 : artifactType.hashCode()); + result = prime * result + ((artifactUrl == null) ? 0 : artifactUrl.hashCode()); + result = prime * result + ((artifactUuid == null) ? 0 : artifactUuid.hashCode()); + result = prime * result + ((artifactVersion == null) ? 0 : artifactVersion.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof AssetInfo) { + final Artifact other = (Artifact) obj; + return ObjectUtils.nullSafeEquals(artifactChecksum, other.artifactChecksum) + && ObjectUtils.nullSafeEquals(artifactDescription, other.artifactDescription) + && ObjectUtils.nullSafeEquals(artifactGroupType, other.artifactGroupType) + && ObjectUtils.nullSafeEquals(artifactLabel, other.artifactLabel) + && ObjectUtils.nullSafeEquals(artifactGroupType, other.artifactGroupType) + && ObjectUtils.nullSafeEquals(artifactName, other.artifactName) + && ObjectUtils.nullSafeEquals(artifactType, other.artifactType) + && ObjectUtils.nullSafeEquals(artifactUrl, other.artifactUrl) + && ObjectUtils.nullSafeEquals(artifactUuid, other.artifactUuid) + && ObjectUtils.nullSafeEquals(artifactVersion, other.artifactVersion); + + + } + return false; + + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("class Artifact {\n"); + sb.append(" artifactName: ").append(artifactName).append("\n"); + sb.append(" artifactType: ").append(artifactType).append("\n"); + sb.append(" artifactURL: ").append(artifactUrl).append("\n"); + sb.append(" artifactDescription: ").append(artifactDescription).append("\n"); + sb.append(" artifactChecksum: ").append(artifactChecksum).append("\n"); + sb.append(" artifactUUID: ").append(artifactUuid).append("\n"); + sb.append(" artifactVersion: ").append(artifactVersion).append("\n"); + sb.append(" artifactLabel: ").append(artifactLabel).append("\n"); + sb.append(" artifactGroupType: ").append(artifactGroupType).append("\n"); + + sb.append("}"); + return sb.toString(); + + } +} diff --git a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/ResourceArtifact.java b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/AssetInfo.java similarity index 81% rename from plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/ResourceArtifact.java rename to plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/AssetInfo.java index 0b9e6cf1..39055cf5 100644 --- a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/ResourceArtifact.java +++ b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/AssetInfo.java @@ -27,7 +27,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; * @author Waqas Ikram (waqas.ikram@est.tech) * */ -public class ResourceArtifact implements Serializable { +public class AssetInfo implements Serializable { private static final long serialVersionUID = 3967660000071162759L; @@ -49,9 +49,6 @@ public class ResourceArtifact implements Serializable { @JsonProperty("category") private String category; - @JsonProperty("subCategory") - private String subCategory; - @JsonProperty("resourceType") private String resourceType; @@ -61,6 +58,9 @@ public class ResourceArtifact implements Serializable { @JsonProperty("lastUpdaterUserId") private String lastUpdaterUserId; + @JsonProperty("toscaResourceName") + private String toscaResourceName; + public String getUuid() { return uuid; } @@ -69,7 +69,7 @@ public class ResourceArtifact implements Serializable { this.uuid = uuid; } - public ResourceArtifact uuid(final String uuid) { + public AssetInfo uuid(final String uuid) { this.uuid = uuid; return this; } @@ -82,7 +82,7 @@ public class ResourceArtifact implements Serializable { this.invariantUuid = invariantUuid; } - public ResourceArtifact invariantUuid(final String invariantUuid) { + public AssetInfo invariantUuid(final String invariantUuid) { this.invariantUuid = invariantUuid; return this; } @@ -95,7 +95,7 @@ public class ResourceArtifact implements Serializable { this.name = name; } - public ResourceArtifact name(final String name) { + public AssetInfo name(final String name) { this.name = name; return this; } @@ -108,7 +108,7 @@ public class ResourceArtifact implements Serializable { this.version = version; } - public ResourceArtifact version(final String version) { + public AssetInfo version(final String version) { this.version = version; return this; } @@ -121,7 +121,7 @@ public class ResourceArtifact implements Serializable { this.toscaModelUrl = toscaModelUrl; } - public ResourceArtifact toscaModelUrl(final String toscaModelUrl) { + public AssetInfo toscaModelUrl(final String toscaModelUrl) { this.toscaModelUrl = toscaModelUrl; return this; } @@ -134,24 +134,11 @@ public class ResourceArtifact implements Serializable { this.category = category; } - public ResourceArtifact category(final String category) { + public AssetInfo category(final String category) { this.category = category; return this; } - public String getSubCategory() { - return subCategory; - } - - public void setSubCategory(final String subCategory) { - this.subCategory = subCategory; - } - - public ResourceArtifact subCategory(final String subCategory) { - this.subCategory = subCategory; - return this; - } - public String getResourceType() { return resourceType; } @@ -160,7 +147,7 @@ public class ResourceArtifact implements Serializable { this.resourceType = resourceType; } - public ResourceArtifact resourceType(final String resourceType) { + public AssetInfo resourceType(final String resourceType) { this.resourceType = resourceType; return this; } @@ -173,7 +160,7 @@ public class ResourceArtifact implements Serializable { this.lifecycleState = lifecycleState; } - public ResourceArtifact lifecycleState(final String lifecycleState) { + public AssetInfo lifecycleState(final String lifecycleState) { this.lifecycleState = lifecycleState; return this; } @@ -186,11 +173,24 @@ public class ResourceArtifact implements Serializable { this.lastUpdaterUserId = lastUpdaterUserId; } - public ResourceArtifact lastUpdaterUserId(final String lastUpdaterUserId) { + public AssetInfo lastUpdaterUserId(final String lastUpdaterUserId) { this.lastUpdaterUserId = lastUpdaterUserId; return this; } + public String getToscaResourceName() { + return toscaResourceName; + } + + public void setToscaResourceName(final String toscaResourceName) { + this.toscaResourceName = toscaResourceName; + } + + public AssetInfo toscaResourceName(final String toscaResourceName) { + this.toscaResourceName = toscaResourceName; + return this; + } + @Override public int hashCode() { final int prime = 31; @@ -201,27 +201,27 @@ public class ResourceArtifact implements Serializable { result = prime * result + ((lifecycleState == null) ? 0 : lifecycleState.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((resourceType == null) ? 0 : resourceType.hashCode()); - result = prime * result + ((subCategory == null) ? 0 : subCategory.hashCode()); result = prime * result + ((toscaModelUrl == null) ? 0 : toscaModelUrl.hashCode()); result = prime * result + ((uuid == null) ? 0 : uuid.hashCode()); result = prime * result + ((version == null) ? 0 : version.hashCode()); + return result; } @Override public boolean equals(final Object obj) { - if (obj instanceof ResourceArtifact) { - final ResourceArtifact other = (ResourceArtifact) obj; + if (obj instanceof AssetInfo) { + final AssetInfo other = (AssetInfo) obj; return ObjectUtils.nullSafeEquals(category, other.category) && ObjectUtils.nullSafeEquals(invariantUuid, other.invariantUuid) && ObjectUtils.nullSafeEquals(lastUpdaterUserId, other.lastUpdaterUserId) && ObjectUtils.nullSafeEquals(lifecycleState, other.lifecycleState) && ObjectUtils.nullSafeEquals(name, other.name) && ObjectUtils.nullSafeEquals(resourceType, other.resourceType) - && ObjectUtils.nullSafeEquals(subCategory, other.subCategory) && ObjectUtils.nullSafeEquals(toscaModelUrl, other.toscaModelUrl) && ObjectUtils.nullSafeEquals(uuid, other.uuid) && ObjectUtils.nullSafeEquals(version, other.version); + } return false; } @@ -229,15 +229,16 @@ public class ResourceArtifact implements Serializable { @Override public String toString() { final StringBuilder sb = new StringBuilder(); - sb.append("class ResourceArtifact {\n"); + sb.append("class AssetInfo {\n"); sb.append(" uuid: ").append(uuid).append("\n"); sb.append(" invariantUuid: ").append(invariantUuid).append("\n"); sb.append(" name: ").append(name).append("\n"); sb.append(" version: ").append(version).append("\n"); sb.append(" toscaModelUrl: ").append(toscaModelUrl).append("\n"); sb.append(" category: ").append(category).append("\n"); - sb.append(" subCategory: ").append(subCategory).append("\n"); + sb.append(" lifecycleState: ").append(lifecycleState).append("\n"); sb.append(" lastUpdaterUserId: ").append(lastUpdaterUserId).append("\n"); + sb.append("}"); return sb.toString(); } diff --git a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/AssetType.java b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/AssetType.java new file mode 100644 index 00000000..749a714f --- /dev/null +++ b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/AssetType.java @@ -0,0 +1,31 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.sdcsimulator.models; + + /** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public enum AssetType { + + RESOURCES, SERVICES; + +} diff --git a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/Metadata.java b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/Metadata.java new file mode 100644 index 00000000..4836fc16 --- /dev/null +++ b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/Metadata.java @@ -0,0 +1,104 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.sdcsimulator.models; + +import java.util.HashSet; +import java.util.Set; +import org.springframework.util.ObjectUtils; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class Metadata extends AssetInfo { + + private static final long serialVersionUID = 2754071491333890698L; + + @JsonProperty("resources") + private Set resources = new HashSet<>(); + + @JsonProperty("artifacts") + private Set artifacts = new HashSet<>(); + + + public Set getResources() { + return resources; + } + + public void setResources(final Set resources) { + this.resources = resources; + } + + public Metadata resources(final Set resources) { + this.resources = resources; + return this; + } + + public Set getArtifacts() { + return artifacts; + } + + public void setArtifacts(final Set artifacts) { + this.artifacts = artifacts; + } + + public Metadata artifacts(Set artifacts) { + this.artifacts = artifacts; + return this; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + super.hashCode(); + result = prime * result + ((resources == null) ? 0 : resources.hashCode()); + result = prime * result + ((artifacts == null) ? 0 : artifacts.hashCode()); + + return result; + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof Metadata) { + final Metadata other = (Metadata) obj; + return super.equals(obj) && ObjectUtils.nullSafeEquals(resources, other.resources) + && ObjectUtils.nullSafeEquals(artifacts, other.artifacts); + + } + return false; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append(super.toString()); + sb.deleteCharAt(sb.length() - 1); + sb.append(" resources: ").append(resources).append("\n"); + sb.append(" artifacts: ").append(artifacts).append("\n"); + + sb.append("}"); + return sb.toString(); + } + + +} diff --git a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/Resource.java b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/Resource.java new file mode 100644 index 00000000..6eb3734b --- /dev/null +++ b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/Resource.java @@ -0,0 +1,198 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.sdcsimulator.models; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; +import org.springframework.util.ObjectUtils; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class Resource implements Serializable { + + private static final long serialVersionUID = -8014206400770867160L; + + @JsonProperty("resourceInstanceName") + private String resourceInstanceName; + + @JsonProperty("resourceName") + private String resourceName; + + @JsonProperty("resourceInvariantUUID") + private String resourceInvariantUuid; + + @JsonProperty("resourceVersion") + private String resourceVersion; + + @JsonProperty("resoucreType") + private String resourceType; + + @JsonProperty("resourceUUID") + private String resourceUuid; + + @JsonProperty("artifacts") + private Set artifacts = new HashSet<>(); + + public String getResourceInstanceName() { + return resourceInstanceName; + } + + public void setResourceInstanceName(final String resourceInstanceName) { + this.resourceInstanceName = resourceInstanceName; + } + + public Resource resourceInstanceName(final String resourceInstanceName) { + this.resourceInstanceName = resourceInstanceName; + return this; + } + + public String getResourceName() { + return resourceName; + } + + public void setResourceName(final String resourceName) { + this.resourceName = resourceName; + } + + public Resource resourceName(final String resourceName) { + this.resourceName = resourceName; + return this; + } + + public String getResourceInvariantUuid() { + return resourceInvariantUuid; + } + + public void setResourceInvariantUuid(final String resourceInvariantUuid) { + this.resourceInvariantUuid = resourceInvariantUuid; + } + + public Resource resourceInvariantUuid(final String resourceInvariantUuid) { + this.resourceInvariantUuid = resourceInvariantUuid; + return this; + } + + public String getResourceVersion() { + return resourceVersion; + } + + public void setResourceVersion(final String resourceVersion) { + this.resourceVersion = resourceVersion; + } + + public Resource resourceVersion(final String resourceVersion) { + this.resourceVersion = resourceVersion; + return this; + } + + public String getResourceType() { + return resourceType; + } + + public void setResourceType(final String resourceType) { + this.resourceType = resourceType; + } + + public Resource resourceType(final String resourceType) { + this.resourceType = resourceType; + return this; + } + + public String getResourceUuid() { + return resourceUuid; + } + + public void setResourceUuid(final String resourceUuid) { + this.resourceUuid = resourceUuid; + } + + public Resource resourceUUID(final String resourceUuid) { + this.resourceUuid = resourceUuid; + return this; + } + + public Set getArtifacts() { + return artifacts; + } + + public void setArtifacts(final Set artifacts) { + this.artifacts = artifacts; + } + + public Resource artifacts(final Set artifacts) { + this.artifacts = artifacts; + return this; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((artifacts == null) ? 0 : artifacts.hashCode()); + result = prime * result + ((resourceType == null) ? 0 : resourceType.hashCode()); + result = prime * result + ((resourceInstanceName == null) ? 0 : resourceInstanceName.hashCode()); + result = prime * result + ((resourceInvariantUuid == null) ? 0 : resourceInvariantUuid.hashCode()); + result = prime * result + ((resourceName == null) ? 0 : resourceName.hashCode()); + result = prime * result + ((resourceUuid == null) ? 0 : resourceUuid.hashCode()); + result = prime * result + ((resourceVersion == null) ? 0 : resourceVersion.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof Resource) { + final Resource other = (Resource) obj; + return ObjectUtils.nullSafeEquals(resourceInstanceName, other.resourceInstanceName) + && ObjectUtils.nullSafeEquals(resourceName, other.resourceName) + && ObjectUtils.nullSafeEquals(resourceInvariantUuid, other.resourceInvariantUuid) + && ObjectUtils.nullSafeEquals(resourceVersion, other.resourceVersion) + && ObjectUtils.nullSafeEquals(resourceType, other.resourceType) + && ObjectUtils.nullSafeEquals(resourceUuid, other.resourceUuid) + && ObjectUtils.nullSafeEquals(artifacts, other.artifacts); + } + return false; + + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("class Resource {\n"); + sb.append(" resourceInstanceName: ").append(resourceInstanceName).append("\n"); + sb.append(" resourceName: ").append(resourceName).append("\n"); + sb.append(" resourceInvariantUuid: ").append(resourceInvariantUuid).append("\n"); + sb.append(" resourceVersion: ").append(resourceVersion).append("\n"); + sb.append(" resourceType: ").append(resourceType).append("\n"); + sb.append(" resourceUuid: ").append(resourceUuid).append("\n"); + sb.append(" artifacts: ").append(artifacts).append("\n"); + + sb.append("}"); + return sb.toString(); + + } + + + +} diff --git a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/ResourceAssetInfo.java b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/ResourceAssetInfo.java new file mode 100644 index 00000000..352070a7 --- /dev/null +++ b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/ResourceAssetInfo.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.sdcsimulator.models; + +import org.springframework.util.ObjectUtils; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class ResourceAssetInfo extends AssetInfo { + + private static final long serialVersionUID = -6812049917047990700L; + + @JsonProperty("subCategory") + private String subCategory; + + public String getSubCategory() { + return subCategory; + } + + public void setSubCategory(final String subCategory) { + this.subCategory = subCategory; + } + + public ResourceAssetInfo subCategory(final String subCategory) { + this.subCategory = subCategory; + return this; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + super.hashCode(); + result = prime * result + ((subCategory == null) ? 0 : subCategory.hashCode()); + + return result; + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof ResourceAssetInfo) { + final ResourceAssetInfo other = (ResourceAssetInfo) obj; + return super.equals(obj) && ObjectUtils.nullSafeEquals(subCategory, other.subCategory); + + } + return false; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append(super.toString()); + sb.deleteCharAt(sb.length() - 1); + sb.append(" subCategory: ").append(subCategory).append("\n"); + + sb.append("}"); + return sb.toString(); + } + +} diff --git a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/ServiceAssetInfo.java b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/ServiceAssetInfo.java new file mode 100644 index 00000000..f1fa2bc9 --- /dev/null +++ b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/models/ServiceAssetInfo.java @@ -0,0 +1,82 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.sdcsimulator.models; + +import org.springframework.util.ObjectUtils; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class ServiceAssetInfo extends AssetInfo { + + private static final long serialVersionUID = 1487426510731947767L; + + @JsonProperty("distributionStatus") + private String distributionStatus; + + public String getDistributionStatus() { + return distributionStatus; + } + + public void setDistributionStatus(final String distributionStatus) { + this.distributionStatus = distributionStatus; + } + + public ServiceAssetInfo distributionStatus(final String distributionStatus) { + this.distributionStatus = distributionStatus; + return this; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + super.hashCode(); + result = prime * result + ((distributionStatus == null) ? 0 : distributionStatus.hashCode()); + + return result; + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof ServiceAssetInfo) { + final ServiceAssetInfo other = (ServiceAssetInfo) obj; + return super.equals(obj) && ObjectUtils.nullSafeEquals(distributionStatus, other.distributionStatus); + + } + return false; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append(super.toString()); + sb.deleteCharAt(sb.length() - 1); + sb.append(" distributionStatus: ").append(distributionStatus).append("\n"); + + sb.append("}"); + return sb.toString(); + } + + +} diff --git a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/providers/ResourceProvider.java b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/providers/AssetProvider.java similarity index 69% rename from plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/providers/ResourceProvider.java rename to plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/providers/AssetProvider.java index 48353a7c..3ea077d4 100644 --- a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/providers/ResourceProvider.java +++ b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/providers/AssetProvider.java @@ -22,15 +22,21 @@ package org.onap.so.sdcsimulator.providers; import java.util.Optional; import java.util.Set; -import org.onap.so.sdcsimulator.models.ResourceArtifact; +import org.onap.so.sdcsimulator.models.AssetInfo; +import org.onap.so.sdcsimulator.models.AssetType; +import org.onap.so.sdcsimulator.models.Metadata; /** * @author Eoin Hanan (eoin.hanan@est.tech) + * @author Waqas Ikram (waqas.ikram@est.tech) + * */ -public interface ResourceProvider { +public interface AssetProvider { - Optional getResource(final String csarId); + Optional getAsset(final String csarId, final AssetType assetType); - Set getResource(); + Set getAssetInfo(final AssetType assetType); + + Optional getMetadata(final String csarId, final AssetType assetType); } diff --git a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/providers/AssetProviderImpl.java b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/providers/AssetProviderImpl.java new file mode 100644 index 00000000..d2614029 --- /dev/null +++ b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/providers/AssetProviderImpl.java @@ -0,0 +1,274 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.so.sdcsimulator.providers; + +import static org.onap.so.sdcsimulator.utils.Constants.CATALOG_URL; +import static org.onap.so.sdcsimulator.utils.Constants.DOT_CSAR; +import static org.onap.so.sdcsimulator.utils.Constants.DOT_JSON; +import static org.onap.so.sdcsimulator.utils.Constants.FORWARD_SLASH; +import static org.onap.so.sdcsimulator.utils.Constants.MAIN_RESOURCE_FOLDER; +import static org.onap.so.sdcsimulator.utils.Constants.WILD_CARD_REGEX; +import static org.springframework.core.io.support.ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import org.onap.so.sdcsimulator.models.AssetInfo; +import org.onap.so.sdcsimulator.models.AssetType; +import org.onap.so.sdcsimulator.models.Metadata; +import org.onap.so.sdcsimulator.models.ResourceAssetInfo; +import org.onap.so.sdcsimulator.models.ServiceAssetInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.stereotype.Service; +import org.springframework.util.StreamUtils; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + */ +@Service +public class AssetProviderImpl implements AssetProvider { + + private static final Logger LOGGER = LoggerFactory.getLogger(AssetProvider.class); + + private final ObjectMapper mapper = + new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);; + + private final String resourceLocation; + + private final ResourcePatternResolver resourcePatternResolver; + + @Autowired + public AssetProviderImpl(@Value("${sdc.resource.location:/app/csars/}") final String resourceLocation, + final ResourcePatternResolver resourcePatternResolver) { + this.resourceLocation = resourceLocation; + this.resourcePatternResolver = resourcePatternResolver; + } + + @Override + public Optional getAsset(final String csarId, final AssetType assetType) { + try { + final Optional optionalInputStream = getInputStream(csarId, assetType); + if (optionalInputStream.isPresent()) { + return Optional.of(StreamUtils.copyToByteArray(optionalInputStream.get())); + } + } catch (final IOException ioException) { + LOGGER.warn("Unable to create file stream ...", ioException); + } + + return Optional.empty(); + } + + @Override + public Set getAssetInfo(final AssetType assetType) { + final Set result = new HashSet<>(); + + final Path dir = Paths.get(resourceLocation).resolve(assetType.toString()); + if (Files.exists(dir)) { + try (final DirectoryStream stream = Files.newDirectoryStream(dir, WILD_CARD_REGEX + DOT_CSAR)) { + for (final Path entry : stream) { + final String filename = getFilenameWithoutExtension(entry); + result.add(getAssetInfo(assetType, filename, entry)); + } + } catch (final IOException ioException) { + LOGGER.error("Unable to find assetInfo on filesystem", ioException); + } + } + + try { + final String classPathdir = MAIN_RESOURCE_FOLDER + assetType.toString() + FORWARD_SLASH; + final String csarFileLocationPattern = CLASSPATH_ALL_URL_PREFIX + classPathdir + WILD_CARD_REGEX + DOT_CSAR; + final Resource[] resources = resourcePatternResolver.getResources(csarFileLocationPattern); + if (resources != null) { + + for (final Resource resource : resources) { + final String filename = getFilenameWithoutExtension(resource.getFilename()); + result.add(getAssetInfo(assetType, filename, resource)); + } + } + + } catch (final IOException ioException) { + LOGGER.error("Unable to find assetInfo in classpath", ioException); + } + + return result; + } + + @Override + public Optional getMetadata(final String csarId, final AssetType assetType) { + final Path dir = Paths.get(resourceLocation).resolve(assetType.toString()); + final Path metadataFilePath = dir.resolve(csarId + DOT_JSON); + try { + if (Files.exists(metadataFilePath)) { + LOGGER.info("Found metadata file on file system using path: {}", metadataFilePath); + + return Optional.of(mapper.readValue(metadataFilePath.toFile(), Metadata.class)); + + } + } catch (final IOException ioException) { + LOGGER.error("Unable to find metadata file on filesystem", ioException); + } + + + try { + final String path = MAIN_RESOURCE_FOLDER + assetType.toString() + FORWARD_SLASH + csarId + DOT_JSON; + LOGGER.warn("Couldn't find metadata file on file system '{}', will search it in classpath", path); + final ClassPathResource classPathResource = getClassPathResource(path); + if (classPathResource.exists()) { + LOGGER.info("Found metadata file in classpath using path: {}", path); + return Optional.of(mapper.readValue(classPathResource.getInputStream(), Metadata.class)); + } + } catch (final IOException ioException) { + LOGGER.error("Unable to find metadata file in classpath", ioException); + } + LOGGER.error("Couldn't find metadata file in classpath ...."); + return Optional.empty(); + } + + private AssetInfo getAssetInfo(final AssetType assetType, final String filename, final Resource resource) + throws IOException { + final Resource jsonResource = resource.createRelative(filename + DOT_JSON); + + if (jsonResource != null && jsonResource.exists()) { + final AssetInfo assetInfo = getJsonAssetInfo(assetType, jsonResource); + assetInfo.setUuid(filename); + assetInfo.setToscaModelUrl(getToscaModelUrl(filename, assetType)); + LOGGER.info("Found AssetInfo file in classpath: {}", assetInfo); + return assetInfo; + + } + + final AssetInfo assetInfo = getAssetInfo(filename, assetType); + LOGGER.info("Returning AssetInfo: {}", assetInfo); + return assetInfo; + + } + + private AssetInfo getAssetInfo(final AssetType assetType, final String filename, final Path entry) + throws IOException { + final Path assetJsonFilePath = entry.getParent().resolve(filename + DOT_JSON); + if (Files.exists(assetJsonFilePath)) { + final AssetInfo assetInfo = getJsonAssetInfo(assetType, assetJsonFilePath.toFile()); + assetInfo.setUuid(filename); + assetInfo.setToscaModelUrl(getToscaModelUrl(filename, assetType)); + LOGGER.info("Found AssetInfo file on file system: {}", assetInfo); + return assetInfo; + + } + final AssetInfo assetInfo = getAssetInfo(filename, assetType); + LOGGER.info("Returning AssetInfo: {}", assetInfo); + return assetInfo; + } + + + private AssetInfo getJsonAssetInfo(final AssetType assetType, final Resource jsonResource) throws IOException { + if (AssetType.RESOURCES.equals(assetType)) { + return mapper.readValue(jsonResource.getInputStream(), ResourceAssetInfo.class); + } + + if (AssetType.SERVICES.equals(assetType)) { + return mapper.readValue(jsonResource.getInputStream(), ServiceAssetInfo.class); + } + + return mapper.readValue(jsonResource.getInputStream(), AssetInfo.class); + } + + + private AssetInfo getJsonAssetInfo(final AssetType assetType, final File file) throws IOException { + if (AssetType.RESOURCES.equals(assetType)) { + return mapper.readValue(file, ResourceAssetInfo.class); + } + + if (AssetType.SERVICES.equals(assetType)) { + return mapper.readValue(file, ServiceAssetInfo.class); + } + + return mapper.readValue(file, AssetInfo.class); + } + + private AssetInfo getAssetInfo(final String filename, final AssetType assetType) { + return getAssetInfoObject(assetType).uuid(filename).invariantUuid(filename).name(filename).version("1.0") + .toscaModelUrl(getToscaModelUrl(filename, assetType)).category("Generic").lifecycleState("CERTIFIED") + .lastUpdaterUserId("SDC_SIMULATOR"); + } + + private AssetInfo getAssetInfoObject(final AssetType assetType) { + if (AssetType.RESOURCES.equals(assetType)) { + return new ResourceAssetInfo().subCategory("Network Service"); + } + + if (AssetType.SERVICES.equals(assetType)) { + return new ServiceAssetInfo().distributionStatus("DISTRIBUTED"); + } + + return new AssetInfo(); + } + + private String getToscaModelUrl(final String filename, final AssetType assetType) { + return CATALOG_URL + FORWARD_SLASH + assetType.toString().toLowerCase() + FORWARD_SLASH + filename + + "/toscaModel"; + } + + private String getFilenameWithoutExtension(final String filename) { + return filename.substring(0, filename.lastIndexOf('.')); + } + + private String getFilenameWithoutExtension(final Path file) { + return getFilenameWithoutExtension(file.getFileName().toString()); + } + + private Optional getInputStream(final String csarId, final AssetType assetType) throws IOException { + final Path filePath = Paths.get(resourceLocation, csarId + DOT_CSAR); + if (Files.exists(filePath)) { + LOGGER.info("Found csar on file system using path: {}", filePath); + return Optional.of(Files.newInputStream(filePath)); + } + LOGGER.warn("Couldn't find file on file system '{}', will search it in classpath", filePath); + + final String path = MAIN_RESOURCE_FOLDER + assetType.toString() + FORWARD_SLASH + csarId + DOT_CSAR; + final ClassPathResource classPathResource = getClassPathResource(path); + if (classPathResource.exists()) { + LOGGER.info("Found csar in classpath using path: {}", path); + return Optional.of(classPathResource.getInputStream()); + } + + LOGGER.error("Couldn't find csar in classpath ...."); + return Optional.empty(); + } + + private ClassPathResource getClassPathResource(final String path) { + return new ClassPathResource(path, this.getClass()); + } + +} diff --git a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/providers/ResourceProviderImpl.java b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/providers/ResourceProviderImpl.java deleted file mode 100644 index eacc9d5c..00000000 --- a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/providers/ResourceProviderImpl.java +++ /dev/null @@ -1,174 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2019 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.so.sdcsimulator.providers; - -import static org.onap.so.sdcsimulator.utils.Constants.CATALOG_URL; -import static org.onap.so.sdcsimulator.utils.Constants.DOT_CSAR; -import static org.onap.so.sdcsimulator.utils.Constants.MAIN_RESOURCE_FOLDER; -import static org.onap.so.sdcsimulator.utils.Constants.WILD_CARD_REGEX; -import static org.springframework.core.io.support.ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; -import org.onap.so.sdcsimulator.models.ResourceArtifact; -import org.onap.so.sdcsimulator.utils.Constants; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.ResourcePatternResolver; -import org.springframework.stereotype.Service; -import org.springframework.util.StreamUtils; - -/** - * @author Eoin Hanan (eoin.hanan@est.tech) - */ -@Service -public class ResourceProviderImpl implements ResourceProvider { - - private static final Logger LOGGER = LoggerFactory.getLogger(ResourceProvider.class); - - private final String resourceLocation; - - private final ResourcePatternResolver resourcePatternResolver; - - @Autowired - public ResourceProviderImpl(@Value("${sdc.resource.location:/app/csars/}") final String resourceLocation, - final ResourcePatternResolver resourcePatternResolver) { - this.resourceLocation = resourceLocation; - this.resourcePatternResolver = resourcePatternResolver; - } - - @Override - public Optional getResource(final String csarId) { - try { - final Optional optionalInputStream = getInputStream(csarId); - if (optionalInputStream.isPresent()) { - return Optional.of(StreamUtils.copyToByteArray(optionalInputStream.get())); - } - } catch (final IOException ioException) { - LOGGER.warn("Unable to create file stream ...", ioException); - } - - return Optional.empty(); - } - - @Override - public Set getResource() { - final Set result = new HashSet<>(); - - final Path dir = Paths.get(resourceLocation); - if (Files.exists(dir)) { - try (final DirectoryStream stream = Files.newDirectoryStream(dir, WILD_CARD_REGEX + DOT_CSAR)) { - for (final Path entry : stream) { - final String filename = getFilenameWithoutExtension(entry); - final ResourceArtifact artifact = getResourceArtifact(filename); - result.add(artifact); - LOGGER.info("Found resource on file system: {}", artifact); - - - } - } catch (final IOException ioException) { - LOGGER.error("Unable to find resources on filesystem", ioException); - } - } - - try { - final String csarFileLocationPattern = - CLASSPATH_ALL_URL_PREFIX + MAIN_RESOURCE_FOLDER + WILD_CARD_REGEX + DOT_CSAR; - final Resource[] resources = resourcePatternResolver.getResources(csarFileLocationPattern); - if (resources != null) { - - for (final Resource resource : resources) { - final ResourceArtifact artifact = - getResourceArtifact(getFilenameWithoutExtension(resource.getFilename())); - result.add(artifact); - LOGGER.info("Found resource in classpath: {}", artifact); - } - } - - } catch (final IOException ioException) { - LOGGER.error("Unable to find resources in classpath", ioException); - } - - return result; - } - - private ResourceArtifact getResourceArtifact(final String filename) { - return new ResourceArtifact().uuid(filename).invariantUuid(filename).name(filename).version("1.0") - .toscaModelUrl(CATALOG_URL + "/resources/" + filename + "/toscaModel").category("Generic") - .subCategory("Network Service").resourceType("VF").lifecycleState("CERTIFIED") - .lastUpdaterUserId("SDC_SIMULATOR"); - } - - private String getFilenameWithoutExtension(final String filename) { - return filename.substring(0, filename.lastIndexOf('.')); - } - - private String getFilenameWithoutExtension(final Path file) { - return getFilenameWithoutExtension(file.getFileName().toString()); - } - - private Optional getInputStream(final String csarId) throws IOException { - final Path filePath = Paths.get(resourceLocation, csarId + DOT_CSAR); - if (Files.exists(filePath)) { - LOGGER.info("Found resource in on file system using path: {}", filePath); - return Optional.of(Files.newInputStream(filePath)); - } - LOGGER.warn("Couldn't find file on file system '{}', will search it in classpath", filePath); - - final String path = MAIN_RESOURCE_FOLDER + csarId + DOT_CSAR; - ClassPathResource classPathResource = getClassPathResource(path); - if (classPathResource.exists()) { - LOGGER.info("Found resource in classpath using path: {}", path); - return Optional.of(classPathResource.getInputStream()); - } - - LOGGER.warn("Couldn't find file on file system '{}', will return default csar", filePath); - classPathResource = getClassPathResource(getDefaultCsarPath()); - if (classPathResource.exists()) { - LOGGER.info("Found default csar in classpath"); - return Optional.of(classPathResource.getInputStream()); - } - - LOGGER.error("Couldn't find default csar in classpath ...."); - return Optional.empty(); - } - - private ClassPathResource getClassPathResource(final String path) { - return new ClassPathResource(path, this.getClass()); - } - - /* - * Used in test - */ - String getDefaultCsarPath() { - return Constants.DEFAULT_CSAR_PATH; - } -} diff --git a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/utils/Constants.java b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/utils/Constants.java index 3ddb5bee..4822b4fc 100644 --- a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/utils/Constants.java +++ b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/java/org/onap/so/sdcsimulator/utils/Constants.java @@ -33,17 +33,15 @@ public class Constants { public static final String HEALTHY = "healthy"; - public static final String DEFAULT_CSAR_NAME = "default_csar_file"; - public static final String DOT = "."; public static final String WILD_CARD_REGEX = "*"; public static final String DOT_CSAR = DOT + "csar"; - public static final String DEFAULT_CSAR_NAME_WITH_EXT = DEFAULT_CSAR_NAME + DOT_CSAR; + public static final String DOT_JSON = DOT + "json"; - public static final String DEFAULT_CSAR_PATH = MAIN_RESOURCE_FOLDER + DEFAULT_CSAR_NAME_WITH_EXT; + public static final String FORWARD_SLASH = "/"; private Constants() {} } diff --git a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/resources/csar/73522444-e8e9-49c1-be29-d355800aa349.csar b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/resources/csar/RESOURCES/73522444-e8e9-49c1-be29-d355800aa349.csar similarity index 100% rename from plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/resources/csar/73522444-e8e9-49c1-be29-d355800aa349.csar rename to plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/resources/csar/RESOURCES/73522444-e8e9-49c1-be29-d355800aa349.csar diff --git a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/resources/csar/RESOURCES/73522444-e8e9-49c1-be29-d355800aa349.json b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/resources/csar/RESOURCES/73522444-e8e9-49c1-be29-d355800aa349.json new file mode 100644 index 00000000..1ca1e7d4 --- /dev/null +++ b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/resources/csar/RESOURCES/73522444-e8e9-49c1-be29-d355800aa349.json @@ -0,0 +1,116 @@ +{ + "uuid": "73522444-e8e9-49c1-be29-d355800aa349", + "invariantUUID": "037f7b1b-5c62-44c1-b806-f92fe8970171", + "name": "EtsiVnfCSIT3", + "version": "1.0", + "toscaModelURL": "/sdc/v1/catalog/resources/73522444-e8e9-49c1-be29-d355800aa349/toscaModel", + "category": "Generic", + "subCategory": "Network Service", + "resourceType": "VF", + "lifecycleState": "CERTIFIED", + "lastUpdaterUserId": "cs0008", + "lastUpdaterFullName": "Carlos Santana", + "toscaResourceName": "org.openecomp.resource.vf.Etsivnfcsit3", + "resources": [ + { + "resourceInstanceName": "Cp_vgw_mux_gw_private_net", + "resourceName": "VDU Cp", + "resourceInvariantUUID": "3e4b8692-e6b1-44e9-90b1-6c5f1abf469c", + "resourceVersion": "1.0", + "resoucreType": "CP", + "resourceUUID": "72b9cd47-e8b7-4033-bb1a-fa30e45e3233" + }, + { + "resourceInstanceName": "Cp_vgw_onap_private", + "resourceName": "VDU Cp", + "resourceInvariantUUID": "3e4b8692-e6b1-44e9-90b1-6c5f1abf469c", + "resourceVersion": "1.0", + "resoucreType": "CP", + "resourceUUID": "72b9cd47-e8b7-4033-bb1a-fa30e45e3233" + }, + { + "resourceInstanceName": "LLU_VNF", + "resourceName": "VNF", + "resourceInvariantUUID": "a85aa428-cdb6-4e96-b873-0c20bfd22cac", + "resourceVersion": "1.0", + "resoucreType": "VFC", + "resourceUUID": "bbe67a58-6fd6-4849-abdf-f6a73dbdd594" + }, + { + "resourceInstanceName": "VDU_vgw_0", + "resourceName": "VDU Compute", + "resourceInvariantUUID": "d211a1fd-ae0d-4b33-9076-76defafa7adc", + "resourceVersion": "1.0", + "resoucreType": "VFC", + "resourceUUID": "5dcd4cc9-2db5-49aa-a51a-a0eb4124df4c" + }, + { + "resourceInstanceName": "VL_mux_gw_private_net", + "resourceName": "VnfVirtualLink", + "resourceInvariantUUID": "a9351632-8045-4422-bda6-fdbf4c472b2b", + "resourceVersion": "1.0", + "resoucreType": "VL", + "resourceUUID": "22ba6824-e467-4f6a-87df-ccc8bee01fe4" + }, + { + "resourceInstanceName": "Cp_vgw_cpe_public", + "resourceName": "VDU Cp", + "resourceInvariantUUID": "3e4b8692-e6b1-44e9-90b1-6c5f1abf469c", + "resourceVersion": "1.0", + "resoucreType": "CP", + "resourceUUID": "72b9cd47-e8b7-4033-bb1a-fa30e45e3233" + }, + { + "resourceInstanceName": "Cp_vgw_public", + "resourceName": "VDU Cp", + "resourceInvariantUUID": "3e4b8692-e6b1-44e9-90b1-6c5f1abf469c", + "resourceVersion": "1.0", + "resoucreType": "CP", + "resourceUUID": "72b9cd47-e8b7-4033-bb1a-fa30e45e3233" + }, + { + "resourceInstanceName": "VL_cpe_public", + "resourceName": "VnfVirtualLink", + "resourceInvariantUUID": "a9351632-8045-4422-bda6-fdbf4c472b2b", + "resourceVersion": "1.0", + "resoucreType": "VL", + "resourceUUID": "22ba6824-e467-4f6a-87df-ccc8bee01fe4" + } + ], + "artifacts": [ + { + "artifactName": "vf-license-model.xml", + "artifactType": "VF_LICENSE", + "artifactURL": "/sdc/v1/catalog/resources/73522444-e8e9-49c1-be29-d355800aa349/artifacts/3e964c48-c539-41b6-b504-52905fbe1f93", + "artifactDescription": "VF license file", + "artifactChecksum": "MDAwOTQ0NWYzNzMzYjJmYjBlODc2ODUyY2MzOTIyMjQ=", + "artifactUUID": "3e964c48-c539-41b6-b504-52905fbe1f93", + "artifactVersion": "1", + "artifactLabel": "vflicense", + "artifactGroupType": "DEPLOYMENT" + }, + { + "artifactName": "vgw6.csar", + "artifactType": "ETSI_PACKAGE", + "artifactURL": "/sdc/v1/catalog/resources/73522444-e8e9-49c1-be29-d355800aa349/artifacts/0737049a-204d-4009-932a-57a48119f5eb", + "artifactDescription": "Artifact created from csar", + "artifactChecksum": "ZjAyYjhmYzJkY2ExZjMyYzk1ZjlmNjk0YzkzNDNhY2Y=", + "artifactUUID": "0737049a-204d-4009-932a-57a48119f5eb", + "artifactVersion": "1", + "artifactLabel": "vgw6csar", + "artifactGroupType": "DEPLOYMENT" + }, + { + "artifactName": "vendor-license-model.xml", + "artifactType": "VENDOR_LICENSE", + "artifactURL": "/sdc/v1/catalog/resources/73522444-e8e9-49c1-be29-d355800aa349/artifacts/f17c8eed-cf1f-44cd-a2b3-2caee9c34b17", + "artifactDescription": " Vendor license file", + "artifactChecksum": "NzY2ZGUzODNkNWEwNjM1MjRiMjNiNDY1ZWNkNWQyOTg=", + "artifactUUID": "f17c8eed-cf1f-44cd-a2b3-2caee9c34b17", + "artifactVersion": "1", + "artifactLabel": "vendorlicense", + "artifactGroupType": "DEPLOYMENT" + } + ], + "description": "test" +} \ No newline at end of file diff --git a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/resources/csar/ba1c0c0e-9fb8-4b83-97bb-5e9af1e73393.csar b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/resources/csar/SERVICES/9bb8c882-44a1-4b67-a12c-5a998e18d6ba.csar similarity index 57% rename from plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/resources/csar/ba1c0c0e-9fb8-4b83-97bb-5e9af1e73393.csar rename to plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/main/resources/csar/SERVICES/9bb8c882-44a1-4b67-a12c-5a998e18d6ba.csar index 4e0400fa4cf7dc3c57df6f66f812863ea086bc6c..6504cb1a05d7b52c84a1f38aa0241a7fda8fa8c2 100644 GIT binary patch delta 61424 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 N&@&zr4|G=q{6DkXZsq_0 delta 30420 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

~9>Bn=Dylg^O;pmb6 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 diff --git a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/test/java/org/onap/so/sdcsimulator/controller/CatalogControllerTest.java b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/test/java/org/onap/so/sdcsimulator/controller/CatalogControllerTest.java index e63a7f90..d7ae74bb 100644 --- a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/test/java/org/onap/so/sdcsimulator/controller/CatalogControllerTest.java +++ b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/test/java/org/onap/so/sdcsimulator/controller/CatalogControllerTest.java @@ -23,13 +23,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.Base64; -import java.util.Optional; import java.util.Set; +import java.util.UUID; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mockito; -import org.onap.so.sdcsimulator.models.ResourceArtifact; -import org.onap.so.sdcsimulator.providers.ResourceProvider; +import org.onap.so.sdcsimulator.models.Metadata; +import org.onap.so.sdcsimulator.models.ResourceAssetInfo; +import org.onap.so.sdcsimulator.models.ServiceAssetInfo; import org.onap.so.sdcsimulator.utils.Constants; import org.onap.so.simulator.model.UserCredentials; import org.springframework.beans.factory.annotation.Autowired; @@ -58,6 +58,10 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @Configuration public class CatalogControllerTest { + private static final String SERVICE_ID = "9bb8c882-44a1-4b67-a12c-5a998e18d6ba"; + + private static final String RESOURCE_ID = "73522444-e8e9-49c1-be29-d355800aa349"; + private static final String PASSWORD = "Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U"; @LocalServerPort @@ -72,42 +76,90 @@ public class CatalogControllerTest { @Test public void test_getCsar_validCsarId_matchContent() { - final String url = getBaseUrl() + "/resources/" + Constants.DEFAULT_CSAR_NAME + "/toscaModel"; + final String url = getBaseUrl() + "/resources/" + RESOURCE_ID + "/toscaModel"; final ResponseEntity response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(getHttpHeaders()), byte[].class); assertEquals(HttpStatus.OK, response.getStatusCode()); assertTrue(response.hasBody()); - assertEquals(3982, response.getBody().length); + assertEquals(117247, response.getBody().length); } @Test public void test_getResources_validResourcesFromClassPath() { - final ResponseEntity> response = + final ResponseEntity> response = restTemplate.exchange(getBaseUrl() + "/resources", HttpMethod.GET, new HttpEntity<>(getHttpHeaders()), - new ParameterizedTypeReference>() {}); + new ParameterizedTypeReference>() {}); assertEquals(HttpStatus.OK, response.getStatusCode()); assertTrue(response.hasBody()); - assertEquals(3, response.getBody().size()); + assertEquals(1, response.getBody().size()); } @Test - public void test_getCsar_invalidCsar_internalServerError() { - final ResourceProvider mockedResourceProvider = Mockito.mock(ResourceProvider.class); - Mockito.when(mockedResourceProvider.getResource(Mockito.anyString())).thenReturn(Optional.empty()); - final CatalogController objUnderTest = new CatalogController(mockedResourceProvider); + public void test_getServices_validServicesFromClassPath() { + + final ResponseEntity> response = + restTemplate.exchange(getBaseUrl() + "/services", HttpMethod.GET, new HttpEntity<>(getHttpHeaders()), + new ParameterizedTypeReference>() {}); + + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertTrue(response.hasBody()); + assertEquals(1, response.getBody().size()); + + } + + @Test + public void test_getResourceCsar_invalidCsar_internalServerError() { + final String url = getBaseUrl() + "/resources/" + UUID.randomUUID().toString() + "/toscaModel"; + + final ResponseEntity response = + restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(getHttpHeaders()), byte[].class); - final ResponseEntity response = objUnderTest.getCsar(Constants.DEFAULT_CSAR_NAME); assertFalse(response.hasBody()); assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); } + @Test + public void test_getResourceMetadata_validMetadataFileInClasspath_matchContent() { + + final String url = getBaseUrl() + "/resources/" + RESOURCE_ID + "/metadata"; + + final ResponseEntity response = + restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(getHttpHeaders()), Metadata.class); + + + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertTrue(response.hasBody()); + final Metadata actual = response.getBody(); + assertEquals(8, actual.getResources().size()); + assertEquals(3, actual.getArtifacts().size()); + + } + + @Test + public void test_getServiceMetadata_validMetadataFileInClasspath_matchContent() { + + final String url = getBaseUrl() + "/services/" + SERVICE_ID + "/metadata"; + + final ResponseEntity response = + restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(getHttpHeaders()), Metadata.class); + + + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertTrue(response.hasBody()); + final Metadata actual = response.getBody(); + assertEquals(1, actual.getResources().size()); + assertEquals(1, actual.getArtifacts().size()); + + } + + private String getBaseUrl() { return "http://localhost:" + port + Constants.CATALOG_URL; } diff --git a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/test/java/org/onap/so/sdcsimulator/providers/ResourceProviderImplTest.java b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/test/java/org/onap/so/sdcsimulator/providers/AssetProviderImplTest.java similarity index 67% rename from plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/test/java/org/onap/so/sdcsimulator/providers/ResourceProviderImplTest.java rename to plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/test/java/org/onap/so/sdcsimulator/providers/AssetProviderImplTest.java index c132184c..293d70d2 100644 --- a/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/test/java/org/onap/so/sdcsimulator/providers/ResourceProviderImplTest.java +++ b/plans/so/integration-etsi-testing/so-simulators/sdc-simulator/src/test/java/org/onap/so/sdcsimulator/providers/AssetProviderImplTest.java @@ -22,6 +22,10 @@ package org.onap.so.sdcsimulator.providers; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertFalse; +import static org.onap.so.sdcsimulator.models.AssetType.RESOURCES; +import static org.onap.so.sdcsimulator.utils.Constants.DOT_CSAR; +import static org.onap.so.sdcsimulator.utils.Constants.FORWARD_SLASH; +import static org.onap.so.sdcsimulator.utils.Constants.MAIN_RESOURCE_FOLDER; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -30,7 +34,6 @@ import java.util.UUID; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; -import org.onap.so.sdcsimulator.utils.Constants; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.util.StreamUtils; @@ -39,7 +42,9 @@ import org.springframework.util.StreamUtils; * @author Waqas Ikram (waqas.ikram@est.tech) * @author Eoin Hanan (eoin.hanan@est.tech) */ -public class ResourceProviderImplTest { +public class AssetProviderImplTest { + + private static final String VNF_RESOURCE_ID = "73522444-e8e9-49c1-be29-d355800aa349"; @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); @@ -51,38 +56,34 @@ public class ResourceProviderImplTest { @Test public void test_getResource_withValidPath_matchContent() throws IOException { - final File folder = temporaryFolder.newFolder(); + final File folder = temporaryFolder.newFolder(RESOURCES.toString()); final String uuid = UUID.randomUUID().toString(); - final Path file = Files.createFile(folder.toPath().resolve(uuid + Constants.DOT_CSAR)); + final Path file = Files.createFile(folder.toPath().resolve(uuid + DOT_CSAR)); Files.write(file, DUMMY_CONTENT.getBytes()); - final ResourceProviderImpl objUnderTest = new ResourceProviderImpl(folder.getPath(), resourcePatternResolver); + final AssetProviderImpl objUnderTest = new AssetProviderImpl(folder.getPath(), resourcePatternResolver); - assertArrayEquals(DUMMY_CONTENT.getBytes(), objUnderTest.getResource(uuid).get()); + assertArrayEquals(DUMMY_CONTENT.getBytes(), objUnderTest.getAsset(uuid, RESOURCES).get()); } @Test public void test_getResource_withoutValidPath_matchContent() throws IOException { - final ClassPathResource classPathResource = new ClassPathResource(Constants.DEFAULT_CSAR_PATH, this.getClass()); + final String validCsarPath = MAIN_RESOURCE_FOLDER + RESOURCES + FORWARD_SLASH + VNF_RESOURCE_ID + DOT_CSAR; + final ClassPathResource classPathResource = new ClassPathResource(validCsarPath, this.getClass()); final byte[] expectedResult = StreamUtils.copyToByteArray(classPathResource.getInputStream()); - final ResourceProviderImpl objUnderTest = new ResourceProviderImpl("", resourcePatternResolver); + final AssetProviderImpl objUnderTest = new AssetProviderImpl("", resourcePatternResolver); - assertArrayEquals(expectedResult, objUnderTest.getResource(Constants.DEFAULT_CSAR_NAME).get()); + assertArrayEquals(expectedResult, objUnderTest.getAsset(VNF_RESOURCE_ID, RESOURCES).get()); } @Test public void test_getResource_unbleToReadFileFromClasspath_emptyOptional() throws IOException { - final ResourceProviderImpl objUnderTest = new ResourceProviderImpl("", resourcePatternResolver) { - @Override - String getDefaultCsarPath() { - return "/some/dummy/path"; - } - }; - assertFalse(objUnderTest.getResource(UUID.randomUUID().toString()).isPresent()); + final AssetProviderImpl objUnderTest = new AssetProviderImpl("", resourcePatternResolver); + assertFalse(objUnderTest.getAsset(UUID.randomUUID().toString(), RESOURCES).isPresent()); } } -- 2.16.6