From afa008eebe40a6fc7d786026f86f088d61606b1c Mon Sep 17 00:00:00 2001 From: pduvvur Date: Mon, 28 Oct 2019 13:13:03 -0700 Subject: [PATCH 1/5] Added JMockit dependency to payments-api module. Added tests for ServiceBase class for Issue #60 --- payments-api/pom.xml | 14 +- .../services/base/ServiceBaseTest.java | 398 ++++++++++++++++++ 2 files changed, 408 insertions(+), 4 deletions(-) create mode 100644 payments-api/src/test/java/com/intuit/payment/services/base/ServiceBaseTest.java diff --git a/payments-api/pom.xml b/payments-api/pom.xml index 459b6800..45c977c8 100644 --- a/payments-api/pom.xml +++ b/payments-api/pom.xml @@ -1,12 +1,12 @@ org.apache.maven.plugins diff --git a/payments-api/src/test/java/com/intuit/payment/services/base/ServiceBaseTest.java b/payments-api/src/test/java/com/intuit/payment/services/base/ServiceBaseTest.java new file mode 100644 index 00000000..6c9d4e23 --- /dev/null +++ b/payments-api/src/test/java/com/intuit/payment/services/base/ServiceBaseTest.java @@ -0,0 +1,398 @@ +package com.intuit.payment.services.base; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.intuit.payment.config.RequestContext; +import com.intuit.payment.data.ECheck; +import com.intuit.payment.data.Entity; +import com.intuit.payment.data.Error; +import com.intuit.payment.data.Errors; +import com.intuit.payment.exception.AuthorizationException; +import com.intuit.payment.exception.BadRequestException; +import com.intuit.payment.exception.BaseException; +import com.intuit.payment.exception.ServiceException; +import com.intuit.payment.http.HttpRequestClient; +import com.intuit.payment.http.MethodType; +import com.intuit.payment.http.Request; +import com.intuit.payment.http.Response; +import mockit.Mock; +import mockit.MockUp; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.math.BigDecimal; + +import static org.testng.Assert.fail; + +public class ServiceBaseTest { + + private ServiceBase serviceBase; + private MockHttpRequestClient mockHttpRequestClient; + + @BeforeClass + public void setup() { + serviceBase = new ServiceBase(); + } + + @BeforeMethod + public void setupMocks() { + // Each test in this class will use the MockHttpRequestClient to mock the response for "makeRequest()" method + mockHttpRequestClient = new MockHttpRequestClient(); + } + + @Test + public void testSendRequest_successPostRequest() throws BaseException { + String eCheckId = "5"; + String eCheckNumber = "1234"; + String eCheckAmount = "600.60"; + + int httpStatusCode = 200; + String tid = "test-tid-123"; + + String expectedPostJsonContent = "{\n" + + " \"amount\" : " + eCheckAmount + ",\n" + + " \"checkNumber\" : \"" + eCheckNumber + "\"\n" + + "}"; + + String mockResponseContent = "{\"id\":\"" + eCheckId + "\",\"amount\":\"" + eCheckAmount + "\",\"checkNumber\":\"" + eCheckNumber + "\"}"; + Response mockResponse = new Response(httpStatusCode, mockResponseContent, tid); + mockHttpRequestClient.setMockResponse(mockResponse); + + ECheck eCheck = new ECheck.Builder() + .checkNumber(eCheckNumber) + .amount(new BigDecimal(eCheckAmount)) + .build(); + + Request serviceRequest = new Request.RequestBuilder(MethodType.POST, "https://ap.intuit.com") + .context(new RequestContext()) + .requestObject(eCheck) + .typeReference(new TypeReference() {}) + .build(); + + + Response actualResponse = serviceBase.sendRequest(serviceRequest); + ECheck actualResponseObject = (ECheck) actualResponse.getResponseObject(); + Request serviceRequestReceivedByClient = mockHttpRequestClient.getServiceRequestReceived(); + + // Verify that the Echeck object is serialized and sent correctly to "HttpRequestClient" + Assert.assertEquals(serviceRequestReceivedByClient.getPostJson(), expectedPostJsonContent); + + Assert.assertEquals(actualResponseObject.getAmount().toString(), eCheckAmount); + Assert.assertEquals(actualResponseObject.getCheckNumber(), eCheckNumber); + Assert.assertEquals(actualResponseObject.getId(), eCheckId); + + Assert.assertEquals(actualResponse.getContent(), mockResponseContent); + Assert.assertEquals(actualResponse.getIntuit_tid(), tid); + } + + /** + * Tests that the "sendRequest" function is able to serialize the Response content to the expected object (ECheck in this test) + * during a GET request + */ + @Test + public void testSendRequest_successGetRequest() throws BaseException { + String eCheckId = "5"; + String eCheckBalance = "505.50"; + + int httpStatusCode = 200; + String tid = "test-tid-123"; + + String mockResponseContent = "{\"id\":\"" + eCheckId + "\",\"amount\":\"" + eCheckBalance + "\"}"; + Response mockResponse = new Response(httpStatusCode, mockResponseContent, tid); + mockHttpRequestClient.setMockResponse(mockResponse); + + Request serviceRequest = new Request.RequestBuilder(MethodType.GET, "url") + .context(new RequestContext()) + .typeReference(new TypeReference() {}) + .build(); + + Response actualResponse = serviceBase.sendRequest(serviceRequest); + ECheck actualResponseObject = (ECheck) actualResponse.getResponseObject(); + + Assert.assertEquals(actualResponseObject.getId(), eCheckId); + Assert.assertEquals(actualResponseObject.getAmount().toString(), eCheckBalance); + + Assert.assertEquals(actualResponse.getContent(), mockResponseContent); + Assert.assertEquals(actualResponse.getIntuit_tid(), tid); + } + + /** + * Tests the case where response payload is empty + */ + @Test + public void testSendRequest_successEmptyResponsePayload() throws BaseException { + int httpStatusCode = 200; + String tid = "test-tid-123"; + + String mockResponseContent = ""; + Response mockResponse = new Response(httpStatusCode, mockResponseContent, tid); + mockHttpRequestClient.setMockResponse(mockResponse); + + Request serviceRequest = new Request.RequestBuilder(MethodType.GET, "url") + .context(new RequestContext()) + .build(); + + Response actualResponse = serviceBase.sendRequest(serviceRequest); + + Assert.assertNull(actualResponse.getResponseObject()); + Assert.assertEquals(actualResponse.getContent(), mockResponseContent); + Assert.assertEquals(actualResponse.getIntuit_tid(), tid); + } + + /** + * Tests that a BaseException is thrown when the response is null for the service request + */ + @Test(expectedExceptions = BaseException.class, + expectedExceptionsMessageRegExp = "Unexpected Error , service response object was null ") + public void testSendRequest_nullResponse() throws BaseException { + mockHttpRequestClient.setMockResponse(null); + + Request serviceRequest = new Request.RequestBuilder(MethodType.GET, "https://api.intuit.com/quickbooks/v4/payments/") + .context(new RequestContext()) + .typeReference(new TypeReference() {}) + .build(); + + serviceBase.sendRequest(serviceRequest); + } + + /** + * Tests the case where the HTTP status code is 404 and the call to httpRequestClient.makeRequest() + * sets the errors in the response content and deserialization of the error goes through fine + */ + @Test + public void testSendRequest_errorPageNotFound() throws BaseException { + int httpStatusCode = 404; + String tid = "test-tid-123"; + String errorDetail = "Could not find requested page"; + + String mockErrorResponseContent = "{\"errors\":[{\"code\":\"" + httpStatusCode + "\",\"detail\":\"" + errorDetail + "\"}]}"; + Response mockResponse = new Response(httpStatusCode, mockErrorResponseContent, tid); + mockHttpRequestClient.setMockResponse(mockResponse); + + Request serviceRequest = new Request.RequestBuilder(MethodType.GET, "url") + .context(new RequestContext()) + .typeReference(new TypeReference() {}) + .build(); + + // Since AuthorizationException is a custom exception and we need to assert the Errors + // inside the exception object, we're not using "expectedExceptions" + try { + serviceBase.sendRequest(serviceRequest); + fail("Expected BadRequestException to be thrown"); + } catch (BadRequestException e) { + Errors errors = e.getErrors(); + Assert.assertNotNull(errors); + Assert.assertEquals(errors.getErrorList().size(), 1); + + Error error = errors.getErrorList().get(0); + Assert.assertEquals(error.getCode(), String.valueOf(httpStatusCode)); + Assert.assertEquals(error.getDetail(), errorDetail); + } + } + + /** + * Tests the case where the HTTP status code is 404 and the call to httpRequestClient.makeRequest() + * sets the errors in the response content but the deserialization of the response error content fails + */ + @Test + public void testSendRequest_errorDeserializingErrorResponse() throws BaseException { + int httpStatusCode = 404; + String tid = "test-tid-123"; + String errorDetail = "Could not find requested page"; + + // This mock error response content has an invalid format and fields, to test the scenario when deserialization fails + String mockErrorResponseContent = "\"errorsInvalid\":[{\"codeInvalid\":\"" + httpStatusCode + "\",\"detailInvalid\":\"" + errorDetail + "\"}]"; + Response mockResponse = new Response(httpStatusCode, mockErrorResponseContent, tid); + mockHttpRequestClient.setMockResponse(mockResponse); + + Request serviceRequest = new Request.RequestBuilder(MethodType.GET, "url") + .context(new RequestContext()) + .typeReference(new TypeReference() {}) + .build(); + + // Since AuthorizationException is a custom exception and we need to assert the Errors + // inside the exception object, we're not using "expectedExceptions" + try { + serviceBase.sendRequest(serviceRequest); + fail("Expected BadRequestException to be thrown"); + } catch (BadRequestException e) { + Errors errors = e.getErrors(); + assertErrorsInException(errors, httpStatusCode, mockErrorResponseContent); + } + } + + /** + * Tests the case where the HTTP status code is 401 but there is no Error set in the response content from the + * call to httpRequestClient.makeRequest() + */ + @Test + public void testSendRequest_errorUnauthorized() throws BaseException { + int httpStatusCode = 401; + String tid = "test-tid-123"; + + String mockResponseContent = ""; + Response mockResponse = new Response(httpStatusCode, mockResponseContent, tid); + mockHttpRequestClient.setMockResponse(mockResponse); + + Request serviceRequest = new Request.RequestBuilder(MethodType.GET, "url") + .context(new RequestContext()) + .typeReference(new TypeReference() {}) + .build(); + + // Since AuthorizationException is a custom exception and we need to assert the Errors + // inside the exception object, we're not using "expectedExceptions" + try { + serviceBase.sendRequest(serviceRequest); + fail("Expected AuthorizationException to be thrown"); + } catch (AuthorizationException authEx) { + Errors errors = authEx.getErrors(); + assertErrorsInException(errors, httpStatusCode, mockResponseContent);} + } + + /** + * Tests the case where the HTTP status code is 400 but there is no Error set in the response content from the + * call to httpRequestClient.makeRequest() + */ + @Test + public void testSendRequest_errorBadRequest() throws BaseException { + int httpStatusCode = 400; + String tid = "test-tid-123"; + + String mockResponseContent = ""; + Response mockResponse = new Response(httpStatusCode, mockResponseContent, tid); + mockHttpRequestClient.setMockResponse(mockResponse); + + Request serviceRequest = new Request.RequestBuilder(MethodType.GET, "url") + .context(new RequestContext()) + .typeReference(new TypeReference() {}) + .build(); + + // Since AuthorizationException is a custom exception and we need to assert the Errors + // inside the exception object, we're not using "expectedExceptions" + try { + serviceBase.sendRequest(serviceRequest); + fail("Expected BadRequestException to be thrown"); + } catch (BadRequestException badRequestEx) { + Errors errors = badRequestEx.getErrors(); + assertErrorsInException(errors, httpStatusCode, mockResponseContent); + } + } + + /** + * Tests the case where the HTTP status code is 500 but there is no Error set in the response content from the + * call to httpRequestClient.makeRequest() + */ + @Test + public void testSendRequest_errorInternalServerError() throws BaseException { + int httpStatusCode = 500; + String tid = "test-tid-123"; + + String mockResponseContent = ""; + Response mockResponse = new Response(httpStatusCode, mockResponseContent, tid); + mockHttpRequestClient.setMockResponse(mockResponse); + + Request serviceRequest = new Request.RequestBuilder(MethodType.GET, "url") + .context(new RequestContext()) + .typeReference(new TypeReference() {}) + .build(); + + // Since AuthorizationException is a custom exception and we need to assert the Errors + // inside the exception object, we're not using "expectedExceptions" + try { + serviceBase.sendRequest(serviceRequest); + fail("Expected ServiceException to be thrown"); + } catch (ServiceException serviceEx) { + Errors errors = serviceEx.getErrors(); + assertErrorsInException(errors, httpStatusCode, mockResponseContent); + } + } + + /** + * Tests the case where the HTTP status code is 301 but there is no Error set in the response content from the + * call to httpRequestClient.makeRequest() + */ + @Test + public void testSendRequest_errorMovedPermanently() { + int httpStatusCode = 301; + String tid = "test-tid-123"; + + String mockResponseContent = ""; + Response mockResponse = new Response(httpStatusCode, mockResponseContent, tid); + mockHttpRequestClient.setMockResponse(mockResponse); + + Request serviceRequest = new Request.RequestBuilder(MethodType.GET, "url") + .context(new RequestContext()) + .typeReference(new TypeReference() {}) + .build(); + + // Since AuthorizationException is a custom exception and we need to assert the Errors + // inside the exception object, we're not using "expectedExceptions" + try { + serviceBase.sendRequest(serviceRequest); + fail("Expected BaseException to be thrown"); + } catch (BaseException baseEx) { + Errors errors = baseEx.getErrors(); + assertErrorsInException(errors, httpStatusCode, mockResponseContent); + } + } + + /** + * Tests that intuit_tid and requestId is being set on the entity + */ + @Test + public void testPrepareResponse_success() { + String expectedRequestId = "146-request-id"; + String expectedTid = "112-tid"; + + RequestContext requestContext = new RequestContext(); + requestContext.setRequestId(expectedRequestId); + + Request request = new Request.RequestBuilder(MethodType.GET, "url") + .context(requestContext) + .build(); + + Response response = new Response(200, "{}", expectedTid); + + Entity entity = new Entity() {}; + + serviceBase.prepareResponse(request, response, entity); + + Assert.assertEquals(entity.getIntuit_tid(), expectedTid); + Assert.assertEquals(entity.getRequestId(), expectedRequestId); + } + + private void assertErrorsInException(Errors actualErrors, int expectedHttpStatusCode, String expectedErrorContent) { + Assert.assertNotNull(actualErrors); + Assert.assertEquals(actualErrors.getErrorList().size(), 1); + + Error error = actualErrors.getErrorList().get(0); + Assert.assertEquals(error.getCode(), "HttpStatusCode-" + expectedHttpStatusCode); + Assert.assertEquals(error.getDetail(), "ResponsePayload: " + expectedErrorContent); + } + + /** + * This is a mock implementation of the HttpRequestClient to mock the response from this class + * Only the "makeRequest()" method is mocked. Other methods can be mocked if necessary. + */ + private final class MockHttpRequestClient extends MockUp { + + private Response mockResponse; + private Request serviceRequestReceived; // Used for asserting the request that was received + + void setMockResponse(Response mockResponse) { + this.mockResponse = mockResponse; + } + + Request getServiceRequestReceived() { + return serviceRequestReceived; + } + + @Mock + public Response makeRequest(Request serviceRequest) throws BadRequestException { + this.serviceRequestReceived = serviceRequest; // Used for asserting the values in the request + + return this.mockResponse; + } + } +} From 4da94f284fd5a28418e1eb09f3f71c083ab1a52a Mon Sep 17 00:00:00 2001 From: pduvvur Date: Mon, 28 Oct 2019 13:20:19 -0700 Subject: [PATCH 2/5] Added copyright notice --- .../payment/services/base/ServiceBaseTest.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/payments-api/src/test/java/com/intuit/payment/services/base/ServiceBaseTest.java b/payments-api/src/test/java/com/intuit/payment/services/base/ServiceBaseTest.java index 6c9d4e23..0aa3e61d 100644 --- a/payments-api/src/test/java/com/intuit/payment/services/base/ServiceBaseTest.java +++ b/payments-api/src/test/java/com/intuit/payment/services/base/ServiceBaseTest.java @@ -1,3 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2017 Intuit + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ package com.intuit.payment.services.base; import com.fasterxml.jackson.core.type.TypeReference; From ebde369e08ba33cb1159602c3c2b3ce6092c2d0b Mon Sep 17 00:00:00 2001 From: pduvvur Date: Mon, 28 Oct 2019 14:23:28 -0700 Subject: [PATCH 3/5] Dummy commit --- .../java/com/intuit/payment/services/base/ServiceBaseTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/payments-api/src/test/java/com/intuit/payment/services/base/ServiceBaseTest.java b/payments-api/src/test/java/com/intuit/payment/services/base/ServiceBaseTest.java index 0aa3e61d..603b156c 100644 --- a/payments-api/src/test/java/com/intuit/payment/services/base/ServiceBaseTest.java +++ b/payments-api/src/test/java/com/intuit/payment/services/base/ServiceBaseTest.java @@ -41,7 +41,6 @@ import static org.testng.Assert.fail; public class ServiceBaseTest { - private ServiceBase serviceBase; private MockHttpRequestClient mockHttpRequestClient; From 24591f5cae7e1911d2e3025a3bdc8b8ebebdf055 Mon Sep 17 00:00:00 2001 From: pduvvur Date: Mon, 28 Oct 2019 15:19:16 -0700 Subject: [PATCH 4/5] Updated pom.xml to allow JMockit tests to run on JDK 9 or greater --- payments-api/pom.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/payments-api/pom.xml b/payments-api/pom.xml index 45c977c8..97f49d21 100644 --- a/payments-api/pom.xml +++ b/payments-api/pom.xml @@ -141,6 +141,16 @@ + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M3 + + + -Djdk.attach.allowAttachSelf + + + From 71450d5560041a1486241c750a72b9bb5473c50a Mon Sep 17 00:00:00 2001 From: pduvvur Date: Mon, 28 Oct 2019 15:30:55 -0700 Subject: [PATCH 5/5] Updated comments --- .../intuit/payment/services/base/ServiceBaseTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/payments-api/src/test/java/com/intuit/payment/services/base/ServiceBaseTest.java b/payments-api/src/test/java/com/intuit/payment/services/base/ServiceBaseTest.java index 603b156c..278b8525 100644 --- a/payments-api/src/test/java/com/intuit/payment/services/base/ServiceBaseTest.java +++ b/payments-api/src/test/java/com/intuit/payment/services/base/ServiceBaseTest.java @@ -189,7 +189,7 @@ public void testSendRequest_errorPageNotFound() throws BaseException { .typeReference(new TypeReference() {}) .build(); - // Since AuthorizationException is a custom exception and we need to assert the Errors + // Since BadRequestException is a custom exception and we need to assert the Errors // inside the exception object, we're not using "expectedExceptions" try { serviceBase.sendRequest(serviceRequest); @@ -225,7 +225,7 @@ public void testSendRequest_errorDeserializingErrorResponse() throws BaseExcepti .typeReference(new TypeReference() {}) .build(); - // Since AuthorizationException is a custom exception and we need to assert the Errors + // Since BadRequestException is a custom exception and we need to assert the Errors // inside the exception object, we're not using "expectedExceptions" try { serviceBase.sendRequest(serviceRequest); @@ -282,7 +282,7 @@ public void testSendRequest_errorBadRequest() throws BaseException { .typeReference(new TypeReference() {}) .build(); - // Since AuthorizationException is a custom exception and we need to assert the Errors + // Since BadRequestException is a custom exception and we need to assert the Errors // inside the exception object, we're not using "expectedExceptions" try { serviceBase.sendRequest(serviceRequest); @@ -311,7 +311,7 @@ public void testSendRequest_errorInternalServerError() throws BaseException { .typeReference(new TypeReference() {}) .build(); - // Since AuthorizationException is a custom exception and we need to assert the Errors + // Since ServiceException is a custom exception and we need to assert the Errors // inside the exception object, we're not using "expectedExceptions" try { serviceBase.sendRequest(serviceRequest); @@ -340,7 +340,7 @@ public void testSendRequest_errorMovedPermanently() { .typeReference(new TypeReference() {}) .build(); - // Since AuthorizationException is a custom exception and we need to assert the Errors + // Since BaseException is a custom exception and we need to assert the Errors // inside the exception object, we're not using "expectedExceptions" try { serviceBase.sendRequest(serviceRequest);