From 184e1ed3e83effc39b6f7f92c9f4b9d874c4cfe7 Mon Sep 17 00:00:00 2001 From: "Benjamin, Max (mb388a)" Date: Mon, 17 Sep 2018 10:52:09 -0400 Subject: add single transaction api to aaiclient fixed marshalling when issuing a patch request added support for single transaction api in A&AI Change-Id: Icf755f547523cc7dbf931e198177847a5a1c6ea1 Issue-ID: SO-1060 Signed-off-by: Benjamin, Max (mb388a) --- .../onap/so/client/aai/AAIPatchConverterTest.java | 102 ++++++++++++++++ .../org/onap/so/client/aai/AAIRestClientTest.java | 72 ++--------- .../client/aai/AAISingleTransactionClientTest.java | 133 +++++++++++++++++++++ .../so/client/aai/AAITransactionalClientTest.java | 13 ++ .../aai/singletransaction/sample-request.json | 26 ++++ .../singletransaction/sample-response-failure.json | 30 +++++ .../aai/singletransaction/sample-response.json | 22 ++++ 7 files changed, 339 insertions(+), 59 deletions(-) create mode 100644 common/src/test/java/org/onap/so/client/aai/AAIPatchConverterTest.java create mode 100644 common/src/test/java/org/onap/so/client/aai/AAISingleTransactionClientTest.java create mode 100644 common/src/test/resources/__files/aai/singletransaction/sample-request.json create mode 100644 common/src/test/resources/__files/aai/singletransaction/sample-response-failure.json create mode 100644 common/src/test/resources/__files/aai/singletransaction/sample-response.json (limited to 'common/src/test') diff --git a/common/src/test/java/org/onap/so/client/aai/AAIPatchConverterTest.java b/common/src/test/java/org/onap/so/client/aai/AAIPatchConverterTest.java new file mode 100644 index 0000000000..008b612cd8 --- /dev/null +++ b/common/src/test/java/org/onap/so/client/aai/AAIPatchConverterTest.java @@ -0,0 +1,102 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 - 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========================================================= + */ + +package org.onap.so.client.aai; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aai.domain.yang.GenericVnf; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; + + +@RunWith(MockitoJUnitRunner.class) +public class AAIPatchConverterTest { + + private ObjectMapper mapper = new AAICommonObjectMapperProvider().getMapper(); + + @Test + public void convertObjectToPatchFormatTest() throws URISyntaxException, JsonParseException, JsonMappingException, IOException { + AAIPatchConverter validator = new AAIPatchConverter(); + GenericVnf vnf = new GenericVnf(); + vnf.setIpv4Loopback0Address(""); + String result = validator.marshallObjectToPatchFormat(vnf); + GenericVnf resultObj = mapper.readValue(result.toString(), GenericVnf.class); + assertTrue("expect object to become a String to prevent double marshalling", result instanceof String); + assertNull("expect null because of custom mapper", resultObj.getIpv4Loopback0Address()); + + } + + @Test + public void convertStringToPatchFormatTest() throws URISyntaxException, JsonParseException, JsonMappingException, IOException { + AAIPatchConverter validator = new AAIPatchConverter(); + String payload = "{\"ipv4-loopback0-address\":\"\"}"; + String result = validator.marshallObjectToPatchFormat(payload); + + assertEquals("expect no change", payload, result); + } + + @Test + public void convertMapToPatchFormatTest() throws URISyntaxException, JsonParseException, JsonMappingException, IOException { + AAIPatchConverter validator = new AAIPatchConverter(); + HashMap map = new HashMap<>(); + map.put("ipv4-loopback0-address", ""); + String result = validator.marshallObjectToPatchFormat(map); + + assertEquals("expect string", "{\"ipv4-loopback0-address\":\"\"}", result); + } + + @Test + public void hasComplexObjectTest() { + AAIPatchConverter validator = new AAIPatchConverter(); + String hasNesting = "{ \"hello\" : \"world\", \"nested\" : { \"key\" : \"value\" } }"; + String noNesting = "{ \"hello\" : \"world\" }"; + String arrayCase = "{ \"hello\" : \"world\", \"nestedSimple\" : [\"value1\" , \"value2\"], \"nestedComplex\" : [{\"key\" : \"value\"}]}"; + String empty = "{}"; + String arrayCaseSimpleOnly = "{ \"hello\" : \"world\", \"nestedSimple\" : [\"value1\" , \"value2\"]}"; + String relationshipListCaseNesting = "{ \"hello\" : \"world\", \"nestedSimple\" : [\"value1\" , \"value2\"], \"relationship-list\" : [{\"key\" : \"value\"}], \"nested\" : { \"key\" : \"value\" }}"; + String relationshipListCase = "{ \"hello\" : \"world\", \"nestedSimple\" : [\"value1\" , \"value2\"], \"relationship-list\" : [{\"key\" : \"value\"}]}"; + String nothing = ""; + + assertTrue("expect has nesting", validator.hasComplexObject(hasNesting)); + assertFalse("expect no nesting", validator.hasComplexObject(noNesting)); + assertTrue("expect has nesting", validator.hasComplexObject(arrayCase)); + assertFalse("expect no nesting", validator.hasComplexObject(empty)); + assertFalse("expect no nesting", validator.hasComplexObject(arrayCaseSimpleOnly)); + assertFalse("expect no nesting", validator.hasComplexObject(relationshipListCase)); + assertTrue("expect has nesting", validator.hasComplexObject(relationshipListCaseNesting)); + assertFalse("expect no nesting", validator.hasComplexObject(nothing)); + } + +} diff --git a/common/src/test/java/org/onap/so/client/aai/AAIRestClientTest.java b/common/src/test/java/org/onap/so/client/aai/AAIRestClientTest.java index f2e371c999..752c49eb5b 100644 --- a/common/src/test/java/org/onap/so/client/aai/AAIRestClientTest.java +++ b/common/src/test/java/org/onap/so/client/aai/AAIRestClientTest.java @@ -21,18 +21,16 @@ package org.onap.so.client.aai; import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; -import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; -import java.util.HashMap; import javax.ws.rs.core.Response; @@ -42,11 +40,9 @@ import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import org.onap.aai.domain.yang.GenericVnf; +import org.onap.so.client.RestClientSSL; import org.onap.so.client.graphinventory.exceptions.GraphInventoryPatchDepthExceededException; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; @RunWith(MockitoJUnitRunner.class) @@ -60,65 +56,23 @@ public class AAIRestClientTest { @Rule public ExpectedException thrown = ExpectedException.none(); - @Test - public void convertObjectToPatchFormatTest() throws URISyntaxException, JsonParseException, JsonMappingException, IOException { - AAIRestClient client = new AAIRestClient(props, new URI("")); - GenericVnf vnf = new GenericVnf(); - vnf.setIpv4Loopback0Address(""); - String result = client.convertObjectToPatchFormat(vnf); - GenericVnf resultObj = mapper.readValue(result.toString(), GenericVnf.class); - assertTrue("expect object to become a String to prevent double marshalling", result instanceof String); - assertNull("expect null because of custom mapper", resultObj.getIpv4Loopback0Address()); - - } - - @Test - public void convertStringToPatchFormatTest() throws URISyntaxException, JsonParseException, JsonMappingException, IOException { - AAIRestClient client = new AAIRestClient(props, new URI("")); - String payload = "{\"ipv4-loopback0-address\":\"\"}"; - String result = client.convertObjectToPatchFormat(payload); - - assertEquals("expect no change", payload, result); - } - - @Test - public void convertMapToPatchFormatTest() throws URISyntaxException, JsonParseException, JsonMappingException, IOException { - AAIRestClient client = new AAIRestClient(props, new URI("")); - HashMap map = new HashMap<>(); - map.put("ipv4-loopback0-address", ""); - String result = client.convertObjectToPatchFormat(map); - - assertEquals("expect string", "{\"ipv4-loopback0-address\":\"\"}", result); - } - @Test public void failPatchOnComplexObject() throws URISyntaxException { AAIRestClient client = new AAIRestClient(props, new URI("")); this.thrown.expect(GraphInventoryPatchDepthExceededException.class); this.thrown.expectMessage(containsString("Object exceeds allowed depth for update action")); client.patch("{ \"hello\" : \"world\", \"nestedSimple\" : [\"value1\" , \"value2\"], \"relationship-list\" : [{\"key\" : \"value\"}], \"nested\" : { \"key\" : \"value\" }}"); - } @Test - public void hasComplexObjectTest() throws URISyntaxException { + public void verifyPatchValidation() throws URISyntaxException { AAIRestClient client = new AAIRestClient(props, new URI("")); - String hasNesting = "{ \"hello\" : \"world\", \"nested\" : { \"key\" : \"value\" } }"; - String noNesting = "{ \"hello\" : \"world\" }"; - String arrayCase = "{ \"hello\" : \"world\", \"nestedSimple\" : [\"value1\" , \"value2\"], \"nestedComplex\" : [{\"key\" : \"value\"}]}"; - String empty = "{}"; - String arrayCaseSimpleOnly = "{ \"hello\" : \"world\", \"nestedSimple\" : [\"value1\" , \"value2\"]}"; - String relationshipListCaseNesting = "{ \"hello\" : \"world\", \"nestedSimple\" : [\"value1\" , \"value2\"], \"relationship-list\" : [{\"key\" : \"value\"}], \"nested\" : { \"key\" : \"value\" }}"; - String relationshipListCase = "{ \"hello\" : \"world\", \"nestedSimple\" : [\"value1\" , \"value2\"], \"relationship-list\" : [{\"key\" : \"value\"}]}"; - String nothing = ""; - - assertTrue("expect has nesting", client.hasComplexObject(hasNesting)); - assertFalse("expect no nesting", client.hasComplexObject(noNesting)); - assertTrue("expect has nesting", client.hasComplexObject(arrayCase)); - assertFalse("expect no nesting", client.hasComplexObject(empty)); - assertFalse("expect no nesting", client.hasComplexObject(arrayCaseSimpleOnly)); - assertFalse("expect no nesting", client.hasComplexObject(relationshipListCase)); - assertTrue("expect has nesting", client.hasComplexObject(relationshipListCaseNesting)); - assertFalse("expect no nesting", client.hasComplexObject(nothing)); + AAIRestClient spy = spy(client); + AAIPatchConverter patchValidatorMock = mock(AAIPatchConverter.class); + doReturn(patchValidatorMock).when(spy).getPatchConverter(); + String payload = "{}"; + doReturn(Response.ok().build()).when(spy).method(eq("PATCH"), any()); + spy.patch(payload); + verify(patchValidatorMock, times(1)).convertPatchFormat(eq((Object)payload)); } } diff --git a/common/src/test/java/org/onap/so/client/aai/AAISingleTransactionClientTest.java b/common/src/test/java/org/onap/so/client/aai/AAISingleTransactionClientTest.java new file mode 100644 index 0000000000..8c42686e5f --- /dev/null +++ b/common/src/test/java/org/onap/so/client/aai/AAISingleTransactionClientTest.java @@ -0,0 +1,133 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 - 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========================================================= + */ + +package org.onap.so.client.aai; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Optional; + +import org.junit.Before; +import org.junit.Test; +import org.onap.aai.domain.yang.Pserver; +import org.onap.aai.domain.yang.v9.Complex; +import org.onap.so.client.aai.entities.singletransaction.SingleTransactionRequest; +import org.onap.so.client.aai.entities.singletransaction.SingleTransactionResponse; +import org.onap.so.client.aai.entities.uri.AAIResourceUri; +import org.onap.so.client.aai.entities.uri.AAIUriFactory; +import org.onap.so.client.defaultproperties.DefaultAAIPropertiesImpl; +import org.skyscreamer.jsonassert.JSONAssert; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + +public class AAISingleTransactionClientTest { + + private final static String AAI_JSON_FILE_LOCATION = "src/test/resources/__files/aai/singletransaction/"; + AAIResourceUri uriA = AAIUriFactory.createResourceUri(AAIObjectType.PSERVER, "pserver-hostname"); + AAIResourceUri uriB = AAIUriFactory.createResourceUri(AAIObjectType.COMPLEX, "my-complex"); + + ObjectMapper mapper; + + @Before + public void before() throws JsonParseException, JsonMappingException, IOException { + mapper = new AAICommonObjectMapperProvider().getMapper(); + mapper.enable(SerializationFeature.INDENT_OUTPUT); + } + + @Test + public void testRequest() throws IOException { + AAIResourcesClient client = createClient(); + Pserver pserver = new Pserver(); + pserver.setHostname("pserver-hostname"); + pserver.setFqdn("pserver-bulk-process-single-transactions-multiple-actions-1-fqdn"); + Pserver pserver2 = new Pserver(); + pserver2.setFqdn("patched-fqdn"); + Complex complex = new Complex(); + complex.setCity("my-city"); + AAISingleTransactionClient singleTransaction = + client.beginSingleTransaction() + .create(uriA, pserver) + .update(uriA, pserver2) + .create(uriB, complex); + + + SingleTransactionRequest actual = singleTransaction.getRequest(); + + SingleTransactionRequest expected = mapper.readValue(this.getJson("sample-request.json"), SingleTransactionRequest.class); + + JSONAssert.assertEquals(mapper.writeValueAsString(expected),mapper.writeValueAsString(actual), false); + } + + @Test + public void testFailure() throws IOException { + AAIResourcesClient client = createClient(); + AAISingleTransactionClient singleTransaction = client.beginSingleTransaction(); + SingleTransactionResponse expected = mapper.readValue(this.getJson("sample-response-failure.json"), SingleTransactionResponse.class); + Optional errorMessage = singleTransaction.locateErrorMessages(expected); + + assertThat(expected.getOperationResponses().size(), greaterThan(0)); + assertThat(errorMessage.isPresent(), equalTo(true)); + + } + + @Test + public void testSuccessResponse() throws IOException { + AAIResourcesClient client = createClient(); + AAISingleTransactionClient singleTransaction = client.beginSingleTransaction(); + SingleTransactionResponse expected = mapper.readValue(this.getJson("sample-response.json"), SingleTransactionResponse.class); + Optional errorMessage = singleTransaction.locateErrorMessages(expected); + + assertThat(expected.getOperationResponses().size(), greaterThan(0)); + assertThat(errorMessage.isPresent(), equalTo(false)); + + } + + @Test + public void confirmPatchFormat() { + AAISingleTransactionClient singleTransaction = spy(new AAISingleTransactionClient(AAIVersion.LATEST)); + AAIPatchConverter mock = mock(AAIPatchConverter.class); + doReturn(mock).when(singleTransaction).getPatchConverter(); + singleTransaction.update(uriA, "{}"); + verify(mock, times(1)).convertPatchFormat(any()); + } + private String getJson(String filename) throws IOException { + return new String(Files.readAllBytes(Paths.get(AAI_JSON_FILE_LOCATION + filename))); + } + + private AAIResourcesClient createClient() { + AAIResourcesClient client = spy(new AAIResourcesClient()); + doReturn(new DefaultAAIPropertiesImpl()).when(client).getRestProperties(); + return client; + } +} diff --git a/common/src/test/java/org/onap/so/client/aai/AAITransactionalClientTest.java b/common/src/test/java/org/onap/so/client/aai/AAITransactionalClientTest.java index f6ee826a78..cbf8d67a82 100644 --- a/common/src/test/java/org/onap/so/client/aai/AAITransactionalClientTest.java +++ b/common/src/test/java/org/onap/so/client/aai/AAITransactionalClientTest.java @@ -21,8 +21,12 @@ package org.onap.so.client.aai; import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import java.io.IOException; import java.nio.file.Files; @@ -136,6 +140,15 @@ public class AAITransactionalClientTest { assertEquals(transactions.locateErrorMessages(getJson("response-failure.json")).get(), "another error message\nmy great error"); } + @Test + public void confirmPatchFormat() { + AAITransactionalClient client = spy(new AAITransactionalClient(AAIVersion.LATEST)); + AAIPatchConverter mock = mock(AAIPatchConverter.class); + doReturn(mock).when(client).getPatchConverter(); + client.update(uriA, "{}"); + verify(mock, times(1)).convertPatchFormat(any()); + } + private String getJson(String filename) throws IOException { return new String(Files.readAllBytes(Paths.get(AAI_JSON_FILE_LOCATION + filename))); } diff --git a/common/src/test/resources/__files/aai/singletransaction/sample-request.json b/common/src/test/resources/__files/aai/singletransaction/sample-request.json new file mode 100644 index 0000000000..f0761a07b6 --- /dev/null +++ b/common/src/test/resources/__files/aai/singletransaction/sample-request.json @@ -0,0 +1,26 @@ +{ + "operations": [ + { + "action": "put", + "uri": "/cloud-infrastructure/pservers/pserver/pserver-hostname", + "body": { + "hostname": "pserver-hostname", + "fqdn": "pserver-bulk-process-single-transactions-multiple-actions-1-fqdn" + } + }, + { + "action": "patch", + "uri": "/cloud-infrastructure/pservers/pserver/pserver-hostname", + "body": { + "fqdn": "patched-fqdn" + } + }, + { + "action": "put", + "uri": "/cloud-infrastructure/complexes/complex/my-complex", + "body": { + "city": "my-city" + } + } + ] +} \ No newline at end of file diff --git a/common/src/test/resources/__files/aai/singletransaction/sample-response-failure.json b/common/src/test/resources/__files/aai/singletransaction/sample-response-failure.json new file mode 100644 index 0000000000..d0b0e39924 --- /dev/null +++ b/common/src/test/resources/__files/aai/singletransaction/sample-response-failure.json @@ -0,0 +1,30 @@ +{ + "operation-responses": [ + { + "action": "put", + "uri": "/cloud-infrastructure/pservers/pserver/pserver-hostname", + "response-status-code": 201, + "response-body": null + }, + { + "action": "patch", + "uri": "/cloud-infrastructure/pservers/pserver/pserver-hostname", + "response-status-code": 200, + "response-body": null + }, + { + "action": "put", + "uri": "/cloud-infrastructure/complexes/complex/my-complex", + "response-status-code": 400, + "response-body": { + "requestError": { + "serviceException": { + "messageId": "SVC3003", + "text": "another error message", + "variables": [] + } + } + } + } + ] +} \ No newline at end of file diff --git a/common/src/test/resources/__files/aai/singletransaction/sample-response.json b/common/src/test/resources/__files/aai/singletransaction/sample-response.json new file mode 100644 index 0000000000..a5b322ee2e --- /dev/null +++ b/common/src/test/resources/__files/aai/singletransaction/sample-response.json @@ -0,0 +1,22 @@ +{ + "operation-responses": [ + { + "action": "put", + "uri": "/cloud-infrastructure/pservers/pserver/pserver-hostname", + "response-status-code": 201, + "response-body": null + }, + { + "action": "patch", + "uri": "/cloud-infrastructure/pservers/pserver/pserver-hostname", + "response-status-code": 200, + "response-body": null + }, + { + "action": "put", + "uri": "/cloud-infrastructure/complexes/complex/my-complex", + "response-status-code": 201, + "response-body": null + } + ] +} \ No newline at end of file -- cgit 1.2.3-korg