Change ServiceInstance's top-level rollbackOnFailure serialization to String 87/99287/6
authorIttay Stern <ittay.stern@att.com>
Sat, 7 Dec 2019 18:05:38 +0000 (20:05 +0200)
committerIttay Stern <ittay.stern@att.com>
Mon, 9 Dec 2019 12:26:47 +0000 (12:26 +0000)
This will satisfy a new test: Template Topology API test:
   Deploy Cypress -> getTemplateTopology returns the same template

Also updating templates__instance_template.json with actual
"templateTopology" endpoint fields.

Issue-ID: VID-724
Change-Id: I1160656c9a58ab2678ca6f2529688463fbd60a91
Signed-off-by: Ittay Stern <ittay.stern@att.com>
vid-app-common/src/main/java/org/onap/vid/model/serviceInstantiation/ServiceInstantiation.java
vid-app-common/src/main/java/org/onap/vid/utils/jackson/BooleanAsStringSerializer.java [new file with mode: 0644]
vid-automation/src/test/java/org/onap/vid/api/InstantiationTemplatesApiTest.java [new file with mode: 0644]
vid-automation/src/test/resources/asyncInstantiation/ServiceTreeForRetry_serviceInstance.json
vid-automation/src/test/resources/asyncInstantiation/ServiceWithFailedServiceInstance.json
vid-automation/src/test/resources/asyncInstantiation/templates__instance_template.json [moved from vid-webpack-master/cypress/support/jsonBuilders/mocks/jsons/instantiationTemplates/templates__instance_template.json with 94% similarity]
vid-webpack-master/cypress/integration/iFrames/instantiation-templates.e2e.ts

index 8828faf..e7e5783 100644 (file)
 package org.onap.vid.model.serviceInstantiation;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
-import org.apache.commons.lang3.ObjectUtils;
-import org.onap.vid.job.JobAdapter;
-import org.onap.vid.job.JobType;
-import org.onap.vid.model.VidNotions;
-import org.onap.vid.mso.model.ModelInfo;
-
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import org.apache.commons.lang3.ObjectUtils;
+import org.onap.vid.job.JobAdapter;
+import org.onap.vid.job.JobType;
+import org.onap.vid.model.VidNotions;
+import org.onap.vid.mso.model.ModelInfo;
+import org.onap.vid.utils.jackson.BooleanAsStringSerializer;
 
 public class ServiceInstantiation extends BaseResource implements JobAdapter.AsyncJobRequest {
 
@@ -127,6 +128,13 @@ public class ServiceInstantiation extends BaseResource implements JobAdapter.Asy
         this.vidNotions = vidNotions;
     }
 
