diff options
author | BT2983 <BT2983@att.com> | 2018-09-16 21:30:20 -0600 |
---|---|---|
committer | Timoney, Dan (dt5972) <dt5972@att.com> | 2018-09-17 12:35:14 -0400 |
commit | 9783a8b7515eaaec310e404650d0dd9092eb90a8 (patch) | |
tree | 90101018aa23a5e91c0d9f85aec0fa5ff407e184 /ms | |
parent | 4f44000fef9608150811e0b9f9b140c580f5822b (diff) |
naming micro-service updates.
More tests, changes for maria DB, support for UUID and timestamp etc.
Change-Id: I17bdf3acbe970ef4104f2ec0d59d5777c0a9928e
Issue-ID: CCSDK-342
Signed-off-by: BT2983 <BT2983@att.com>
Diffstat (limited to 'ms')
26 files changed, 663 insertions, 50 deletions
diff --git a/ms/controllerblueprints/application/src/test/java/org/onap/ccsdk/apps/controllerblueprints/ControllerBluprintsApplicationTest.java b/ms/controllerblueprints/application/src/test/java/org/onap/ccsdk/apps/controllerblueprints/ControllerBluprintsApplicationTest.java index 58f3ccc3..61b5c50f 100644 --- a/ms/controllerblueprints/application/src/test/java/org/onap/ccsdk/apps/controllerblueprints/ControllerBluprintsApplicationTest.java +++ b/ms/controllerblueprints/application/src/test/java/org/onap/ccsdk/apps/controllerblueprints/ControllerBluprintsApplicationTest.java @@ -48,20 +48,36 @@ public class ControllerBluprintsApplicationTest { private HttpHeaders headers;
private ResponseEntity<ConfigModel> entity;
-
@Before
public void setUp(){
headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
entity = this.restTemplate
.exchange("/api/v1/config-model/1", HttpMethod.GET, new HttpEntity<>(headers),ConfigModel.class);
-
+
}
@Test
public void testConfigModel() {
+
+ HttpHeaders headers = new HttpHeaders();
+ headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
+ ResponseEntity<ConfigModel> entity = this.restTemplate
+ .exchange("/api/v1/config-model/1", HttpMethod.GET, new HttpEntity<>(headers),ConfigModel.class);
+
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
Assert.assertNotNull("failed to get response Config model",entity.getBody());
}
+ @Test
+ public void testConfigModelFailure() {
+
+ HttpHeaders headers = new HttpHeaders();
+ headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
+ ResponseEntity<ConfigModel> entity = this.restTemplate
+ .exchange("/api/v1/config-model-not-found/1", HttpMethod.GET, new HttpEntity<>(headers),ConfigModel.class);
+
+ assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
+ Assert.assertNotNull("failed to get response Config model",entity.getBody());
+ }
}
diff --git a/ms/neng/opt/etc/config/application.properties b/ms/neng/opt/etc/config/application.properties index 71d7a5f5..e2cd963d 100644 --- a/ms/neng/opt/etc/config/application.properties +++ b/ms/neng/opt/etc/config/application.properties @@ -25,7 +25,7 @@ # #========================================================================= -datasource.db.driver-class-name=com.mysql.jdbc.Driver +datasource.db.driver-class-name=org.mariadb.jdbc.Driver endpoints.beans.id=springbeans endpoints.beans.sensitive=false diff --git a/ms/neng/pom.xml b/ms/neng/pom.xml index 87ac192e..bcc5d0cd 100644 --- a/ms/neng/pom.xml +++ b/ms/neng/pom.xml @@ -33,7 +33,7 @@ <java.version>1.8</java.version> <spring.version>4.3.8.RELEASE</spring.version> <springboot.version>1.5.6.RELEASE</springboot.version> - <docker.registry>nexus3.onap.org:10003</docker.registry> + <docker.registry>nexus3.onap.org:10001</docker.registry> <build.number>local</build.number> <kube.namespace>TBD</kube.namespace> <service.account>TBD</service.account> @@ -122,7 +122,7 @@ <artifactId>docker-maven-plugin</artifactId> <version>0.4.11</version> <configuration> - <imageName>onap/ccsdk-apps-ms-neng:${project.version}</imageName> + <imageName>${docker.registry}/onap/ccsdk-apps-ms-neng:${project.version}</imageName> <dockerDirectory>src/main/docker</dockerDirectory> <serverId>docker-hub</serverId> <registryUrl>https://${docker.registry}</registryUrl> diff --git a/ms/neng/src/main/docker/Dockerfile b/ms/neng/src/main/docker/Dockerfile index dd239ebc..e8594e5f 100644 --- a/ms/neng/src/main/docker/Dockerfile +++ b/ms/neng/src/main/docker/Dockerfile @@ -19,7 +19,7 @@ #================================================================================ # Docker setup for the micro-service #================================================================================ -FROM onap/ccsdk-ubuntu-image:latest +FROM onap/ccsdk-ubuntu-image:0.3.0-SNAPSHOT VOLUME /tmp ADD NetworkElementNameGen.jar app.jar VOLUME /opt/etc diff --git a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/gen/NameGenerator.java b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/gen/NameGenerator.java index 8cfe7c88..ec04960f 100644 --- a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/gen/NameGenerator.java +++ b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/gen/NameGenerator.java @@ -42,6 +42,7 @@ import org.onap.ccsdk.apps.ms.neng.core.exceptions.NengException; import org.onap.ccsdk.apps.ms.neng.core.persistence.NamePersister; import org.onap.ccsdk.apps.ms.neng.core.policy.PolicyFinder; import org.onap.ccsdk.apps.ms.neng.core.policy.PolicyParameters; +import org.onap.ccsdk.apps.ms.neng.core.policy.PolicyPropertyMethodUtils; import org.onap.ccsdk.apps.ms.neng.core.policy.PolicySequence; import org.onap.ccsdk.apps.ms.neng.core.policy.PropertyOperator; import org.onap.ccsdk.apps.ms.neng.core.policy.RecipeParser; @@ -73,21 +74,21 @@ public class NameGenerator { /** * Constructor. * - * @param policyFinder a way to find policies - * @param policyParams parameters related to policy - * @param seqGenerator a way to generate sequences - * @param dbValidator a way to validate generated names against DB - * @param aaiValidator a way to validate generated names against A&AI - * @param namePersister a way to persist names - * @param requestElement the request element for which the name is generated, containing data such - * as policy name, naming-type, external-key and resource-name - * @param allElements all the elements in the request (including the current request element for - * which name is generated), as this is needed to re-use names generated from other request elements - * within the same transaction - * @param earlierNames names generated earlier in the same transaction, as a map from naming-type - * to names (which is a map with keys "resource-name", "resource-value" and "external-key") - * @param policyCache cache containing policies retrieved in this transaction, to avoid repeated - * calls to policy manager within the same transaction + * @param policyFinder a way to find policies + * @param policyParams parameters related to policy + * @param seqGenerator a way to generate sequences + * @param dbValidator a way to validate generated names against DB + * @param aaiValidator a way to validate generated names against A&AI + * @param namePersister a way to persist names + * @param requestElement the request element for which the name is generated, containing data such + * as policy name, naming-type, external-key and resource-name + * @param allElements all the elements in the request (including the current request element for + * which name is generated), as this is needed to re-use names generated from other request elements + * within the same transaction + * @param earlierNames names generated earlier in the same transaction, as a map from naming-type + * to names (which is a map with keys "resource-name", "resource-value" and "external-key") + * @param policyCache cache containing policies retrieved in this transaction, to avoid repeated + * calls to policy manager within the same transaction */ public NameGenerator(PolicyFinder policyFinder, PolicyParameters policyParams, SequenceGenerator seqGenerator, DbNameValidator dbValidator, AaiNameValidator aaiValidator, NamePersister namePersister, @@ -146,7 +147,7 @@ public class NameGenerator { response.put(RESOURCE_VALUE_ELEMENT_ITEM, value); return response; } - + String buildSequenceSuffix(Map<String, Object> recipeValues, String recipeName, List<String> recipe) throws Exception { StringBuffer buf = new StringBuffer(); @@ -184,7 +185,7 @@ public class NameGenerator { Map<String, ?> namingModel = namingModel(namingModels, namingType); if (namingModel == null) { throw new NengException( - "Could not find the policy data for " + policyName + " and naming-type " + namingType); + "Could not find the policy data for " + policyName + " and naming-type " + namingType); } return generateNew(policyName, namingType, namingModels, namingModel); } else { @@ -211,6 +212,12 @@ public class NameGenerator { if ("SEQUENCE".equals(recipeItem)) { PolicySequence seq = seq(propMap); recipeValues.put(recipeItem, seq); + } else if ("UUID".equals(recipeItem)) { + String uuid = PolicyPropertyMethodUtils.genUuid(); + recipeValues.put(recipeItem, uuid); + } else if ("TIMESTAMP".equals(recipeItem)) { + String ts = PolicyPropertyMethodUtils.getIsoDateString(); + recipeValues.put(recipeItem, ts); } else { String val = generateNonSequenceValue(namingModels, policyName, namingType, namingModel, propMap, recipeItem); @@ -311,8 +318,8 @@ public class NameGenerator { if (val instanceof PolicySequence) { PolicySequence seq = (PolicySequence) val; if (scope.equals(seq.getScope())) { - SeqGenData seqVal = generateSequenceValue( - seq, policyName, namingType, recipeValues, item, lastSeq, attemptCount, recipe); + SeqGenData seqVal = generateSequenceValue(seq, policyName, namingType, recipeValues, item, + lastSeq, attemptCount, recipe); String seqStr = SequenceFormatter.formatSequence(seqVal.getSeq(), seq); seqVal.setSeqEncoded(seqStr); seq.setKey(item); @@ -434,7 +441,7 @@ public class NameGenerator { } return policy; } - + void storeGeneratedName(String key, String name, String namingType, SeqGenData seqData) throws Exception { String prefix = null; @@ -465,7 +472,7 @@ public class NameGenerator { record.setSequenceNumberEnc(seqEncoded); this.namePersister.persist(record); } - + void validateAllItemsPresent(String policyName, String namingType, List<String> recipe, Map<String, Object> recipeValues) throws Exception { List<String> missing = new ArrayList<>(); diff --git a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/policy/PolicyPropertyMethodUtils.java b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/policy/PolicyPropertyMethodUtils.java index 9f4725fb..67805246 100644 --- a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/policy/PolicyPropertyMethodUtils.java +++ b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/policy/PolicyPropertyMethodUtils.java @@ -20,13 +20,18 @@ package org.onap.ccsdk.apps.ms.neng.core.policy; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.UUID; + /** * Utility methods equivalent to the JavaScript like functions used in policies by the policy-manager. */ public class PolicyPropertyMethodUtils { /** - * Equivalent to the substring function used by policy-manager (which works similar to JavaScript + * Equivalent to the substring function used by policy-manager (which works similar to JavaScript * substring function). */ public static String substring(String sourceStr, String startIndex, String endIndex) { @@ -34,7 +39,7 @@ public class PolicyPropertyMethodUtils { } /** - * Equivalent to the substring function used by policy-manager (which works similar to JavaScript + * Equivalent to the substring function used by policy-manager (which works similar to JavaScript * substring function). */ public static String substring(String sourceStr, String length) { @@ -66,4 +71,20 @@ public class PolicyPropertyMethodUtils { public static String toLowerCase(String sourceStr) { return sourceStr.toLowerCase(); } + + /** + * Generates a random UUID and returns it. + */ + public static String genUuid() { + UUID uuid = UUID.randomUUID(); + return uuid.toString(); + } + + /** + * Generates a date timestamp. + */ + public static String getIsoDateString() { + String utcDate = ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT); + return utcDate.replaceAll("-", "").replaceAll(":", "").replaceAll("\\.", ""); + } } diff --git a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/service/SpringServiceImpl.java b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/service/SpringServiceImpl.java index daf8f574..a8ca4bb6 100644 --- a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/service/SpringServiceImpl.java +++ b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/core/service/SpringServiceImpl.java @@ -196,7 +196,7 @@ public class SpringServiceImpl implements SpringService { void validateRequest(NameGenRequest request) throws Exception { List<Map<String, String>> elems = request.getElements(); - if (!elems.isEmpty()) { + if (elems != null && !elems.isEmpty()) { boolean error = false; Set<String> externalKeySet = elems.stream().map(s -> s.get("external-key")).collect(Collectors.toSet()); if (externalKeySet.size() != request.getElements().size()) { diff --git a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/service/extinf/impl/AaiServiceImpl.java b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/service/extinf/impl/AaiServiceImpl.java index a401d214..db8d4429 100644 --- a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/service/extinf/impl/AaiServiceImpl.java +++ b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/service/extinf/impl/AaiServiceImpl.java @@ -74,6 +74,15 @@ public class AaiServiceImpl { return !resp.isRecFound(); } + + public void setAaiRestTempBuilder(RestTemplateBuilder aaiRestTempBuilder) { + this.aaiRestTempBuilder = aaiRestTempBuilder; + } + + public void setRestTemplate(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + AaiResponse makeOutboundCall(String url, String name) throws Exception { String uri = aaiProps.getUriBase() + url + name; log.info("AAI URI - " + uri); @@ -128,4 +137,5 @@ public class AaiServiceImpl { } return keyStore; } + } diff --git a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/service/extinf/impl/PolicyFinderServiceImpl.java b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/service/extinf/impl/PolicyFinderServiceImpl.java index a19c9153..392567b7 100644 --- a/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/service/extinf/impl/PolicyFinderServiceImpl.java +++ b/ms/neng/src/main/java/org/onap/ccsdk/apps/ms/neng/service/extinf/impl/PolicyFinderServiceImpl.java @@ -59,9 +59,7 @@ public class PolicyFinderServiceImpl implements PolicyFinder { private static Logger log = Logger.getLogger(PolicyFinderServiceImpl.class.getName()); @Autowired PolicyManagerProps policManProps; - @Autowired - @Qualifier("policyMgrRestTempBuilder") - RestTemplateBuilder policyMgrRestTempBuilder; + @Autowired @Qualifier("policyMgrRestTempBuilder") RestTemplateBuilder policyMgrRestTempBuilder; @Autowired PolicyManagerAuthorizationInterceptor authInt; RestTemplate restTemplate; @@ -73,7 +71,7 @@ public class PolicyFinderServiceImpl implements PolicyFinder { Object response = getConfig(policyName).getResponse(); if (response instanceof List) { @SuppressWarnings("unchecked") - List<Map<String, Object>> policyList = (List<Map<String, Object>>)response; + List<Map<String, Object>> policyList = (List<Map<String, Object>>) response; return ((policyList != null && policyList.size() > 0) ? policyList.get(0) : null); } else { return null; @@ -98,7 +96,7 @@ public class PolicyFinderServiceImpl implements PolicyFinder { System.out.println(objectmapper.writeValueAsString(resp.getBody())); List<Map<Object, Object>> respObj = objectmapper.readValue( objectmapper.writeValueAsString(resp.getBody()), - new TypeReference<List<Map<Object, Object>>>() {}); + new TypeReference<List<Map<Object, Object>>>() {}); transformConfigObject(objectmapper, respObj); GetConfigResponse getConfigResp = new GetConfigResponse(); getConfigResp.setResponse(respObj); @@ -113,6 +111,12 @@ public class PolicyFinderServiceImpl implements PolicyFinder { void handleError(HttpStatusCodeException e) throws Exception { String respString = e.getResponseBodyAsString(); log.info(respString); + if (e.getStatusText() != null) { + log.info(e.getStatusText()); + } + if (e.getResponseHeaders() != null && e.getResponseHeaders().toSingleValueMap() != null) { + log.info(e.getResponseHeaders().toSingleValueMap().toString()); + } if (HttpStatus.NOT_FOUND.equals(e.getStatusCode()) && (respString != null && respString.contains(""))) { throw new NengException("Policy not found in policy manager."); } diff --git a/ms/neng/src/main/resources/db/changelog/db.changelog-master.xml b/ms/neng/src/main/resources/db/changelog/db.changelog-master.xml index dbbd71b6..e481be8c 100644 --- a/ms/neng/src/main/resources/db/changelog/db.changelog-master.xml +++ b/ms/neng/src/main/resources/db/changelog/db.changelog-master.xml @@ -29,5 +29,9 @@ <include file="db/changelog/scripts/rel_18_10/01_initial_ref_data_v1.sql" /> <include file="db/changelog/scripts/rel_18_10/02_create_indexes_ddl.sql" /> <include file="db/changelog/scripts/rel_18_10/04_ref_data_extrn_int.sql" /> + + <include file="db/changelog/scripts/rel_18_10/create_message_table.sql" /> + <include file="db/changelog/scripts/rel_18_10/10_identifier_map_upd_dml.sql" /> + </databaseChangeLog> diff --git a/ms/neng/src/main/resources/db/changelog/scripts/rel_18_10/10_identifier_map_upd_dml.sql b/ms/neng/src/main/resources/db/changelog/scripts/rel_18_10/10_identifier_map_upd_dml.sql new file mode 100644 index 00000000..bf16b621 --- /dev/null +++ b/ms/neng/src/main/resources/db/changelog/scripts/rel_18_10/10_identifier_map_upd_dml.sql @@ -0,0 +1,10 @@ +--liquibase formatted sql +--changeset identifier_map_update_sql_recipefunction:18_10.identifier_map_upd_dml.sql + +delete from IDENTIFIER_MAP where POLICY_FN_NAME='UUID'; + +INSERT INTO IDENTIFIER_MAP(POLICY_FN_NAME, JS_FN_NAME, CREATED_BY) VALUES ('UUID','genUUID', 'Initial'); + +delete from IDENTIFIER_MAP where POLICY_FN_NAME='TIMESTAMP'; + +INSERT INTO IDENTIFIER_MAP(POLICY_FN_NAME, JS_FN_NAME, CREATED_BY) VALUES ('TIMESTAMP','getISODateString', 'Initial'); diff --git a/ms/neng/src/main/resources/db/changelog/scripts/rel_18_10/create_message_table.sql b/ms/neng/src/main/resources/db/changelog/scripts/rel_18_10/create_message_table.sql new file mode 100644 index 00000000..33b42434 --- /dev/null +++ b/ms/neng/src/main/resources/db/changelog/scripts/rel_18_10/create_message_table.sql @@ -0,0 +1,14 @@ +--liquibase formatted sql +--changeset message_table:18_10.create_message_table.sql + +CREATE TABLE NELGEN_MESSAGE (NELGEN_MESSAGE_ID VARCHAR(500) PRIMARY KEY, +MESSAGE_ID VARCHAR(500) COMMENT 'Message id', +CONVERSATION_ID VARCHAR(500) COMMENT 'Conversation id for the transaction', +SERVICE_NAME VARCHAR(100) COMMENT 'Service name', +START_TIME DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 'Transaction start time', +ELAPSED_MILLIS INTEGER , +STATUS VARCHAR(20) COMMENT 'Transaction status', +REQUEST VARCHAR(10000) NOT NULL COMMENT 'Request JSON', +RESPONSE VARCHAR(20000) COMMENT 'Request JSON', +REQUESTER VARCHAR(50) COMMENT 'Requester' +); diff --git a/ms/neng/src/test/java/org/onap/ccsdk/apps/ms/neng/core/gen/SequenceFormatterTest.java b/ms/neng/src/test/java/org/onap/ccsdk/apps/ms/neng/core/gen/SequenceFormatterTest.java index 5a161319..86f418ac 100644 --- a/ms/neng/src/test/java/org/onap/ccsdk/apps/ms/neng/core/gen/SequenceFormatterTest.java +++ b/ms/neng/src/test/java/org/onap/ccsdk/apps/ms/neng/core/gen/SequenceFormatterTest.java @@ -33,8 +33,7 @@ public class SequenceFormatterTest { private PolicySequence poly; @Before - public void setUp() - { + public void setUp() { poly = new PolicySequence(); } @@ -60,31 +59,27 @@ public class SequenceFormatterTest { } @Test - public void testGetSetIncrement() - { + public void testGetSetIncrement() { poly.setIncrement(1L); assertEquals(1L, poly.getIncrement()); } @Test - public void testGetSetMaxValue() - { + public void testGetSetMaxValue() { poly.setMaxValue(1L); assertEquals(1L, poly.getMaxValue()); } @Test - public void testGetSetKey() - { + public void testGetSetKey() { poly.setKey("testKey"); assertEquals("testKey", poly.getKey()); } @Test - public void testGetSetLastReleaseSeqNumTried() - { + public void testGetSetLastReleaseSeqNumTried() { poly.setLastReleaseSeqNumTried(1L); - Long expected=1L; + Long expected = 1L; assertEquals(expected, poly.getLastReleaseSeqNumTried()); } } diff --git a/ms/neng/src/test/java/org/onap/ccsdk/apps/ms/neng/core/policy/PolicyReaderTest.java b/ms/neng/src/test/java/org/onap/ccsdk/apps/ms/neng/core/policy/PolicyReaderTest.java index 30fc6e45..b439c610 100644 --- a/ms/neng/src/test/java/org/onap/ccsdk/apps/ms/neng/core/policy/PolicyReaderTest.java +++ b/ms/neng/src/test/java/org/onap/ccsdk/apps/ms/neng/core/policy/PolicyReaderTest.java @@ -21,9 +21,15 @@ package org.onap.ccsdk.apps.ms.neng.core.policy; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.onap.ccsdk.apps.ms.neng.core.policy.PolicyReader.namingModels; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; import java.util.Map; + import org.junit.Test; public class PolicyReaderTest { @@ -41,4 +47,57 @@ public class PolicyReaderTest { assertEquals("VNF", PolicyReader.relaxedNamingType("vnf-name")); assertEquals("VNF", PolicyReader.relaxedNamingType("vnf_name")); } + + @Test + public void testNamingProperty() throws Exception { + List<Map<String, ?>> namingModels = PolicyReader.namingModels(buildPolicyResponse_withoutContent()); + assertNotNull(namingModels); + assertNull(PolicyReader.namingProperty(namingModels.get(0), "TEST")); + namingModels = PolicyReader.namingModels(buildPolicyResponse_withoutContent()); + assertNull(PolicyReader.namingProperty(namingModels.get(0), "TEST")); + } + + @Test + public void testNamingModelRelaxed() throws Exception { + List<Map<String, ?>> namingModels = PolicyReader.namingModels(buildPolicyResponse_withoutContent()); + assertNotNull(PolicyReader.namingModelRelaxed(namingModels, "VNF")); + } + + @Test + public void testDependentNamingModel() throws Exception { + List<Map<String, ?>> namingModels = PolicyReader.namingModels(buildPolicyResponse_withoutContent()); + assertNotNull(PolicyReader.dependentNamingModel(namingModels, "VNF")); + assertNotNull(PolicyReader.dependentNamingModel(namingModels, "VNF_NAME")); + assertNull(PolicyReader.dependentNamingModel(namingModels, "VNFC_NAME")); + } + + @Test + public void testNumber() throws Exception { + assertEquals(100, PolicyReader.number("10G", 100L)); + } + + private Map<String, ?> buildPolicyResponse_withoutContent() { + Map<String, Object> policyDataMap = new HashMap<>(); + policyDataMap.put("policy-instance-name", "SDNC_Policy.Config_MS_VNFCNamingPolicy"); + + Map<String, Object> namingModelMap = new HashMap<>(); + namingModelMap.put("nf-role", "vPE"); + namingModelMap.put("naming-type", "VNF"); + namingModelMap.put("naming-recipe", "COMPLEX|NF-NAMING-CODE|Field2|Field3|Field4"); + + Map<String, Object> namingPropertyMap = new HashMap<>(); + Map<String, Object> propertyMap1 = new HashMap<>(); + propertyMap1.put("property-name", "COMPLEX"); + Map<String, Object> propertyMap2 = new HashMap<>(); + propertyMap2.put("property-name", "NF-NAMING-CODE"); + namingPropertyMap.put("", Arrays.asList(new Object[] {propertyMap1, propertyMap2})); + + namingModelMap.put("naming-properties", Arrays.asList(new Object[] {propertyMap1, propertyMap2})); + + policyDataMap.put("naming-models", Arrays.asList(new Object[] {namingModelMap})); + + Map<String, Object> configMap = new HashMap<>(); + configMap.put("config", policyDataMap); + return configMap; + } } diff --git a/ms/neng/src/test/java/org/onap/ccsdk/apps/ms/neng/core/policy/PolicySequenceTest.java b/ms/neng/src/test/java/org/onap/ccsdk/apps/ms/neng/core/policy/PolicySequenceTest.java new file mode 100644 index 00000000..9a0bbbd3 --- /dev/null +++ b/ms/neng/src/test/java/org/onap/ccsdk/apps/ms/neng/core/policy/PolicySequenceTest.java @@ -0,0 +1,43 @@ +package org.onap.ccsdk.apps.ms.neng.core.policy; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class PolicySequenceTest { + + @Test + public void testGetMaxValue() throws Exception { + PolicySequence seq = new PolicySequence(); + seq.setMaxValueString("0AB"); + seq.setType(PolicySequence.Type.ALPHA); + assertEquals(371L, seq.getMaxValue()); + } + + @Test + public void testGetMaxValue_Exp() throws Exception { + PolicySequence seq = new PolicySequence(); + seq.setMaxValueString("0AB"); + seq.setType(PolicySequence.Type.NUMERIC); + assertEquals(999, seq.getMaxValue()); + } + + @Test + public void testGetMaxValue_Numeric() throws Exception { + PolicySequence seq = new PolicySequence(); + seq.setMaxValueString("011"); + seq.setType(PolicySequence.Type.NUMERIC); + assertEquals(11, seq.getMaxValue()); + } + + @Test + public void testGetMaxValue_null_maxvalue() throws Exception { + PolicySequence seq = new PolicySequence(); + seq.setLength(3); + seq.setType(PolicySequence.Type.NUMERIC); + assertEquals(999, seq.getMaxValue()); + } +} diff --git a/ms/neng/src/test/java/org/onap/ccsdk/apps/ms/neng/core/service/SpringServiceIntTest.java b/ms/neng/src/test/java/org/onap/ccsdk/apps/ms/neng/core/service/SpringServiceIntTest.java index c3815f43..aca0a533 100644 --- a/ms/neng/src/test/java/org/onap/ccsdk/apps/ms/neng/core/service/SpringServiceIntTest.java +++ b/ms/neng/src/test/java/org/onap/ccsdk/apps/ms/neng/core/service/SpringServiceIntTest.java @@ -20,6 +20,7 @@ package org.onap.ccsdk.apps.ms.neng.core.service; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.doReturn; @@ -44,8 +45,10 @@ import org.onap.ccsdk.apps.ms.neng.core.persistence.NamePersister; import org.onap.ccsdk.apps.ms.neng.core.resource.model.NameGenRequest; import org.onap.ccsdk.apps.ms.neng.core.resource.model.NameGenResponse; import org.onap.ccsdk.apps.ms.neng.core.service.rs.RestServiceImpl; +import org.onap.ccsdk.apps.ms.neng.persistence.entity.ExternalInterface; import org.onap.ccsdk.apps.ms.neng.persistence.entity.GeneratedName; import org.onap.ccsdk.apps.ms.neng.persistence.entity.PolicyDetails; +import org.onap.ccsdk.apps.ms.neng.persistence.repository.ExternalInterfaceRespository; import org.onap.ccsdk.apps.ms.neng.persistence.repository.PolicyDetailsRepository; import org.onap.ccsdk.apps.ms.neng.persistence.repository.ServiceParameterRepository; import org.onap.ccsdk.apps.ms.neng.service.extinf.impl.AaiServiceImpl; @@ -85,6 +88,8 @@ public class SpringServiceIntTest { AaiServiceImpl aaiServiceImpl; @Autowired RestServiceImpl restServiceImpl; + @Autowired + ExternalInterfaceRespository extIntRepo; @Before public void setup() { @@ -215,4 +220,23 @@ public class SpringServiceIntTest { doThrow(new NengException("")).when(springService).addPolicy(policy); restServiceImpl.addPolicyToDb(policy); } + + @Test + public void testExternalInterfaceRepo() throws Exception { + ExternalInterface extInt = new ExternalInterface(); + extInt.setCreatedBy("user"); + extInt.setCreatedTime(null); + extInt.setExternalInteraceId(100); + extInt.setLastUpdatedBy("user"); + extInt.setParam("VNF"); + extInt.setSystem("AAI"); + extInt.setUrlSuffix("nodes/generic-vnfs?vnf-name="); + + extIntRepo.save(extInt); + ExternalInterface extIntDb = extIntRepo.findOne(100); + + assertNotNull(extIntDb); + assertEquals("nodes/generic-vnfs?vnf-name=",extIntDb.getUrlSuffix()); + } + } diff --git a/ms/neng/src/test/java/org/onap/ccsdk/apps/ms/neng/core/service/SpringServiceTest.java b/ms/neng/src/test/java/org/onap/ccsdk/apps/ms/neng/core/service/SpringServiceTest.java index b4821a21..7ea63e61 100644 --- a/ms/neng/src/test/java/org/onap/ccsdk/apps/ms/neng/core/service/SpringServiceTest.java +++ b/ms/neng/src/test/java/org/onap/ccsdk/apps/ms/neng/core/service/SpringServiceTest.java @@ -110,14 +110,12 @@ public class SpringServiceTest { } @Test - public void testGetQuickHello() - { + public void testGetQuickHello() { Assert.assertTrue(springserviceImpl.getQuickHello("testMessage") instanceof HelloWorld); } @Test - public void testGetQuickHelloForNullMessage() - { + public void testGetQuickHelloForNullMessage() { Assert.assertTrue(springserviceImpl.getQuickHello("") instanceof HelloWorld); } } diff --git a/ms/neng/src/test/sanity/add-policy-vnf-ts.sh b/ms/neng/src/test/sanity/add-policy-vnf-ts.sh new file mode 100644 index 00000000..4119d88a --- /dev/null +++ b/ms/neng/src/test/sanity/add-policy-vnf-ts.sh @@ -0,0 +1,46 @@ +#!/bin/bash +#============LICENSE_START======================================================= +# ONAP : CCSDK.apps +# ================================================================================ +# Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============LICENSE_END========================================================= + +#================================================================================== +# This script does a sanity test on the add-policy API of the micro-service. +#================================================================================== + +. ./env.sh +URL=web/service/v1/addPolicy +TEMP_FILE=/tmp/add-policy.$$.$RANDOM +EXTERNAL_KEY=${1:-123456789} + +printf '{ ' > $TEMP_FILE +printf '"policyName": "vnf-policy-ts-1' >> $TEMP_FILE +printf '", "policyValue" : "' >> $TEMP_FILE +cat ./policy-vnf-ts.json | sed 's/\"/\\\"/g' | tr '\n' ' ' | tr '\r' ' ' >> $TEMP_FILE +echo '"}' >> $TEMP_FILE + +echo "===================================================" +echo "====== Adding Policy: ===========================" +cat $TEMP_FILE +echo "" +echo "===================================================" + +echo "===================================================" +curl -vi -H "Content-Type: application/json" --data @$TEMP_FILE $PROTOCOL://$HOST:$PORT/$URL +echo "===================================================" + +rm -f $TEMP_FILE + diff --git a/ms/neng/src/test/sanity/add-policy-vnf-uuid.sh b/ms/neng/src/test/sanity/add-policy-vnf-uuid.sh new file mode 100644 index 00000000..020dd6e4 --- /dev/null +++ b/ms/neng/src/test/sanity/add-policy-vnf-uuid.sh @@ -0,0 +1,46 @@ +#!/bin/bash +#============LICENSE_START======================================================= +# ONAP : CCSDK.apps +# ================================================================================ +# Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============LICENSE_END========================================================= + +#================================================================================== +# This script does a sanity test on the add-policy API of the micro-service. +#================================================================================== + +. ./env.sh +URL=web/service/v1/addPolicy +TEMP_FILE=/tmp/add-policy.$$.$RANDOM +EXTERNAL_KEY=${1:-123456789} + +printf '{ ' > $TEMP_FILE +printf '"policyName": "vnf-policy-uuid-1' >> $TEMP_FILE +printf '", "policyValue" : "' >> $TEMP_FILE +cat ./policy-vnf-uuid.json | sed 's/\"/\\\"/g' | tr '\n' ' ' | tr '\r' ' ' >> $TEMP_FILE +echo '"}' >> $TEMP_FILE + +echo "===================================================" +echo "====== Adding Policy: ===========================" +cat $TEMP_FILE +echo "" +echo "===================================================" + +echo "===================================================" +curl -vi -H "Content-Type: application/json" --data @$TEMP_FILE $PROTOCOL://$HOST:$PORT/$URL +echo "===================================================" + +rm -f $TEMP_FILE + diff --git a/ms/neng/src/test/sanity/add-policy-vnf.sh b/ms/neng/src/test/sanity/add-policy-vnf.sh new file mode 100644 index 00000000..b10cf57f --- /dev/null +++ b/ms/neng/src/test/sanity/add-policy-vnf.sh @@ -0,0 +1,46 @@ +#!/bin/bash +#============LICENSE_START======================================================= +# ONAP : CCSDK.apps +# ================================================================================ +# Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============LICENSE_END========================================================= + +#================================================================================== +# This script does a sanity test on the add-policy API of the micro-service. +#================================================================================== + +. ./env.sh +URL=web/service/v1/addPolicy +TEMP_FILE=/tmp/add-policy.$$.$RANDOM +EXTERNAL_KEY=${1:-123456789} + +printf '{ ' > $TEMP_FILE +printf '"policyName": "vnf-policy-1' >> $TEMP_FILE +printf '", "policyValue" : "' >> $TEMP_FILE +cat ./policy-vnf.json | sed 's/\"/\\\"/g' | tr '\n' ' ' | tr '\r' ' ' >> $TEMP_FILE +echo '"}' >> $TEMP_FILE + +echo "===================================================" +echo "====== Adding Policy: ===========================" +cat $TEMP_FILE +echo "" +echo "===================================================" + +echo "===================================================" +curl -vi -H "Content-Type: application/json" --data @$TEMP_FILE $PROTOCOL://$HOST:$PORT/$URL +echo "===================================================" + +rm -f $TEMP_FILE + diff --git a/ms/neng/src/test/sanity/gen-name-vnf-ts.sh b/ms/neng/src/test/sanity/gen-name-vnf-ts.sh new file mode 100644 index 00000000..abd3c79c --- /dev/null +++ b/ms/neng/src/test/sanity/gen-name-vnf-ts.sh @@ -0,0 +1,57 @@ +#!/bin/bash +#============LICENSE_START======================================================= +# ONAP : CCSDK.apps +# ================================================================================ +# Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============LICENSE_END========================================================= + +#================================================================================== +# This script does a sanity test on the generate-name API of this micro-service. +#================================================================================== + +. ./env.sh +URL=web/service/v1/genNetworkElementName +TEMP_FILE=/tmp/gen-name.$$.$RANDOM +EXTERNAL_KEY=$RANDOM + +USE_DB=${1:-'Y'} +USE_DB_BOOL=$([ "$USE_DB" == "Y" ] && echo "true" || echo "false") + +printf '{ "UseDb": "' > $TEMP_FILE +printf $USE_DB_BOOL >> $TEMP_FILE +printf '", "elements": [ { "external-key": "sanity-' >> $TEMP_FILE +printf $EXTERNAL_KEY >> $TEMP_FILE +printf '", "policy-instance-name": "vnf-policy-ts-1", "NF_NAMING_CODE": "me9", "COMPLEX": "dlstxa", ' >> $TEMP_FILE +printf '"resource-name": "VNF", "naming-type": "VNF" } ] }' >> $TEMP_FILE + +echo "===================================================" +echo "======== Generating name with request: ============" +echo "" +echo "" +cat $TEMP_FILE +echo "" +echo "" +echo "" +echo "===================================================" + +echo "===================================================" +curl -vi -H "Content-Type: application/json" --data @$TEMP_FILE $PROTOCOL://$HOST:$PORT/$URL +echo "" +echo "" +echo "===================================================" + +rm -f $TEMP_FILE + + diff --git a/ms/neng/src/test/sanity/gen-name-vnf-uuid.sh b/ms/neng/src/test/sanity/gen-name-vnf-uuid.sh new file mode 100644 index 00000000..9b98bd92 --- /dev/null +++ b/ms/neng/src/test/sanity/gen-name-vnf-uuid.sh @@ -0,0 +1,57 @@ +#!/bin/bash +#============LICENSE_START======================================================= +# ONAP : CCSDK.apps +# ================================================================================ +# Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============LICENSE_END========================================================= + +#================================================================================== +# This script does a sanity test on the generate-name API of this micro-service. +#================================================================================== + +. ./env.sh +URL=web/service/v1/genNetworkElementName +TEMP_FILE=/tmp/gen-name.$$.$RANDOM +EXTERNAL_KEY=$RANDOM + +USE_DB=${1:-'Y'} +USE_DB_BOOL=$([ "$USE_DB" == "Y" ] && echo "true" || echo "false") + +printf '{ "UseDb": "' > $TEMP_FILE +printf $USE_DB_BOOL >> $TEMP_FILE +printf '", "elements": [ { "external-key": "sanity-' >> $TEMP_FILE +printf $EXTERNAL_KEY >> $TEMP_FILE +printf '", "policy-instance-name": "vnf-policy-uuid-1", "NF_NAMING_CODE": "me9", "COMPLEX": "dlstxa", ' >> $TEMP_FILE +printf '"resource-name": "VNF", "naming-type": "VNF" } ] }' >> $TEMP_FILE + +echo "===================================================" +echo "======== Generating name with request: ============" +echo "" +echo "" +cat $TEMP_FILE +echo "" +echo "" +echo "" +echo "===================================================" + +echo "===================================================" +curl -vi -H "Content-Type: application/json" --data @$TEMP_FILE $PROTOCOL://$HOST:$PORT/$URL +echo "" +echo "" +echo "===================================================" + +rm -f $TEMP_FILE + + diff --git a/ms/neng/src/test/sanity/gen-name-vnf.sh b/ms/neng/src/test/sanity/gen-name-vnf.sh new file mode 100644 index 00000000..5c4c3ec5 --- /dev/null +++ b/ms/neng/src/test/sanity/gen-name-vnf.sh @@ -0,0 +1,57 @@ +#!/bin/bash +#============LICENSE_START======================================================= +# ONAP : CCSDK.apps +# ================================================================================ +# Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============LICENSE_END========================================================= + +#================================================================================== +# This script does a sanity test on the generate-name API of this micro-service. +#================================================================================== + +. ./env.sh +URL=web/service/v1/genNetworkElementName +TEMP_FILE=/tmp/gen-name.$$.$RANDOM +EXTERNAL_KEY=$RANDOM + +USE_DB=${1:-'Y'} +USE_DB_BOOL=$([ "$USE_DB" == "Y" ] && echo "true" || echo "false") + +printf '{ "UseDb": "' > $TEMP_FILE +printf $USE_DB_BOOL >> $TEMP_FILE +printf '", "elements": [ { "external-key": "sanity-' >> $TEMP_FILE +printf $EXTERNAL_KEY >> $TEMP_FILE +printf '", "policy-instance-name": "vnf-policy-1", "NF_NAMING_CODE": "me9", "COMPLEX": "dlstxa", ' >> $TEMP_FILE +printf '"resource-name": "VNF", "naming-type": "VNF" } ] }' >> $TEMP_FILE + +echo "===================================================" +echo "======== Generating name with request: ============" +echo "" +echo "" +cat $TEMP_FILE +echo "" +echo "" +echo "" +echo "===================================================" + +echo "===================================================" +curl -vi -H "Content-Type: application/json" --data @$TEMP_FILE $PROTOCOL://$HOST:$PORT/$URL +echo "" +echo "" +echo "===================================================" + +rm -f $TEMP_FILE + + diff --git a/ms/neng/src/test/sanity/policy-vnf-ts.json b/ms/neng/src/test/sanity/policy-vnf-ts.json new file mode 100644 index 00000000..ff6303dd --- /dev/null +++ b/ms/neng/src/test/sanity/policy-vnf-ts.json @@ -0,0 +1,33 @@ +[ + { + "config": { + "content": { + "naming-models":[ + { + "naming-properties":[ + { "property-name" : "COMPLEX", "property-operation" : "substr(5)" }, + { "property-name" : "SEQUENCE", "increment-sequence":{ + "max" : "zzz" , "scope" : "ENTIRETY" , "start-value" : "001" , "length" : "3", + "increment" : "1" , "sequence-type" : "alpha-numeric"} + }, + {"property-name" : "NF_NAMING_CODE"} + ], + "naming-type" : "VNF", + "nfRole" : "vPE", + "naming-recipe" : "COMPLEX|SEQUENCE|NF_NAMING_CODE|TIMESTAMP" + }, + { + "naming-properties":[ + {"property-name" : "NF_NAMING_CODE"} + ], + "naming-type" : "VNF", + "nfRole" : "VNF", + "naming-recipe" : "NF_NAMING_CODE" + } + ] + } + }, + "policyName": "vnf-policy-1" + } +] + diff --git a/ms/neng/src/test/sanity/policy-vnf-uuid.json b/ms/neng/src/test/sanity/policy-vnf-uuid.json new file mode 100644 index 00000000..4a44cc8d --- /dev/null +++ b/ms/neng/src/test/sanity/policy-vnf-uuid.json @@ -0,0 +1,33 @@ +[ + { + "config": { + "content": { + "naming-models":[ + { + "naming-properties":[ + { "property-name" : "COMPLEX", "property-operation" : "substr(5)" }, + { "property-name" : "SEQUENCE", "increment-sequence":{ + "max" : "zzz" , "scope" : "ENTIRETY" , "start-value" : "001" , "length" : "3", + "increment" : "1" , "sequence-type" : "alpha-numeric"} + }, + {"property-name" : "NF_NAMING_CODE"} + ], + "naming-type" : "VNF", + "nfRole" : "vPE", + "naming-recipe" : "COMPLEX|SEQUENCE|NF_NAMING_CODE|UUID" + }, + { + "naming-properties":[ + {"property-name" : "NF_NAMING_CODE"} + ], + "naming-type" : "VNF", + "nfRole" : "VNF", + "naming-recipe" : "NF_NAMING_CODE" + } + ] + } + }, + "policyName": "vnf-policy-1" + } +] + diff --git a/ms/neng/src/test/sanity/policy-vnf.json b/ms/neng/src/test/sanity/policy-vnf.json new file mode 100644 index 00000000..314e3f39 --- /dev/null +++ b/ms/neng/src/test/sanity/policy-vnf.json @@ -0,0 +1,33 @@ +[ + { + "config": { + "content": { + "naming-models":[ + { + "naming-properties":[ + { "property-name" : "COMPLEX", "property-operation" : "substr(5)" }, + { "property-name" : "SEQUENCE", "increment-sequence":{ + "max" : "zzz" , "scope" : "ENTIRETY" , "start-value" : "001" , "length" : "3", + "increment" : "1" , "sequence-type" : "alpha-numeric"} + }, + {"property-name" : "NF_NAMING_CODE"} + ], + "naming-type" : "VNF", + "nfRole" : "vPE", + "naming-recipe" : "COMPLEX|SEQUENCE|NF_NAMING_CODE" + }, + { + "naming-properties":[ + {"property-name" : "NF_NAMING_CODE"} + ], + "naming-type" : "VNF", + "nfRole" : "VNF", + "naming-recipe" : "NF_NAMING_CODE" + } + ] + } + }, + "policyName": "vnf-policy-1" + } +] + |