diff --git a/build.gradle b/build.gradle index f6c002a9..63952868 100644 --- a/build.gradle +++ b/build.gradle @@ -54,7 +54,11 @@ dependencies { testImplementation('com.github.tomakehurst:wiremock-jre8:2.26.3') // mockito for dependency mocking - dependencies { testImplementation "org.mockito:mockito-core:3.+" } + dependencies { + testImplementation "org.mockito:mockito-core:3.+" + testImplementation 'org.mockito:mockito-inline:2.13.0' + } + /////////////////////////////////// // Examples dependencies diff --git a/src/test/java/com/nylas/ByteChannelSource.java b/src/test/java/com/nylas/ByteChannelSource.java new file mode 100644 index 00000000..9c2f2c66 --- /dev/null +++ b/src/test/java/com/nylas/ByteChannelSource.java @@ -0,0 +1,55 @@ +package com.nylas; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ReadableByteChannel; +import okio.Buffer; +import okio.Source; +import okio.Timeout; + +/** + * Creates a Source around a ReadableByteChannel and efficiently reads data using an UnsafeCursor. + * + *
This is a basic example showing another use for the UnsafeCursor. Using the
+ * {@link ByteBuffer#wrap(byte[], int, int) ByteBuffer.wrap()} along with access to Buffer segments,
+ * a ReadableByteChannel can be given direct access to Buffer data without having to copy the data.
+ */
+final class ByteChannelSource implements Source {
+ private final ReadableByteChannel channel;
+ private final Timeout timeout;
+
+ private final Buffer.UnsafeCursor cursor = new Buffer.UnsafeCursor();
+
+ ByteChannelSource(ReadableByteChannel channel, Timeout timeout) {
+ this.channel = channel;
+ this.timeout = timeout;
+ }
+
+ @Override public long read(Buffer sink, long byteCount) throws IOException {
+ if (!channel.isOpen()) throw new IllegalStateException("closed");
+
+ try (Buffer.UnsafeCursor ignored = sink.readAndWriteUnsafe(cursor)) {
+ timeout.throwIfReached();
+ long oldSize = sink.size();
+ int length = (int) Math.min(8192, byteCount);
+
+ cursor.expandBuffer(length);
+ int read = channel.read(ByteBuffer.wrap(cursor.data, cursor.start, length));
+ if (read == -1) {
+ cursor.resizeBuffer(oldSize);
+ return -1;
+ } else {
+ cursor.resizeBuffer(oldSize + read);
+ return read;
+ }
+ }
+ }
+
+ @Override public Timeout timeout() {
+ return timeout;
+ }
+
+ @Override public void close() throws IOException {
+ channel.close();
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/nylas/NylasClientTest.java b/src/test/java/com/nylas/NylasClientTest.java
new file mode 100644
index 00000000..0ad63435
--- /dev/null
+++ b/src/test/java/com/nylas/NylasClientTest.java
@@ -0,0 +1,536 @@
+package com.nylas;
+
+import okhttp3.*;
+import okio.Buffer;
+import okio.BufferedSource;
+import okio.Okio;
+import okio.Timeout;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentMatchers;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.nio.channels.ReadableByteChannel;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import static com.nylas.AccessTokenTest.TEST_ACCESS_TOKEN;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+
+public class NylasClientTest {
+ private NylasClient nylasClient;
+
+ private MockNylas mockNylas;
+
+ public static String TEST_CLIENT_ID = "kmsdv7809834n98fdvc";
+ public static String TEST_CLIENT_SECRET = "kjlsdvnis8yv923nfo89";
+
+ @BeforeEach
+ private void init() {
+ mockNylas = new MockNylas();
+ }
+
+ @AfterEach
+ private void cleanup() {
+ mockNylas.cleanup();
+ }
+
+ @Test
+ public void testNylasClientDefaultConstructor() {
+ nylasClient = new NylasClient();
+ assertNotNull(nylasClient);
+ }
+
+ @Test
+ public void testNylasClientConstructor_customHttpBuilder() {
+ OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder()
+ .connectTimeout(60, TimeUnit.SECONDS)
+ .readTimeout(60, TimeUnit.SECONDS)
+ .writeTimeout(60, TimeUnit.SECONDS)
+ .protocols(Arrays.asList(Protocol.HTTP_1_1))
+ .addNetworkInterceptor(new HttpLoggingInterceptor());
+
+ nylasClient = new NylasClient(httpClientBuilder);
+
+ assertNotNull(nylasClient);
+ }
+
+ @Test
+ public void testGetsNewUriBuilder() {
+ nylasClient = new NylasClient();
+
+ HttpUrl.Builder builder = nylasClient.newUrlBuilder();
+
+ assertNotNull(builder);
+ }
+
+ @Test
+ public void testGetHttpClient() {
+ nylasClient = new NylasClient();
+
+ OkHttpClient client = nylasClient.getHttpClient();
+
+ assertNotNull(client.interceptors());
+ assertNotNull(client);
+ }
+
+ @Test
+ public void testRetrieveApplication() {
+ nylasClient = new NylasClient();
+
+ NylasApplication application = nylasClient.application(TEST_CLIENT_ID, TEST_CLIENT_SECRET);
+
+ assertNotNull(application);
+ }
+
+ @Test
+ public void testRetrieveNylasAccount() {
+ nylasClient = new NylasClient();
+
+ NylasAccount account = nylasClient.account(TEST_ACCESS_TOKEN);
+
+ assertNotNull(account);
+ }
+
+ @Test
+ public void testExecuteGet() throws RequestFailedException, IOException, NoSuchFieldException, IllegalAccessException {
+ // mockery
+ okhttp3.HttpUrl.Builder url = mock(okhttp3.HttpUrl.Builder.class);
+ OkHttpClient mockClient = mock(OkHttpClient.class);
+ okhttp3.Response mockResponse = mock(okhttp3.Response.class);
+ ResponseBody mockResponseBody = mock(ResponseBody.class);
+ Call mockCall = mock(Call.class);
+
+ nylasClient = new NylasClient();
+
+ Field clientField = nylasClient.getClass().getDeclaredField("httpClient");
+ clientField.setAccessible(true);
+ clientField.set(nylasClient, mockClient);
+
+ when(url.build()).thenReturn(new HttpUrl.Builder()
+ .scheme("https")
+ .addPathSegment("test")
+ .addPathSegment("response")
+ .host("api.nylas.com")
+ .build());
+
+ ReadableByteChannel channel = new Buffer().writeUtf8("{\"status\": \"ok\"}");
+ BufferedSource source = Okio.buffer(new ByteChannelSource(channel, Timeout.NONE));
+
+ when(mockClient.newCall(ArgumentMatchers.any())).thenReturn(mockCall);
+ when(mockCall.execute()).thenReturn(mockResponse);
+ when(mockResponse.isSuccessful()).thenReturn(true);
+ when(mockResponse.body()).thenReturn(mockResponseBody);
+ when(mockResponseBody.source()).thenReturn(source);
+
+ TestClientResponse response = nylasClient.executeGet("jhonny", url, TestClientResponse.class, NylasClient.AuthMethod.BASIC);
+ assertEquals(response.getStatus(), "ok");
+ }
+
+ @Test
+ public void testExecuteGet_noAuthMethod() throws RequestFailedException, IOException, NoSuchFieldException, IllegalAccessException {
+ // mockery
+ okhttp3.HttpUrl.Builder url = mock(okhttp3.HttpUrl.Builder.class);
+ OkHttpClient mockClient = mock(OkHttpClient.class);
+ okhttp3.Response mockResponse = mock(okhttp3.Response.class);
+ ResponseBody mockResponseBody = mock(ResponseBody.class);
+ Call mockCall = mock(Call.class);
+
+ nylasClient = new NylasClient();
+
+ Field clientField = nylasClient.getClass().getDeclaredField("httpClient");
+ clientField.setAccessible(true);
+ clientField.set(nylasClient, mockClient);
+
+ when(url.build()).thenReturn(new HttpUrl.Builder()
+ .scheme("https")
+ .addPathSegment("test")
+ .addPathSegment("response")
+ .host("api.nylas.com")
+ .build());
+
+ ReadableByteChannel channel = new Buffer().writeUtf8("{\"status\": \"ok\"}");
+ BufferedSource source = Okio.buffer(new ByteChannelSource(channel, Timeout.NONE));
+
+ when(mockClient.newCall(ArgumentMatchers.any())).thenReturn(mockCall);
+ when(mockCall.execute()).thenReturn(mockResponse);
+ when(mockResponse.isSuccessful()).thenReturn(true);
+ when(mockResponse.body()).thenReturn(mockResponseBody);
+ when(mockResponseBody.source()).thenReturn(source);
+
+ TestClientResponse response = nylasClient.executeGet("jhonny", url, TestClientResponse.class);
+ assertEquals(response.getStatus(), "ok");
+ }
+
+ @Test
+ public void testExecuteGet_noAuthMethod_fails() throws RequestFailedException, IOException, NoSuchFieldException, IllegalAccessException {
+ // mockery
+ okhttp3.HttpUrl.Builder url = mock(okhttp3.HttpUrl.Builder.class);
+ OkHttpClient mockClient = mock(OkHttpClient.class);
+ okhttp3.Response mockResponse = mock(okhttp3.Response.class);
+ ResponseBody mockResponseBody = mock(ResponseBody.class);
+ Call mockCall = mock(Call.class);
+
+ nylasClient = new NylasClient();
+
+ Field clientField = nylasClient.getClass().getDeclaredField("httpClient");
+ clientField.setAccessible(true);
+ clientField.set(nylasClient, mockClient);
+
+ when(url.build()).thenReturn(new HttpUrl.Builder()
+ .scheme("https")
+ .addPathSegment("test")
+ .addPathSegment("response")
+ .host("api.nylas.com")
+ .build());
+
+ ReadableByteChannel channel = new Buffer().writeUtf8("{\"status\": \"ok\"}");
+ BufferedSource source = Okio.buffer(new ByteChannelSource(channel, Timeout.NONE));
+
+ when(mockClient.newCall(ArgumentMatchers.any())).thenReturn(mockCall);
+ when(mockCall.execute()).thenReturn(mockResponse);
+ when(mockResponse.isSuccessful()).thenReturn(false);
+ when(mockResponse.body()).thenReturn(mockResponseBody);
+ when(mockResponseBody.string()).thenReturn("error");
+ when(mockResponse.code()).thenReturn(400);
+
+ Exception exception = assertThrows(RequestFailedException.class, () -> {
+ nylasClient.executeGet("jhonny", url, TestClientResponse.class);
+ });
+
+ assertEquals(exception.getMessage(), "statusCode=400, type=null, message=null");
+ }
+
+ @Test
+ public void testExecutePut() throws RequestFailedException, IOException, NoSuchFieldException, IllegalAccessException {
+ // mockery
+ okhttp3.HttpUrl.Builder url = mock(okhttp3.HttpUrl.Builder.class);
+ OkHttpClient mockClient = mock(OkHttpClient.class);
+ okhttp3.Response mockResponse = mock(okhttp3.Response.class);
+ ResponseBody mockResponseBody = mock(ResponseBody.class);
+ Call mockCall = mock(Call.class);
+
+ nylasClient = new NylasClient();
+
+ Field clientField = nylasClient.getClass().getDeclaredField("httpClient");
+ clientField.setAccessible(true);
+ clientField.set(nylasClient, mockClient);
+
+ when(url.build()).thenReturn(new HttpUrl.Builder()
+ .scheme("https")
+ .addPathSegment("test")
+ .addPathSegment("response")
+ .host("api.nylas.com")
+ .build());
+
+ ReadableByteChannel channel = new Buffer().writeUtf8("{\"status\": \"ok\"}");
+ BufferedSource source = Okio.buffer(new ByteChannelSource(channel, Timeout.NONE));
+
+ when(mockClient.newCall(ArgumentMatchers.any())).thenReturn(mockCall);
+ when(mockCall.execute()).thenReturn(mockResponse);
+ when(mockResponse.isSuccessful()).thenReturn(true);
+ when(mockResponse.body()).thenReturn(mockResponseBody);
+ when(mockResponseBody.source()).thenReturn(source);
+
+ Map