+    @Override
+    @JsonSerialize(using=BooleanAsStringSerializer.class)
+    public boolean isRollbackOnFailure() {
+        // this override is for the BooleanAsStringSerializer annotation,
+        // but for Service-Instance level only
+        return super.isRollbackOnFailure();
+    }
 
     public String getOwningEntityId() {
         return owningEntityId;
diff --git a/vid-app-common/src/main/java/org/onap/vid/utils/jackson/BooleanAsStringSerializer.java b/vid-app-common/src/main/java/org/onap/vid/utils/jackson/BooleanAsStringSerializer.java
new file mode 100644 (file)
index 0000000..a610442
--- /dev/null
@@ -0,0 +1,39 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * VID
+ * ================================================================================
+ * Copyright (C) 2017 - 2019 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.vid.utils.jackson;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import java.io.IOException;
+
+public class BooleanAsStringSerializer extends JsonSerializer<Boolean> {
+
+    /**
+     * Annotate a Jackson getter with <code>@JsonSerialize(using=BooleanAsStringSerializer.class)</code>
+     * to get a boolean value be serialized as quoted string.
+     */
+    @Override
+    public void serialize(Boolean bool, JsonGenerator generator, SerializerProvider provider) throws IOException {
+        // bool is guaranteed not to be null
+        generator.writeString(bool.toString());
+    }
+}
diff --git a/vid-automation/src/test/java/org/onap/vid/api/InstantiationTemplatesApiTest.java b/vid-automation/src/test/java/org/onap/vid/api/InstantiationTemplatesApiTest.java
new file mode 100644 (file)
index 0000000..a14e81f
--- /dev/null
@@ -0,0 +1,138 @@
+package org.onap.vid.api;
+
+import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.arrayWithSize;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.onap.vid.api.TestUtils.convertRequest;
+import static vid.automation.test.services.SimulatorApi.registerExpectationFromPreset;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import java.io.IOException;
+import java.util.Map.Entry;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.onap.sdc.ci.tests.datatypes.UserCredentials;
+import org.onap.simulator.presetGenerator.presets.aai.PresetAAIGetSubscribersGet;
+import org.onap.vid.model.mso.MsoResponseWrapper2;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpMethod;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+import vid.automation.test.Constants;
+import vid.automation.test.model.User;
+import vid.automation.test.services.AsyncJobsService;
+import vid.automation.test.services.SimulatorApi.RegistrationStrategy;
+
+public class InstantiationTemplatesApiTest extends AsyncInstantiationBase {
+
+    /*
+    Testing the Template Topology API should be very thin, given the following
+    assumptions:
+
+      - Template topology API is relying on Retry's logic.
+
+      - The templates themselves are an actual representation of the initial
+        state in VID's backend. This is all the knowledge that used to create
+        a service in the first time. So if API is fed with same state, it already
+        should be able to reiterate another instance.
+
+
+    The tests below will verify that:
+
+      - A request resulting from Cypress test on "instantiation-templates.e2e.ts"
+        is accepted by API endpoint
+
+      - A valid "regular" (not from template) request, yields a template that a
+        Cypress is able to deploy.
+
+      These two tests are, technically,  cyclic.
+
+      Currently the only test below is shortcutting the both tests, by checking
+      that feeding a Cypress input yields a Template that is the same. This is
+      not perfect, but currently what we have.
+
+     */
+
+    @Override
+    public UserCredentials getUserCredentials() {
+        User user = usersService.getUser(Constants.Users.EMANUEL_EMANUEL);
+        return new UserCredentials(user.credentials.userId, user.credentials.password, Constants.Users.EMANUEL_EMANUEL, "", "");
+    }
+
+    @AfterMethod
+    protected void dropAllFromNameCounter() {
+        AsyncJobsService asyncJobsService = new AsyncJobsService();
+        asyncJobsService.muteAllAsyncJobs();
+        asyncJobsService.dropAllFromNameCounter();
+    }
+
+    protected String templateTopologyUri(String jobId) {
+        return uri.toASCIIString() + "/asyncInstantiation/templateTopology/" + jobId;
+    }
+
+    @Test(groups = "underDevelopment")
+    public void templateTopology_givenDeployFromCypressE2E_getTemplateTopologyDataIsEquivalent() throws IOException {
+        templateTopology_givenDeploy_templateTopologyIsEquivalent(objectMapper.readValue(
+            convertRequest(objectMapper, "asyncInstantiation/templates__instance_template.json"),
+            JsonNode.class));
+    }
+
+    public void templateTopology_givenDeploy_templateTopologyIsEquivalent(JsonNode body) {
+        registerExpectationFromPreset(new PresetAAIGetSubscribersGet(), RegistrationStrategy.CLEAR_THEN_SET);
+
+        String uuid1 = postAsyncInstanceRequest(body);
+        JsonNode templateTopology1 = restTemplate.getForObject(templateTopologyUri(uuid1), JsonNode.class);
+
+        assertThat(cleanupTemplate(templateTopology1), jsonEquals(cleanupTemplate(body)));
+    }
+
+    private JsonNode cleanupTemplate(JsonNode templateTopology) {
+        return Stream.of(templateTopology)
+            .map(this::removeTrackById)
+            .map(this::removeNullValues)
+            .findAny().get();
+    }
+
+    private JsonNode removeTrackById(JsonNode node) {
+        return removeAny(node, it -> it.getKey().equals("trackById"));
+    }
+
+    private JsonNode removeNullValues(JsonNode node) {
+        return removeAny(node, it -> it.getValue().isNull());
+    }
+
+    private JsonNode removeAny(JsonNode node, Predicate<Entry<String, JsonNode>> entryPredicate) {
+        if (node.isObject()) {
+            ((ObjectNode) node).remove(
+                Streams.fromIterator(node.fields())
+                    .filter(entryPredicate)
+                    .map(Entry::getKey)
+                    .collect(Collectors.toList())
+            );
+
+            for (JsonNode child : node) {
+                removeAny(child, entryPredicate);
+            }
+        }
+
+        return node;
+    }
+
+    private <T> String postAsyncInstanceRequest(T body) {
+        String[] jobsUuids = (String[]) restTemplate.exchange(
+            getCreateBulkUri(),
+            HttpMethod.POST,
+            new HttpEntity<>(body),
+            new ParameterizedTypeReference<MsoResponseWrapper2<String[]>>() {
+            })
+            .getBody().getEntity();
+
+        assertThat(jobsUuids, arrayWithSize(greaterThan(0)));
+        return jobsUuids[0];
+    }
+
+}
index 5139aa0..d5b282e 100644 (file)
@@ -55,7 +55,7 @@
   "instanceParams": [],
   "pause": false,
   "bulkSize": 1,
-  "rollbackOnFailure": false,
+  "rollbackOnFailure": "false",
   "isALaCarte": true,
   "testApi": "VNF_API",
   "instanceId": "INSTANCE_ID",
index 849cb7e..28761f3 100644 (file)
@@ -27,7 +27,7 @@
   "pause": false,
   "productFamilyId": "ddf9cc0f-6331-4d35-bed0-a37f2d5e9cb3",
   "projectName": "zasaki",
-  "rollbackOnFailure": false,
+  "rollbackOnFailure": "false",
   "statusMessage": "The service instantiation is failed.",
   "subscriberName": "SILVIA ROBBINS",
   "subscriptionServiceType": "TYLER SILVIA",
@@ -46,6 +46,7 @@
         {}
       ],
       "rollbackOnFailure": true,
