diff --git a/CHANGELOG.md b/CHANGELOG.md index d62380e46..a2f183ce8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [5.3.1] +## [5.4.0] ### Added -- Added AppEndpoint for ConnectAction +- Added AppEndpoint support for ConnectAction. +- Added the ability to log the API response in when logger is set to debug mode. +- Added ability to override base url for StopStream, ModifyCall, and Sn ## [5.3.0] ### Added diff --git a/build.gradle b/build.gradle index 2b925be95..88d080b67 100644 --- a/build.gradle +++ b/build.gradle @@ -47,6 +47,8 @@ dependencies { testCompile 'junit:junit:4.4' testCompile "org.mockito:mockito-core:2.25.1" testCompile 'org.hamcrest:hamcrest-all:1.3' + testCompile group: 'org.powermock', name: 'powermock-api-mockito2', version: '2.0.7' + testCompile group: 'org.powermock', name: 'powermock-module-junit4', version: '2.0.7' } test { diff --git a/src/main/java/com/nexmo/client/AbstractMethod.java b/src/main/java/com/nexmo/client/AbstractMethod.java index 1e7627d83..342b2d01f 100644 --- a/src/main/java/com/nexmo/client/AbstractMethod.java +++ b/src/main/java/com/nexmo/client/AbstractMethod.java @@ -22,6 +22,7 @@ package com.nexmo.client; import com.nexmo.client.auth.AuthMethod; +import com.nexmo.client.logging.LoggingUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.HttpEntity; @@ -100,6 +101,9 @@ public ResultT execute(RequestT request) throws NexmoResponseParseException, Nex LOG.debug(EntityUtils.toString(enclosingRequest.getEntity())); } HttpResponse response = this.httpWrapper.getHttpClient().execute(httpRequest); + + LOG.debug("Response: " + LoggingUtils.logResponse(response)); + try{ return parseResponse(response); } diff --git a/src/main/java/com/nexmo/client/logging/LoggingUtils.java b/src/main/java/com/nexmo/client/logging/LoggingUtils.java new file mode 100644 index 000000000..9dd96e960 --- /dev/null +++ b/src/main/java/com/nexmo/client/logging/LoggingUtils.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011-2017 Nexmo Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.nexmo.client.logging; + +import org.apache.http.HttpResponse; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; + +public class LoggingUtils { + + public static String logResponse(HttpResponse response) throws IOException { + StringBuilder log = new StringBuilder(); + String responseBody = EntityUtils.toString(response.getEntity()); + int statusCode = response.getStatusLine().getStatusCode(); + String statusLine = response.getStatusLine().getReasonPhrase(); + + log.append("status_code: ") + .append(statusCode) + .append( ", ") + .append("status_line: ") + .append(statusLine) + .append(", ") + .append(" body: ") + .append(responseBody); + + //Calling Http#getEntity will consume the entity so you have to replace the entity after logging + response.setEntity(new StringEntity(responseBody, ContentType.get(response.getEntity()))); + + return log.toString(); + } +} diff --git a/src/test/java/com/nexmo/client/AbstractMethodTest.java b/src/test/java/com/nexmo/client/AbstractMethodTest.java index 269fc1bf2..a2d36d050 100644 --- a/src/test/java/com/nexmo/client/AbstractMethodTest.java +++ b/src/test/java/com/nexmo/client/AbstractMethodTest.java @@ -25,9 +25,13 @@ import com.nexmo.client.auth.AuthCollection; import com.nexmo.client.auth.AuthMethod; import com.nexmo.client.auth.JWTAuthMethod; +import com.nexmo.client.logging.LoggingUtils; import io.jsonwebtoken.lang.Assert; import org.apache.commons.io.IOUtils; -import org.apache.http.*; +import org.apache.http.HttpEntity; +import org.apache.http.HttpEntityEnclosingRequest; +import org.apache.http.HttpResponse; +import org.apache.http.ProtocolVersion; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.RequestBuilder; @@ -38,7 +42,10 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; import java.io.IOException; import java.nio.charset.Charset; @@ -46,8 +53,10 @@ import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.*; +import static org.powermock.api.mockito.PowerMockito.mockStatic; - +@RunWith(PowerMockRunner.class) +@PrepareForTest(LoggingUtils.class) public class AbstractMethodTest { private static class ConcreteMethod extends AbstractMethod { public ConcreteMethod(HttpWrapper httpWrapper) { @@ -86,6 +95,7 @@ public String parseResponse(HttpResponse response) throws IOException{ @Before public void setUp() throws Exception { + mockStatic(LoggingUtils.class); mockWrapper = mock(HttpWrapper.class); mockAuthMethods = mock(AuthCollection.class); mockAuthMethod = mock(AuthMethod.class); @@ -98,6 +108,7 @@ public void setUp() throws Exception { 1, 1 ), 200, "OK"))); + when(LoggingUtils.logResponse(any(HttpResponse.class))).thenReturn("response logged"); when(mockWrapper.getAuthCollection()).thenReturn(mockAuthMethods); } diff --git a/src/test/java/com/nexmo/client/ClientTest.java b/src/test/java/com/nexmo/client/ClientTest.java index f71ead57a..f625943cb 100644 --- a/src/test/java/com/nexmo/client/ClientTest.java +++ b/src/test/java/com/nexmo/client/ClientTest.java @@ -22,19 +22,26 @@ package com.nexmo.client; import com.nexmo.client.auth.TokenAuthMethod; +import com.nexmo.client.logging.LoggingUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpUriRequest; import org.junit.Before; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; import java.io.ByteArrayInputStream; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +@RunWith(PowerMockRunner.class) +@PrepareForTest(LoggingUtils.class) public abstract class ClientTest { protected HttpWrapper wrapper; protected T client; @@ -46,12 +53,14 @@ public void setupWrapper() { protected HttpClient stubHttpClient(int statusCode, String content) throws Exception { HttpClient result = mock(HttpClient.class); + mockStatic(LoggingUtils.class); HttpResponse response = mock(HttpResponse.class); StatusLine sl = mock(StatusLine.class); HttpEntity entity = mock(HttpEntity.class); when(result.execute(any(HttpUriRequest.class))).thenReturn(response); + when(LoggingUtils.logResponse(any(HttpResponse.class))).thenReturn("response logged"); when(entity.getContent()).thenReturn(new ByteArrayInputStream(content.getBytes("UTF-8"))); when(sl.getStatusCode()).thenReturn(statusCode); when(response.getStatusLine()).thenReturn(sl); diff --git a/src/test/java/com/nexmo/client/NexmoClientTest.java b/src/test/java/com/nexmo/client/NexmoClientTest.java index dcd8442af..0d5dfdbd0 100644 --- a/src/test/java/com/nexmo/client/NexmoClientTest.java +++ b/src/test/java/com/nexmo/client/NexmoClientTest.java @@ -22,6 +22,7 @@ package com.nexmo.client; import com.nexmo.client.auth.*; +import com.nexmo.client.logging.LoggingUtils; import com.nexmo.client.voice.Call; import com.nexmo.client.voice.CallEvent; import com.nexmo.client.voice.CallStatus; @@ -36,6 +37,9 @@ import org.apache.http.client.methods.RequestBuilder; import org.apache.http.message.BasicNameValuePair; import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; @@ -51,18 +55,23 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +@RunWith(PowerMockRunner.class) +@PrepareForTest(LoggingUtils.class) public class NexmoClientTest { private TestUtils testUtils = new TestUtils(); private HttpClient stubHttpClient(int statusCode, String content) throws Exception { HttpClient result = mock(HttpClient.class); + mockStatic(LoggingUtils.class); HttpResponse response = mock(HttpResponse.class); StatusLine sl = mock(StatusLine.class); HttpEntity entity = mock(HttpEntity.class); when(result.execute(any(HttpUriRequest.class))).thenReturn(response); + when(LoggingUtils.logResponse(any(HttpResponse.class))).thenReturn("response logged"); when(entity.getContent()).thenReturn(new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8))); when(sl.getStatusCode()).thenReturn(statusCode); when(response.getStatusLine()).thenReturn(sl); diff --git a/src/test/java/com/nexmo/client/numbers/NumbersClientTest.java b/src/test/java/com/nexmo/client/numbers/NumbersClientTest.java index 5ad8b3caf..b252d84af 100644 --- a/src/test/java/com/nexmo/client/numbers/NumbersClientTest.java +++ b/src/test/java/com/nexmo/client/numbers/NumbersClientTest.java @@ -25,12 +25,16 @@ import com.nexmo.client.TestUtils; import com.nexmo.client.auth.AuthCollection; import com.nexmo.client.auth.TokenAuthMethod; +import com.nexmo.client.logging.LoggingUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpUriRequest; import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; import java.io.ByteArrayInputStream; @@ -39,18 +43,23 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +@RunWith(PowerMockRunner.class) +@PrepareForTest(LoggingUtils.class) public class NumbersClientTest { private TestUtils testUtils = new TestUtils(); private HttpWrapper stubHttpWrapper(int statusCode, String content) throws Exception { HttpClient client = mock(HttpClient.class); + mockStatic(LoggingUtils.class); HttpResponse response = mock(HttpResponse.class); StatusLine sl = mock(StatusLine.class); HttpEntity entity = mock(HttpEntity.class); when(client.execute(any(HttpUriRequest.class))).thenReturn(response); + when(LoggingUtils.logResponse(any(HttpResponse.class))).thenReturn("response logged"); when(entity.getContent()).thenReturn(new ByteArrayInputStream(content.getBytes("UTF-8"))); when(sl.getStatusCode()).thenReturn(statusCode); when(response.getStatusLine()).thenReturn(sl); diff --git a/src/test/java/com/nexmo/client/sms/SmsClientTest.java b/src/test/java/com/nexmo/client/sms/SmsClientTest.java index d5f5fcda4..d4f38fd88 100644 --- a/src/test/java/com/nexmo/client/sms/SmsClientTest.java +++ b/src/test/java/com/nexmo/client/sms/SmsClientTest.java @@ -25,6 +25,7 @@ import com.nexmo.client.HttpWrapper; import com.nexmo.client.NexmoResponseParseException; import com.nexmo.client.auth.TokenAuthMethod; +import com.nexmo.client.logging.LoggingUtils; import com.nexmo.client.sms.messages.Message; import com.nexmo.client.sms.messages.TextMessage; import org.apache.http.HttpEntity; @@ -35,6 +36,9 @@ import org.hamcrest.CoreMatchers; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; import javax.xml.parsers.ParserConfigurationException; import java.io.ByteArrayInputStream; @@ -45,7 +49,10 @@ import static org.junit.Assert.*; import static org.mockito.Mockito.*; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +@RunWith(PowerMockRunner.class) +@PrepareForTest(LoggingUtils.class) public class SmsClientTest { private HttpWrapper wrapper; private SmsClient client; @@ -57,6 +64,8 @@ public void setUp() throws ParserConfigurationException { } private HttpClient stubHttpClient(int statusCode, String content) throws Exception { + //Log log = mock(Log.class); + mockStatic(LoggingUtils.class); HttpClient result = mock(HttpClient.class); HttpResponse response = mock(HttpResponse.class); @@ -64,6 +73,7 @@ private HttpClient stubHttpClient(int statusCode, String content) throws Excepti HttpEntity entity = mock(HttpEntity.class); when(result.execute(any(HttpUriRequest.class))).thenReturn(response); + when(LoggingUtils.logResponse(any(HttpResponse.class))).thenReturn("response logged"); when(entity.getContent()).thenReturn(new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8))); when(sl.getStatusCode()).thenReturn(statusCode); when(response.getStatusLine()).thenReturn(sl); diff --git a/src/test/java/com/nexmo/client/sns/SnsClientTest.java b/src/test/java/com/nexmo/client/sns/SnsClientTest.java index d6c26afff..88bc9b3d9 100644 --- a/src/test/java/com/nexmo/client/sns/SnsClientTest.java +++ b/src/test/java/com/nexmo/client/sns/SnsClientTest.java @@ -25,6 +25,7 @@ import com.nexmo.client.HttpWrapper; import com.nexmo.client.NexmoResponseParseException; import com.nexmo.client.auth.TokenAuthMethod; +import com.nexmo.client.logging.LoggingUtils; import com.nexmo.client.sns.request.SnsPublishRequest; import com.nexmo.client.sns.request.SnsSubscribeRequest; import com.nexmo.client.sns.response.SnsPublishResponse; @@ -36,6 +37,9 @@ import org.apache.http.client.methods.HttpUriRequest; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; @@ -43,7 +47,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.Mockito.*; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +@RunWith(PowerMockRunner.class) +@PrepareForTest(LoggingUtils.class) public class SnsClientTest { private HttpWrapper httpWrapper; private SnsClient client; @@ -56,12 +63,14 @@ public void setUp() throws Exception { private HttpClient stubHttpClient(int statusCode, String content) throws Exception { HttpClient result = mock(HttpClient.class); + mockStatic(LoggingUtils.class); HttpResponse response = mock(HttpResponse.class); StatusLine sl = mock(StatusLine.class); HttpEntity entity = mock(HttpEntity.class); when(result.execute(any(HttpUriRequest.class))).thenReturn(response); + when(LoggingUtils.logResponse(any(HttpResponse.class))).thenReturn("response logged"); when(entity.getContent()).thenReturn(new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8))); when(sl.getStatusCode()).thenReturn(statusCode); when(response.getStatusLine()).thenReturn(sl); diff --git a/src/test/java/com/nexmo/client/voice/VoiceClientTest.java b/src/test/java/com/nexmo/client/voice/VoiceClientTest.java index d4f177ffa..3bba637dc 100644 --- a/src/test/java/com/nexmo/client/voice/VoiceClientTest.java +++ b/src/test/java/com/nexmo/client/voice/VoiceClientTest.java @@ -25,6 +25,7 @@ import com.nexmo.client.TestUtils; import com.nexmo.client.auth.AuthCollection; import com.nexmo.client.auth.JWTAuthMethod; +import com.nexmo.client.logging.LoggingUtils; import com.nexmo.client.voice.ncco.Ncco; import com.nexmo.client.voice.ncco.TalkAction; import org.apache.http.HttpEntity; @@ -33,6 +34,9 @@ import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpUriRequest; import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; @@ -41,18 +45,23 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +@RunWith(PowerMockRunner.class) +@PrepareForTest(LoggingUtils.class) public class VoiceClientTest { private TestUtils testUtils = new TestUtils(); private HttpWrapper stubHttpWrapper(int statusCode, String content) throws Exception { HttpClient client = mock(HttpClient.class); + mockStatic(LoggingUtils.class); HttpResponse response = mock(HttpResponse.class); StatusLine sl = mock(StatusLine.class); HttpEntity entity = mock(HttpEntity.class); when(client.execute(any(HttpUriRequest.class))).thenReturn(response); + when(LoggingUtils.logResponse(any(HttpResponse.class))).thenReturn("response logged"); when(entity.getContent()).thenReturn(new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8))); when(sl.getStatusCode()).thenReturn(statusCode); when(response.getStatusLine()).thenReturn(sl);