+      "instanceId": null,
       "vfModules": {
         "vprobe_nc_vnf0..VprobeNcVnf..FE_base_module..module-0": {
           "vprobe_nc_vnf0..VprobeNcVnf..FE_base_module..module-0ahubg": {
@@ -66,7 +67,8 @@
               {}
             ],
             "rollbackOnFailure": true,
-            "trackById": "ea2879a6-10bc-4697-90d7-7bc3e71da0fd"
+            "trackById": "ea2879a6-10bc-4697-90d7-7bc3e71da0fd",
+            "isFailed": false
           }
         },
         "vprobe_nc_vnf0..VprobeNcVnf..FE_Add_On_Module_vlbagent_eph..module-1": {
             ],
             "rollbackOnFailure": true,
             "trackById": "b134410e-3bc0-478e-883e-1b6bdf8a28df",
+            "isFailed": false,
             "volumeGroupInstanceName": "zolson57arlba007_lba_dj_01_vol",
             "usePreload": true
           }
         }
       },
       "trackById": "1d2848a0-3573-4d29-b3dd-60bb263260ea",
+      "isFailed": false,
+      "statusMessage": null,
       "position": null,
       "lineOfBusiness": "EMANUEL-CONSUMER"
     }
   ],
   "pause": false,
   "bulkSize": 1,
+  "instanceId": null,
+  "isFailed": false,
+  "statusMessage": null,
   "vidNotions": {
     "instantiationUI": "anyAlacarteWhichNotExcluded",
     "modelCategory": "5G Fabric Configuration",
index 2533527..8eb70b1 100644 (file)
@@ -30,7 +30,7 @@ describe('Drawing Board: Instantiation Templates', function () {
       .as('serviceModel');
 
       cy.route(`**/asyncInstantiation/${templateTopologyEndpoint}/${templateUuid}`,
-        'fixture:../support/jsonBuilders/mocks/jsons/instantiationTemplates/templates__instance_template.json')
+        'fixture:../../../vid-automation/src/test/resources/asyncInstantiation/templates__instance_template.json')
       .as('templateTopology');
 
       // When...
@@ -48,7 +48,7 @@ describe('Drawing Board: Instantiation Templates', function () {
       // Then...
 
       cy.wait('@expectedPostAsyncInstantiation').then(xhr => {
-         cy.readFile('cypress/support/jsonBuilders/mocks/jsons/instantiationTemplates/templates__instance_template.json').then((expectedResult) => {
+         cy.readFile('../vid-automation/src/test/resources/asyncInstantiation/templates__instance_template.json').then((expectedResult) => {
            convertRollbackOnFailureValueFromStringToBoolean(expectedResult);
             cy.deepCompare(xhr.request.body, expectedResult);
         });