From 79a183a4922277414bba3b295f2c531a501ab5fd Mon Sep 17 00:00:00 2001 From: Aaron de Mello Date: Wed, 30 Jul 2025 10:47:25 -0400 Subject: [PATCH 1/3] Upgraded OkHttp dependency from 3.14.5 to 4.12.0 --- CHANGELOG.md | 5 ++ build.gradle.kts | 4 +- .../com/nylas/examples/OkHttpUpgradeTest.java | 82 +++++++++++++++++ src/main/kotlin/com/nylas/NylasClient.kt | 29 +++--- .../interceptors/ContentHeadersInterceptor.kt | 8 +- .../interceptors/HttpLoggingInterceptor.kt | 28 +++--- src/main/kotlin/com/nylas/util/FileUtils.kt | 3 +- src/main/kotlin/com/nylas/util/JsonHelper.kt | 3 +- src/test/kotlin/com/nylas/NylasClientTest.kt | 90 ++++++++++--------- .../com/nylas/resources/ApplicationsTests.kt | 5 +- .../com/nylas/resources/AttachmentsTests.kt | 5 +- .../kotlin/com/nylas/resources/AuthTests.kt | 9 +- .../com/nylas/resources/BookingsTest.kt | 4 +- .../com/nylas/resources/CalendarsTest.kt | 4 +- .../com/nylas/resources/ConfigurationsTest.kt | 4 +- .../com/nylas/resources/ConnectorsTests.kt | 5 +- .../com/nylas/resources/ContactsTests.kt | 4 +- .../com/nylas/resources/CredentialsTests.kt | 5 +- .../kotlin/com/nylas/resources/DraftsTests.kt | 16 ++-- .../kotlin/com/nylas/resources/EventsTests.kt | 4 +- .../com/nylas/resources/FoldersTests.kt | 4 +- .../kotlin/com/nylas/resources/GrantsTests.kt | 5 +- .../com/nylas/resources/MessagesTests.kt | 10 +-- .../com/nylas/resources/NotetakersTests.kt | 4 +- .../com/nylas/resources/RedirectUriTests.kt | 5 +- .../com/nylas/resources/SessionsTest.kt | 4 +- .../com/nylas/resources/SmartComposeTests.kt | 5 +- .../com/nylas/resources/ThreadsTests.kt | 4 +- .../com/nylas/resources/WebhooksTests.kt | 5 +- 29 files changed, 234 insertions(+), 129 deletions(-) create mode 100644 examples/src/main/java/com/nylas/examples/OkHttpUpgradeTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a2eb4d2..707ed532 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Nylas Java SDK Changelog +## [Unreleased] + +### Changed +* Upgraded OkHttp dependency from 3.14.5 to 4.12.0 + ## [2.11.1] - Release 2025-07-11 ### Added diff --git a/build.gradle.kts b/build.gradle.kts index 055ff953..c44fed2d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -29,8 +29,8 @@ dependencies { // //////////////////////////////// // Public dependencies - // OkHttp 3 - Http client (without Kotlin dependency of version 4) - api("com.squareup.okhttp3:okhttp:3.14.5") + // OkHttp 4 - Http client + api("com.squareup.okhttp3:okhttp:4.12.0") // Moshi JSON library implementation("com.squareup.moshi:moshi:1.15.0") diff --git a/examples/src/main/java/com/nylas/examples/OkHttpUpgradeTest.java b/examples/src/main/java/com/nylas/examples/OkHttpUpgradeTest.java new file mode 100644 index 00000000..bf8aa919 --- /dev/null +++ b/examples/src/main/java/com/nylas/examples/OkHttpUpgradeTest.java @@ -0,0 +1,82 @@ +package com.nylas.examples; + +import com.nylas.NylasClient; +import okhttp3.OkHttpClient; +import okhttp3.Protocol; + +import java.util.concurrent.TimeUnit; + +/** + * Simple test to verify OkHttp 4 upgrade works correctly + */ +public class OkHttpUpgradeTest { + public static void main(String[] args) { + try { + System.out.println("๐Ÿ”ง Testing OkHttp 4 upgrade with Nylas Java SDK...\n"); + + // Test 1: Basic NylasClient creation with default OkHttpClient + System.out.println("1. Testing basic NylasClient creation:"); + NylasClient basicClient = new NylasClient("test-api-key", new OkHttpClient.Builder(), "https://api.us.nylas.com"); + System.out.println(" โœ… Basic NylasClient created successfully"); + System.out.println(" API Key: " + basicClient.getApiKey()); + + // Test 2: NylasClient with custom OkHttpClient.Builder + System.out.println("\n2. Testing NylasClient with custom OkHttpClient:"); + OkHttpClient.Builder customBuilder = new OkHttpClient.Builder() + .connectTimeout(30, TimeUnit.SECONDS) + .readTimeout(60, TimeUnit.SECONDS) + .writeTimeout(45, TimeUnit.SECONDS) + .protocols(java.util.Arrays.asList(Protocol.HTTP_1_1)); + + NylasClient customClient = new NylasClient("test-api-key", customBuilder, "https://api.us.nylas.com"); + System.out.println(" โœ… Custom NylasClient created successfully"); + + // Test 3: NylasClient.Builder pattern + System.out.println("\n3. Testing NylasClient.Builder pattern:"); + NylasClient builderClient = new NylasClient.Builder("test-api-key") + .apiUri("https://api.us.nylas.com") + .httpClient(new OkHttpClient.Builder().callTimeout(120, TimeUnit.SECONDS)) + .build(); + System.out.println(" โœ… Builder pattern NylasClient created successfully"); + + // Test 4: Basic client functionality (tests OkHttp integration) + System.out.println("\n4. Testing basic client functionality:"); + try { + // Test that the client is properly initialized + System.out.println(" โœ… Client initialization successful"); + System.out.println(" โœ… Basic client methods accessible"); + } catch (Exception e) { + System.out.println(" โŒ Client functionality test failed: " + e.getMessage()); + throw e; + } + + // Test 5: OkHttp version information + System.out.println("\n5. OkHttp version information:"); + try { + // Try to get OkHttp version through reflection or manifest + Package okHttpPackage = OkHttpClient.class.getPackage(); + String version = okHttpPackage.getImplementationVersion(); + if (version != null) { + System.out.println(" OkHttp Version: " + version); + if (version.startsWith("4.")) { + System.out.println(" โœ… Successfully upgraded to OkHttp 4.x"); + } else { + System.out.println(" โš ๏ธ Unexpected version: " + version); + } + } else { + System.out.println(" โ„น๏ธ Version information not available"); + } + } catch (Exception e) { + System.out.println(" โ„น๏ธ Could not determine OkHttp version: " + e.getMessage()); + } + + System.out.println("\n๐ŸŽ‰ All OkHttp upgrade tests passed successfully!"); + System.out.println(" The Nylas Java SDK is compatible with OkHttp 4.x"); + + } catch (Exception e) { + System.out.println("\nโŒ OkHttp upgrade test failed: " + e.getMessage()); + e.printStackTrace(); + System.exit(1); + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/nylas/NylasClient.kt b/src/main/kotlin/com/nylas/NylasClient.kt index 786ffa4a..6a97af96 100644 --- a/src/main/kotlin/com/nylas/NylasClient.kt +++ b/src/main/kotlin/com/nylas/NylasClient.kt @@ -8,6 +8,7 @@ import com.nylas.resources.* import com.nylas.util.JsonHelper import com.squareup.moshi.JsonDataException import okhttp3.* +import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.Response import java.io.IOException import java.lang.Exception @@ -66,7 +67,7 @@ open class NylasClient( } init { - this.apiUri = HttpUrl.get(apiUri) + this.apiUri = apiUri.toHttpUrl() httpClient = httpClientBuilder .addInterceptor(AddVersionHeadersInterceptor()) // enforce user agent and build data .addInterceptor(ContentHeadersInterceptor()) // enforce Content-Type headers. @@ -375,9 +376,9 @@ open class NylasClient( val response = httpClient.newCall(request).execute() throwAndCloseOnFailedRequest(finalUrl, response) - return response.body() ?: throw Exception("Unexpected null response body") + return response.body ?: throw Exception("Unexpected null response body") } catch (e: SocketTimeoutException) { - throw NylasSdkTimeoutError(finalUrl.toString(), httpClient.callTimeoutMillis()) + throw NylasSdkTimeoutError(finalUrl.toString(), httpClient.callTimeoutMillis) } catch (e: SocketException) { throw NylasSdkRemoteClosedError(finalUrl.toString(), e.message ?: "Unknown error") } catch (e: AbstractNylasApiError) { @@ -397,11 +398,11 @@ open class NylasClient( return } - val responseBody = response.body()!!.string() + val responseBody = response.body!!.string() val parsedError: AbstractNylasApiError? response.close() - if (url.encodedPath().equals("/v3/connect/token") || url.encodedPath().equals("/v3/connect/revoke")) { + if (url.encodedPath.equals("/v3/connect/token") || url.encodedPath.equals("/v3/connect/revoke")) { try { parsedError = JsonHelper.moshi().adapter(NylasOAuthError::class.java) .fromJson(responseBody) @@ -413,8 +414,8 @@ open class NylasClient( errorDescription = "Unknown error received from the API: $responseBody", errorUri = "unknown", errorCode = "0", - statusCode = response.code(), - headers = response.headers().toMultimap(), + statusCode = response.code, + headers = response.headers.toMultimap(), ) } @@ -435,8 +436,8 @@ open class NylasClient( throw NylasApiError( type = "unknown", message = "Unknown error received from the API: $responseBody", - statusCode = response.code(), - headers = response.headers().toMultimap(), + statusCode = response.code, + headers = response.headers.toMultimap(), ) } else -> throw ex @@ -445,23 +446,23 @@ open class NylasClient( } if (parsedError != null) { - parsedError.statusCode = response.code() - parsedError.headers = response.headers().toMultimap() + parsedError.statusCode = response.code + parsedError.headers = response.headers.toMultimap() throw parsedError } throw NylasApiError( type = "unknown", message = "Unknown error received from the API: $responseBody", - statusCode = response.code(), - headers = response.headers().toMultimap(), + statusCode = response.code, + headers = response.headers.toMultimap(), ) } private fun buildUrl(path: String, queryParams: IQueryParams?, overrides: RequestOverrides?): HttpUrl.Builder { // Sets the API URI if it is provided in the overrides. var url = if (overrides?.apiUri != null) { - HttpUrl.get(overrides.apiUri).newBuilder().addPathSegments(path) + overrides.apiUri.toHttpUrl().newBuilder().addPathSegments(path) } else { newUrlBuilder().addPathSegments(path) } diff --git a/src/main/kotlin/com/nylas/interceptors/ContentHeadersInterceptor.kt b/src/main/kotlin/com/nylas/interceptors/ContentHeadersInterceptor.kt index fc12ded8..4b0087b4 100644 --- a/src/main/kotlin/com/nylas/interceptors/ContentHeadersInterceptor.kt +++ b/src/main/kotlin/com/nylas/interceptors/ContentHeadersInterceptor.kt @@ -12,16 +12,16 @@ class ContentHeadersInterceptor : Interceptor { @Throws(IOException::class) override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request() - val path = request.url().encodedPath() + val path = request.url.encodedPath val contentHeader = request.header(NylasClient.HttpHeaders.CONTENT_TYPE.headerName) if (contentHeader == null && !isDownloadablePath(path)) { val enhancedRequest = request.newBuilder() - if (request.body() != null && request.body()!!.contentType() != null) { + if (request.body != null && request.body!!.contentType() != null) { enhancedRequest.header( NylasClient.HttpHeaders.CONTENT_TYPE.headerName, - request.body()!!.contentType()!!.toString(), + request.body!!.contentType()!!.toString(), ) - } else if (request.body() != null) { + } else if (request.body != null) { enhancedRequest.header( NylasClient.HttpHeaders.CONTENT_TYPE.headerName, NylasClient.MediaType.APPLICATION_JSON.mediaType, diff --git a/src/main/kotlin/com/nylas/interceptors/HttpLoggingInterceptor.kt b/src/main/kotlin/com/nylas/interceptors/HttpLoggingInterceptor.kt index 91ae0432..71708b87 100644 --- a/src/main/kotlin/com/nylas/interceptors/HttpLoggingInterceptor.kt +++ b/src/main/kotlin/com/nylas/interceptors/HttpLoggingInterceptor.kt @@ -42,18 +42,18 @@ class HttpLoggingInterceptor : Interceptor { @Throws(IOException::class) private fun logRequest(request: Request) { - val requestBody = request.body() + val requestBody = request.body val hasBody = requestBody != null // Summary if (requestLogs.isDebugEnabled) { requestLogs.debug( - "=> " + request.method() + - " " + request.url() + + "=> " + request.method + + " " + request.url + " reqBodySize=" + if (hasBody) requestBody!!.contentLength() else 0, ) } - logHeaders("=>", request.headers()) + logHeaders("=>", request.headers) if (bodyLogs.isDebugEnabled) { val message = if (!hasBody) { " No request body" @@ -77,27 +77,27 @@ class HttpLoggingInterceptor : Interceptor { // Summary if (requestLogs.isDebugEnabled) { requestLogs.debug( - "<= " + response!!.code() + - " " + response.message() + + "<= " + response!!.code + + " " + response.message + " resBodySize=" + contentLength + " durationMs=" + durationMillis, ) } - logHeaders("<=", response!!.headers()) + logHeaders("<=", response!!.headers) if (bodyLogs.isDebugEnabled) { val message: String if (contentLength == -1L) { message = " No response body" } else { - val contentType = response.body()!!.contentType() + val contentType = response.body!!.contentType() if (!isPrintableMediaType(contentType)) { message = " Skipped logging response body of type that may not be printable: $contentType" } else { - val source = response.body()!!.source() + val source = response.body!!.source() source.request(Long.MAX_VALUE) // if zipped, may need to buffer all of it var buf = source.buffer.clone() var gzippedMessage = "" - if ("gzip".equals(response.headers()["Content-Encoding"], ignoreCase = true)) { + if ("gzip".equals(response.headers["Content-Encoding"], ignoreCase = true)) { val gzippedSize = buf.size GzipSource(buf).use { gzippedResponseBody -> buf = Buffer() @@ -115,7 +115,7 @@ class HttpLoggingInterceptor : Interceptor { private fun logHeaders(direction: String, headers: Headers) { if (headersLogs.isDebugEnabled) { val headersLog = StringBuilder().append(direction).append("\n") - for (i in 0 until headers.size()) { + for (i in 0 until headers.size) { val name = headers.name(i) var value = headers.value(i) if (!isLogAuthHeader && "Authorization" == name) { @@ -131,7 +131,7 @@ class HttpLoggingInterceptor : Interceptor { private fun isPrintableMediaType(type: MediaType?): Boolean { return ( type != null && - ("text" == type.type() || type.toString().startsWith("application/json")) + ("text" == type.type || type.toString().startsWith("application/json")) ) } @@ -155,10 +155,10 @@ class HttpLoggingInterceptor : Interceptor { } private fun getContentLength(response: Response?): Long { - return if (response!!.body() == null) { + return if (response!!.body == null) { -1 } else { - response.body()!!.contentLength() + response.body!!.contentLength() } } diff --git a/src/main/kotlin/com/nylas/util/FileUtils.kt b/src/main/kotlin/com/nylas/util/FileUtils.kt index d59f06f1..c6606c75 100644 --- a/src/main/kotlin/com/nylas/util/FileUtils.kt +++ b/src/main/kotlin/com/nylas/util/FileUtils.kt @@ -3,6 +3,7 @@ package com.nylas.util import com.nylas.models.CreateAttachmentRequest import com.nylas.models.IMessageAttachmentRequest import okhttp3.MediaType +import okhttp3.MediaType.Companion.toMediaType import okhttp3.MultipartBody import okhttp3.RequestBody import okio.BufferedSink @@ -85,7 +86,7 @@ class FileUtils { // Add a separate form field for each attachment requestBody.attachments?.forEachIndexed { index, attachment -> - val contentType = MediaType.parse(attachment.contentType) + val contentType = attachment.contentType.toMediaType() val contentBody = attachment.content.toStreamingRequestBody(contentType) multipartBuilder.addFormDataPart("file$index", attachment.filename, contentBody) } diff --git a/src/main/kotlin/com/nylas/util/JsonHelper.kt b/src/main/kotlin/com/nylas/util/JsonHelper.kt index cf49c358..baa79ca2 100644 --- a/src/main/kotlin/com/nylas/util/JsonHelper.kt +++ b/src/main/kotlin/com/nylas/util/JsonHelper.kt @@ -12,6 +12,7 @@ import com.squareup.moshi.Types import com.squareup.moshi.adapters.Rfc3339DateJsonAdapter import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import okhttp3.MediaType +import okhttp3.MediaType.Companion.toMediaType import okhttp3.RequestBody import java.io.IOException import java.lang.reflect.Type @@ -200,7 +201,7 @@ class JsonHelper { return json } - private val jsonType = MediaType.parse("application/json") + private val jsonType = "application/json".toMediaType() /** * Get the JSON media type. diff --git a/src/test/kotlin/com/nylas/NylasClientTest.kt b/src/test/kotlin/com/nylas/NylasClientTest.kt index d85b358e..73c8439c 100644 --- a/src/test/kotlin/com/nylas/NylasClientTest.kt +++ b/src/test/kotlin/com/nylas/NylasClientTest.kt @@ -9,12 +9,11 @@ import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test -import org.mockito.ArgumentCaptor -import org.mockito.Captor import org.mockito.Mockito.mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.whenever import java.net.SocketException import java.net.SocketTimeoutException @@ -61,7 +60,7 @@ class NylasClientTest { fun `builder sets correct httpClient`() { val mockOkHttpClientBuilder: OkHttpClient.Builder = mock() val mockOkHttpClient: OkHttpClient = mock() - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockOkHttpClient) val client = NylasClient.Builder("testApiKey") @@ -90,7 +89,7 @@ class NylasClientTest { fun `initializing the NylasClient with values sets them correctly`() { val mockOkHttpClientBuilder: OkHttpClient.Builder = mock() val mockOkHttpClient: OkHttpClient = mock() - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockOkHttpClient) val client = NylasClient(apiKey = "testApiKey", httpClientBuilder = mockOkHttpClientBuilder, apiUri = "https://custom-api.nylas.com/") @@ -185,20 +184,17 @@ class NylasClientTest { private val mockHeaderResponse: Headers = mock(Headers::class.java) private val headersMultiMap = mapOf("header1" to listOf("value1"), "header2" to listOf("value2")) - @Captor - private lateinit var requestCaptor: ArgumentCaptor - @BeforeEach fun setup() { MockitoAnnotations.openMocks(this) val mockOkHttpClientBuilder: OkHttpClient.Builder = mock() - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) - whenever(mockResponse.headers()).thenReturn(mockHeaderResponse) + whenever(mockResponse.body).thenReturn(mockResponseBody) + whenever(mockResponse.headers).thenReturn(mockHeaderResponse) whenever(mockHeaderResponse.toMultimap()).thenReturn(headersMultiMap) nylasClient = NylasClient("testApiKey", mockOkHttpClientBuilder) } @@ -209,12 +205,14 @@ class NylasClientTest { whenever(mockResponseBody.source()).thenReturn(Buffer().writeUtf8("{ \"foo\": \"bar\" }")) val result = nylasClient.executeRequest>(urlBuilder, NylasClient.HttpMethod.GET, null, JsonHelper.mapTypeOf(String::class.java, String::class.java)) + + val requestCaptor = argumentCaptor() verify(mockHttpClient).newCall(requestCaptor.capture()) - val capturedRequest = requestCaptor.value + val capturedRequest = requestCaptor.firstValue assertEquals("bar", result["foo"]) - assertEquals(capturedRequest.url().toString(), "https://api.us.nylas.com/") - assertEquals(capturedRequest.method(), "GET") + assertEquals(capturedRequest.url.toString(), "https://api.us.nylas.com/") + assertEquals(capturedRequest.method, "GET") } @Test @@ -223,7 +221,7 @@ class NylasClientTest { val revokeUrlBuilder = nylasClient.newUrlBuilder().addPathSegments("v3/connect/revoke") val oauthUrls = listOf(tokenUrlBuilder, revokeUrlBuilder) whenever(mockResponse.isSuccessful).thenReturn(false) - whenever(mockResponse.code()).thenReturn(401) + whenever(mockResponse.code).thenReturn(401) whenever(mockResponseBody.string()).thenReturn("{ \"error\": \"internal_error\", \"error_code\": 500, \"error_description\": \"Internal error, contact administrator\", \"error_uri\": \"https://accounts.nylas.io/#tag/Event-Codes\", \"request_id\": \"eccc9c3f-7150-48e1-965e-4f89714ab51a\" }") for (urlBuilder in oauthUrls) { @@ -247,7 +245,7 @@ class NylasClientTest { val revokeUrlBuilder = nylasClient.newUrlBuilder().addPathSegments("v3/connect/revoke") val oauthUrls = listOf(tokenUrlBuilder, revokeUrlBuilder) whenever(mockResponse.isSuccessful).thenReturn(false) - whenever(mockResponse.code()).thenReturn(500) + whenever(mockResponse.code).thenReturn(500) whenever(mockResponseBody.string()).thenReturn("not a json") for (urlBuilder in oauthUrls) { @@ -268,7 +266,7 @@ class NylasClientTest { fun `should throw NylasApiError on error from non-oauth endpoints`() { val urlBuilder = nylasClient.newUrlBuilder().addPathSegments("v3/some/other/path") whenever(mockResponse.isSuccessful).thenReturn(false) - whenever(mockResponse.code()).thenReturn(400) + whenever(mockResponse.code).thenReturn(400) whenever(mockResponseBody.string()).thenReturn("{ \"request_id\": \"4c2740b4-52a4-412e-bdee-49a6c6671b22\", \"error\": { \"type\": \"provider_error\", \"message\": \"Unauthorized\", \"provider_error\": { \"error\": \"Request had invalid authentication credentials.\" } } }") val exception = assertFailsWith { @@ -287,7 +285,7 @@ class NylasClientTest { fun `should throw NylasApiError on error from non-oauth endpoints even if unexpected response from API`() { val urlBuilder = nylasClient.newUrlBuilder().addPathSegments("v3/some/other/path") whenever(mockResponse.isSuccessful).thenReturn(false) - whenever(mockResponse.code()).thenReturn(400) + whenever(mockResponse.code).thenReturn(400) whenever(mockResponseBody.string()).thenReturn("not a json") val exception = assertFailsWith { @@ -327,7 +325,7 @@ class NylasClientTest { @Test fun `should handle unexpected null response body`() { val urlBuilder = nylasClient.newUrlBuilder() - whenever(mockResponse.body()).thenReturn(null) + whenever(mockResponse.body).thenReturn(null) val exception = assertFailsWith { nylasClient.executeRequest(urlBuilder, NylasClient.HttpMethod.GET, null, String::class.java) @@ -353,12 +351,14 @@ class NylasClientTest { @Test fun `should handle download request`() { val result = nylasClient.downloadResponse("test/path") + + val requestCaptor = argumentCaptor() verify(mockHttpClient).newCall(requestCaptor.capture()) - val capturedRequest = requestCaptor.value + val capturedRequest = requestCaptor.firstValue assertEquals(mockResponseBody, result) - assertEquals(capturedRequest.url().toString(), "https://api.us.nylas.com/test/path") - assertEquals(capturedRequest.method(), "GET") + assertEquals(capturedRequest.url.toString(), "https://api.us.nylas.com/test/path") + assertEquals(capturedRequest.method, "GET") } @Test @@ -375,10 +375,11 @@ class NylasClientTest { JsonHelper.mapTypeOf(String::class.java, String::class.java), ) + val requestCaptor = argumentCaptor() verify(mockHttpClient).newCall(requestCaptor.capture()) - val capturedRequest = requestCaptor.value - assertEquals(capturedRequest.url().toString(), "https://api.us.nylas.com/test/path") - assertEquals(capturedRequest.method(), "POST") + val capturedRequest = requestCaptor.firstValue + assertEquals(capturedRequest.url.toString(), "https://api.us.nylas.com/test/path") + assertEquals(capturedRequest.method, "POST") } @Test @@ -398,11 +399,12 @@ class NylasClientTest { mockQueryParams, ) + val requestCaptor = argumentCaptor() verify(mockHttpClient).newCall(requestCaptor.capture()) - val capturedRequest = requestCaptor.value + val capturedRequest = requestCaptor.firstValue - assertEquals(capturedRequest.url().toString(), "https://api.us.nylas.com/test/path?foo=bar&list=a&list=b&list=c&map=key1%3Avalue1&map=key2%3Avalue2") - assertEquals(capturedRequest.method(), "GET") + assertEquals(capturedRequest.url.toString(), "https://api.us.nylas.com/test/path?foo=bar&list=a&list=b&list=c&map=key1%3Avalue1&map=key2%3Avalue2") + assertEquals(capturedRequest.method, "GET") } @Test @@ -412,12 +414,13 @@ class NylasClientTest { whenever(mockResponseBody.source()).thenReturn(Buffer().writeUtf8("{ \"foo\": \"bar\" }")) nylasClient.executePut>("test/path", type, putBody) + val requestCaptor = argumentCaptor() verify(mockHttpClient).newCall(requestCaptor.capture()) - val capturedRequest = requestCaptor.value - val requestBodyBuffer = capturedRequest.body().asString() + val capturedRequest = requestCaptor.firstValue + val requestBodyBuffer = capturedRequest.body.asString() - assertEquals(capturedRequest.url().toString(), "https://api.us.nylas.com/test/path") - assertEquals(capturedRequest.method(), "PUT") + assertEquals(capturedRequest.url.toString(), "https://api.us.nylas.com/test/path") + assertEquals(capturedRequest.method, "PUT") assertEquals(requestBodyBuffer, putBody) } @@ -428,12 +431,13 @@ class NylasClientTest { whenever(mockResponseBody.source()).thenReturn(Buffer().writeUtf8("{ \"foo\": \"bar\" }")) nylasClient.executePatch>("test/path", type, patchBody) + val requestCaptor = argumentCaptor() verify(mockHttpClient).newCall(requestCaptor.capture()) - val capturedRequest = requestCaptor.value - val requestBodyBuffer = capturedRequest.body().asString() + val capturedRequest = requestCaptor.firstValue + val requestBodyBuffer = capturedRequest.body.asString() - assertEquals(capturedRequest.url().toString(), "https://api.us.nylas.com/test/path") - assertEquals(capturedRequest.method(), "PATCH") + assertEquals(capturedRequest.url.toString(), "https://api.us.nylas.com/test/path") + assertEquals(capturedRequest.method, "PATCH") assertEquals(requestBodyBuffer, patchBody) } @@ -444,12 +448,13 @@ class NylasClientTest { whenever(mockResponseBody.source()).thenReturn(Buffer().writeUtf8("{ \"foo\": \"bar\" }")) nylasClient.executePost>("test/path", type, postBody) + val requestCaptor = argumentCaptor() verify(mockHttpClient).newCall(requestCaptor.capture()) - val capturedRequest = requestCaptor.value - val requestBodyBuffer = capturedRequest.body().asString() + val capturedRequest = requestCaptor.firstValue + val requestBodyBuffer = capturedRequest.body.asString() - assertEquals(capturedRequest.url().toString(), "https://api.us.nylas.com/test/path") - assertEquals(capturedRequest.method(), "POST") + assertEquals(capturedRequest.url.toString(), "https://api.us.nylas.com/test/path") + assertEquals(capturedRequest.method, "POST") assertEquals(requestBodyBuffer, postBody) } @@ -459,11 +464,12 @@ class NylasClientTest { whenever(mockResponseBody.source()).thenReturn(Buffer().writeUtf8("{ \"foo\": \"bar\" }")) nylasClient.executeDelete>("test/path", type) + val requestCaptor = argumentCaptor() verify(mockHttpClient).newCall(requestCaptor.capture()) - val capturedRequest = requestCaptor.value + val capturedRequest = requestCaptor.firstValue - assertEquals(capturedRequest.url().toString(), "https://api.us.nylas.com/test/path") - assertEquals(capturedRequest.method(), "DELETE") + assertEquals(capturedRequest.url.toString(), "https://api.us.nylas.com/test/path") + assertEquals(capturedRequest.method, "DELETE") } /** diff --git a/src/test/kotlin/com/nylas/resources/ApplicationsTests.kt b/src/test/kotlin/com/nylas/resources/ApplicationsTests.kt index 5125af3b..3c19353f 100644 --- a/src/test/kotlin/com/nylas/resources/ApplicationsTests.kt +++ b/src/test/kotlin/com/nylas/resources/ApplicationsTests.kt @@ -5,6 +5,7 @@ import com.nylas.models.* import com.nylas.util.JsonHelper import com.squareup.moshi.Types import okhttp3.Call +import okhttp3.Interceptor import okhttp3.OkHttpClient import okhttp3.ResponseBody import okio.Buffer @@ -31,12 +32,12 @@ class ApplicationsTests { @BeforeEach fun setup() { MockitoAnnotations.openMocks(this) - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) + whenever(mockResponse.body).thenReturn(mockResponseBody) } @Nested diff --git a/src/test/kotlin/com/nylas/resources/AttachmentsTests.kt b/src/test/kotlin/com/nylas/resources/AttachmentsTests.kt index fd1cebe4..865616f5 100644 --- a/src/test/kotlin/com/nylas/resources/AttachmentsTests.kt +++ b/src/test/kotlin/com/nylas/resources/AttachmentsTests.kt @@ -5,6 +5,7 @@ import com.nylas.models.* import com.nylas.util.JsonHelper import com.squareup.moshi.Types import okhttp3.Call +import okhttp3.Interceptor import okhttp3.OkHttpClient import okhttp3.ResponseBody import okio.Buffer @@ -27,12 +28,12 @@ class AttachmentsTests { @BeforeEach fun setup() { MockitoAnnotations.openMocks(this) - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) + whenever(mockResponse.body).thenReturn(mockResponseBody) } @Nested diff --git a/src/test/kotlin/com/nylas/resources/AuthTests.kt b/src/test/kotlin/com/nylas/resources/AuthTests.kt index ac7d2b2c..e8984cc0 100644 --- a/src/test/kotlin/com/nylas/resources/AuthTests.kt +++ b/src/test/kotlin/com/nylas/resources/AuthTests.kt @@ -5,7 +5,8 @@ import com.nylas.models.* import com.nylas.util.JsonHelper import com.squareup.moshi.Types import okhttp3.Call -import okhttp3.HttpUrl +import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.Interceptor import okhttp3.OkHttpClient import okhttp3.ResponseBody import org.junit.jupiter.api.BeforeEach @@ -36,15 +37,15 @@ class AuthTests { @BeforeEach fun setup() { MockitoAnnotations.openMocks(this) - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) + whenever(mockResponse.body).thenReturn(mockResponseBody) grantId = "abc-123-grant-id" mockNylasClient = Mockito.mock(NylasClient::class.java) - whenever(mockNylasClient.newUrlBuilder()).thenReturn(HttpUrl.get(baseUrl).newBuilder()) + whenever(mockNylasClient.newUrlBuilder()).thenReturn(baseUrl.toHttpUrl().newBuilder()) whenever(mockNylasClient.apiKey).thenReturn("test-api-key") auth = Auth(mockNylasClient) } diff --git a/src/test/kotlin/com/nylas/resources/BookingsTest.kt b/src/test/kotlin/com/nylas/resources/BookingsTest.kt index 137950e3..abb6fcb3 100644 --- a/src/test/kotlin/com/nylas/resources/BookingsTest.kt +++ b/src/test/kotlin/com/nylas/resources/BookingsTest.kt @@ -27,12 +27,12 @@ class BookingsTest { @BeforeEach fun setUp() { MockitoAnnotations.openMocks(this) - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) + whenever(mockResponse.body).thenReturn(mockResponseBody) } @Nested diff --git a/src/test/kotlin/com/nylas/resources/CalendarsTest.kt b/src/test/kotlin/com/nylas/resources/CalendarsTest.kt index 43c1ee26..ed719232 100644 --- a/src/test/kotlin/com/nylas/resources/CalendarsTest.kt +++ b/src/test/kotlin/com/nylas/resources/CalendarsTest.kt @@ -27,12 +27,12 @@ class CalendarsTest { @BeforeEach fun setup() { MockitoAnnotations.openMocks(this) - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) + whenever(mockResponse.body).thenReturn(mockResponseBody) } @Nested diff --git a/src/test/kotlin/com/nylas/resources/ConfigurationsTest.kt b/src/test/kotlin/com/nylas/resources/ConfigurationsTest.kt index 917997fb..61adad10 100644 --- a/src/test/kotlin/com/nylas/resources/ConfigurationsTest.kt +++ b/src/test/kotlin/com/nylas/resources/ConfigurationsTest.kt @@ -28,12 +28,12 @@ class ConfigurationsTest { @BeforeEach fun setup() { MockitoAnnotations.openMocks(this) - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) + whenever(mockResponse.body).thenReturn(mockResponseBody) } @Nested diff --git a/src/test/kotlin/com/nylas/resources/ConnectorsTests.kt b/src/test/kotlin/com/nylas/resources/ConnectorsTests.kt index 841cb9e7..c691b165 100644 --- a/src/test/kotlin/com/nylas/resources/ConnectorsTests.kt +++ b/src/test/kotlin/com/nylas/resources/ConnectorsTests.kt @@ -5,6 +5,7 @@ import com.nylas.models.* import com.nylas.util.JsonHelper import com.squareup.moshi.Types import okhttp3.Call +import okhttp3.Interceptor import okhttp3.OkHttpClient import okhttp3.ResponseBody import okio.Buffer @@ -31,12 +32,12 @@ class ConnectorsTests { @BeforeEach fun setup() { MockitoAnnotations.openMocks(this) - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) + whenever(mockResponse.body).thenReturn(mockResponseBody) } @Nested diff --git a/src/test/kotlin/com/nylas/resources/ContactsTests.kt b/src/test/kotlin/com/nylas/resources/ContactsTests.kt index bb15167c..c2710025 100644 --- a/src/test/kotlin/com/nylas/resources/ContactsTests.kt +++ b/src/test/kotlin/com/nylas/resources/ContactsTests.kt @@ -28,12 +28,12 @@ class ContactsTests { @BeforeEach fun setup() { MockitoAnnotations.openMocks(this) - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) + whenever(mockResponse.body).thenReturn(mockResponseBody) } @Nested diff --git a/src/test/kotlin/com/nylas/resources/CredentialsTests.kt b/src/test/kotlin/com/nylas/resources/CredentialsTests.kt index dce1f425..3eeb6e97 100644 --- a/src/test/kotlin/com/nylas/resources/CredentialsTests.kt +++ b/src/test/kotlin/com/nylas/resources/CredentialsTests.kt @@ -5,6 +5,7 @@ import com.nylas.models.* import com.nylas.util.JsonHelper import com.squareup.moshi.Types import okhttp3.Call +import okhttp3.Interceptor import okhttp3.OkHttpClient import okhttp3.ResponseBody import okio.Buffer @@ -31,12 +32,12 @@ class CredentialsTests { @BeforeEach fun setup() { MockitoAnnotations.openMocks(this) - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) + whenever(mockResponse.body).thenReturn(mockResponseBody) } @Nested diff --git a/src/test/kotlin/com/nylas/resources/DraftsTests.kt b/src/test/kotlin/com/nylas/resources/DraftsTests.kt index 1f440116..3c613bd5 100644 --- a/src/test/kotlin/com/nylas/resources/DraftsTests.kt +++ b/src/test/kotlin/com/nylas/resources/DraftsTests.kt @@ -32,12 +32,12 @@ class DraftsTests { @BeforeEach fun setup() { MockitoAnnotations.openMocks(this) - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) + whenever(mockResponse.body).thenReturn(mockResponseBody) } @Nested @@ -359,11 +359,11 @@ class DraftsTests { assertEquals(NylasClient.HttpMethod.POST, methodCaptor.firstValue) assertNull(queryParamCaptor.firstValue) val multipart = requestBodyCaptor.firstValue as MultipartBody - assertEquals(2, multipart.size()) + assertEquals(2, multipart.size) val buffer = Buffer() val fileBuffer = Buffer() - multipart.part(0).body().writeTo(buffer) - multipart.part(1).body().writeTo(fileBuffer) + multipart.part(0).body.writeTo(buffer) + multipart.part(1).body.writeTo(fileBuffer) assertEquals(adapter.toJson(attachmentLessRequest), buffer.readUtf8()) assertEquals("test data", fileBuffer.readUtf8()) } @@ -498,11 +498,11 @@ class DraftsTests { assertEquals(NylasClient.HttpMethod.PUT, methodCaptor.firstValue) assertNull(queryParamCaptor.firstValue) val multipart = requestBodyCaptor.firstValue as MultipartBody - assertEquals(2, multipart.size()) + assertEquals(2, multipart.size) val buffer = Buffer() val fileBuffer = Buffer() - multipart.part(0).body().writeTo(buffer) - multipart.part(1).body().writeTo(fileBuffer) + multipart.part(0).body.writeTo(buffer) + multipart.part(1).body.writeTo(fileBuffer) assertEquals(adapter.toJson(attachmentLessRequest), buffer.readUtf8()) assertEquals("test data", fileBuffer.readUtf8()) } diff --git a/src/test/kotlin/com/nylas/resources/EventsTests.kt b/src/test/kotlin/com/nylas/resources/EventsTests.kt index 67caafb3..32483bbd 100644 --- a/src/test/kotlin/com/nylas/resources/EventsTests.kt +++ b/src/test/kotlin/com/nylas/resources/EventsTests.kt @@ -27,12 +27,12 @@ class EventsTests { @BeforeEach fun setup() { MockitoAnnotations.openMocks(this) - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) + whenever(mockResponse.body).thenReturn(mockResponseBody) } @Nested diff --git a/src/test/kotlin/com/nylas/resources/FoldersTests.kt b/src/test/kotlin/com/nylas/resources/FoldersTests.kt index 4beb8949..3c12f845 100644 --- a/src/test/kotlin/com/nylas/resources/FoldersTests.kt +++ b/src/test/kotlin/com/nylas/resources/FoldersTests.kt @@ -28,12 +28,12 @@ class FoldersTests { @BeforeEach fun setup() { MockitoAnnotations.openMocks(this) - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) + whenever(mockResponse.body).thenReturn(mockResponseBody) } @Nested diff --git a/src/test/kotlin/com/nylas/resources/GrantsTests.kt b/src/test/kotlin/com/nylas/resources/GrantsTests.kt index 5e21d2e4..6ad79f56 100644 --- a/src/test/kotlin/com/nylas/resources/GrantsTests.kt +++ b/src/test/kotlin/com/nylas/resources/GrantsTests.kt @@ -5,6 +5,7 @@ import com.nylas.models.* import com.nylas.util.JsonHelper import com.squareup.moshi.Types import okhttp3.Call +import okhttp3.Interceptor import okhttp3.OkHttpClient import okhttp3.ResponseBody import okio.Buffer @@ -32,12 +33,12 @@ class GrantsTests { @BeforeEach fun setup() { MockitoAnnotations.openMocks(this) - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) + whenever(mockResponse.body).thenReturn(mockResponseBody) } @Nested diff --git a/src/test/kotlin/com/nylas/resources/MessagesTests.kt b/src/test/kotlin/com/nylas/resources/MessagesTests.kt index 0bad6ae6..c1a66f16 100644 --- a/src/test/kotlin/com/nylas/resources/MessagesTests.kt +++ b/src/test/kotlin/com/nylas/resources/MessagesTests.kt @@ -29,12 +29,12 @@ class MessagesTests { @BeforeEach fun setup() { MockitoAnnotations.openMocks(this) - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) + whenever(mockResponse.body).thenReturn(mockResponseBody) } @Nested @@ -665,11 +665,11 @@ class MessagesTests { assertEquals(NylasClient.HttpMethod.POST, methodCaptor.firstValue) assertNull(queryParamCaptor.firstValue) val multipart = requestBodyCaptor.firstValue as MultipartBody - assertEquals(2, multipart.size()) + assertEquals(2, multipart.size) val buffer = Buffer() val fileBuffer = Buffer() - multipart.part(0).body().writeTo(buffer) - multipart.part(1).body().writeTo(fileBuffer) + multipart.part(0).body.writeTo(buffer) + multipart.part(1).body.writeTo(fileBuffer) assertEquals(adapter.toJson(attachmentLessRequest), buffer.readUtf8()) assertEquals("test data", fileBuffer.readUtf8()) } diff --git a/src/test/kotlin/com/nylas/resources/NotetakersTests.kt b/src/test/kotlin/com/nylas/resources/NotetakersTests.kt index 5b81b5d2..221fb91c 100644 --- a/src/test/kotlin/com/nylas/resources/NotetakersTests.kt +++ b/src/test/kotlin/com/nylas/resources/NotetakersTests.kt @@ -28,12 +28,12 @@ class NotetakersTests { @BeforeEach fun setup() { MockitoAnnotations.openMocks(this) - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) + whenever(mockResponse.body).thenReturn(mockResponseBody) } @Nested diff --git a/src/test/kotlin/com/nylas/resources/RedirectUriTests.kt b/src/test/kotlin/com/nylas/resources/RedirectUriTests.kt index dd4240af..3212ada4 100644 --- a/src/test/kotlin/com/nylas/resources/RedirectUriTests.kt +++ b/src/test/kotlin/com/nylas/resources/RedirectUriTests.kt @@ -5,6 +5,7 @@ import com.nylas.models.* import com.nylas.util.JsonHelper import com.squareup.moshi.Types import okhttp3.Call +import okhttp3.Interceptor import okhttp3.OkHttpClient import okhttp3.ResponseBody import okio.Buffer @@ -31,12 +32,12 @@ class RedirectUriTests { @BeforeEach fun setup() { MockitoAnnotations.openMocks(this) - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) + whenever(mockResponse.body).thenReturn(mockResponseBody) } @Nested diff --git a/src/test/kotlin/com/nylas/resources/SessionsTest.kt b/src/test/kotlin/com/nylas/resources/SessionsTest.kt index f4e7795c..8a32f673 100644 --- a/src/test/kotlin/com/nylas/resources/SessionsTest.kt +++ b/src/test/kotlin/com/nylas/resources/SessionsTest.kt @@ -27,12 +27,12 @@ class SessionsTest { @BeforeEach fun setup() { MockitoAnnotations.openMocks(this) - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) + whenever(mockResponse.body).thenReturn(mockResponseBody) } @Nested diff --git a/src/test/kotlin/com/nylas/resources/SmartComposeTests.kt b/src/test/kotlin/com/nylas/resources/SmartComposeTests.kt index 1e2f166d..9d8b8620 100644 --- a/src/test/kotlin/com/nylas/resources/SmartComposeTests.kt +++ b/src/test/kotlin/com/nylas/resources/SmartComposeTests.kt @@ -5,6 +5,7 @@ import com.nylas.models.* import com.nylas.util.JsonHelper import com.squareup.moshi.Types import okhttp3.Call +import okhttp3.Interceptor import okhttp3.OkHttpClient import okhttp3.ResponseBody import okio.Buffer @@ -32,12 +33,12 @@ class SmartComposeTests { @BeforeEach fun setup() { MockitoAnnotations.openMocks(this) - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) + whenever(mockResponse.body).thenReturn(mockResponseBody) } @Nested diff --git a/src/test/kotlin/com/nylas/resources/ThreadsTests.kt b/src/test/kotlin/com/nylas/resources/ThreadsTests.kt index 2413aea3..e90b77c3 100644 --- a/src/test/kotlin/com/nylas/resources/ThreadsTests.kt +++ b/src/test/kotlin/com/nylas/resources/ThreadsTests.kt @@ -29,12 +29,12 @@ class ThreadsTests { @BeforeEach fun setup() { MockitoAnnotations.openMocks(this) - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) + whenever(mockResponse.body).thenReturn(mockResponseBody) } @Nested diff --git a/src/test/kotlin/com/nylas/resources/WebhooksTests.kt b/src/test/kotlin/com/nylas/resources/WebhooksTests.kt index 8ccac8d1..c9131cec 100644 --- a/src/test/kotlin/com/nylas/resources/WebhooksTests.kt +++ b/src/test/kotlin/com/nylas/resources/WebhooksTests.kt @@ -5,6 +5,7 @@ import com.nylas.models.* import com.nylas.util.JsonHelper import com.squareup.moshi.Types import okhttp3.Call +import okhttp3.Interceptor import okhttp3.OkHttpClient import okhttp3.ResponseBody import okio.Buffer @@ -32,12 +33,12 @@ class WebhooksTests { @BeforeEach fun setup() { MockitoAnnotations.openMocks(this) - whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) whenever(mockCall.execute()).thenReturn(mockResponse) whenever(mockResponse.isSuccessful).thenReturn(true) - whenever(mockResponse.body()).thenReturn(mockResponseBody) + whenever(mockResponse.body).thenReturn(mockResponseBody) } @Nested From 5edc341e695ed08552ddf82f8ff3cfff8cb797ba Mon Sep 17 00:00:00 2001 From: Aaron de Mello Date: Wed, 30 Jul 2025 16:15:40 -0400 Subject: [PATCH 2/3] Improving codecoverage --- examples/Makefile | 3 + .../com/nylas/examples/OkHttpUpgradeTest.java | 82 ------------------- src/test/kotlin/com/nylas/NylasClientTest.kt | 48 +++++++++++ 3 files changed, 51 insertions(+), 82 deletions(-) delete mode 100644 examples/src/main/java/com/nylas/examples/OkHttpUpgradeTest.java diff --git a/examples/Makefile b/examples/Makefile index 23dfbe1c..cb5a09b5 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -21,6 +21,9 @@ list: java-notetaker: @cd .. && ./gradlew :examples:run -PmainClass=com.nylas.examples.NotetakerExample +java-messages: + @cd .. && ./gradlew :examples:run -PmainClass=com.nylas.examples.MessagesExample + java-events: @cd .. && ./gradlew :examples:run -PmainClass=com.nylas.examples.EventsExample diff --git a/examples/src/main/java/com/nylas/examples/OkHttpUpgradeTest.java b/examples/src/main/java/com/nylas/examples/OkHttpUpgradeTest.java deleted file mode 100644 index bf8aa919..00000000 --- a/examples/src/main/java/com/nylas/examples/OkHttpUpgradeTest.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.nylas.examples; - -import com.nylas.NylasClient; -import okhttp3.OkHttpClient; -import okhttp3.Protocol; - -import java.util.concurrent.TimeUnit; - -/** - * Simple test to verify OkHttp 4 upgrade works correctly - */ -public class OkHttpUpgradeTest { - public static void main(String[] args) { - try { - System.out.println("๐Ÿ”ง Testing OkHttp 4 upgrade with Nylas Java SDK...\n"); - - // Test 1: Basic NylasClient creation with default OkHttpClient - System.out.println("1. Testing basic NylasClient creation:"); - NylasClient basicClient = new NylasClient("test-api-key", new OkHttpClient.Builder(), "https://api.us.nylas.com"); - System.out.println(" โœ… Basic NylasClient created successfully"); - System.out.println(" API Key: " + basicClient.getApiKey()); - - // Test 2: NylasClient with custom OkHttpClient.Builder - System.out.println("\n2. Testing NylasClient with custom OkHttpClient:"); - OkHttpClient.Builder customBuilder = new OkHttpClient.Builder() - .connectTimeout(30, TimeUnit.SECONDS) - .readTimeout(60, TimeUnit.SECONDS) - .writeTimeout(45, TimeUnit.SECONDS) - .protocols(java.util.Arrays.asList(Protocol.HTTP_1_1)); - - NylasClient customClient = new NylasClient("test-api-key", customBuilder, "https://api.us.nylas.com"); - System.out.println(" โœ… Custom NylasClient created successfully"); - - // Test 3: NylasClient.Builder pattern - System.out.println("\n3. Testing NylasClient.Builder pattern:"); - NylasClient builderClient = new NylasClient.Builder("test-api-key") - .apiUri("https://api.us.nylas.com") - .httpClient(new OkHttpClient.Builder().callTimeout(120, TimeUnit.SECONDS)) - .build(); - System.out.println(" โœ… Builder pattern NylasClient created successfully"); - - // Test 4: Basic client functionality (tests OkHttp integration) - System.out.println("\n4. Testing basic client functionality:"); - try { - // Test that the client is properly initialized - System.out.println(" โœ… Client initialization successful"); - System.out.println(" โœ… Basic client methods accessible"); - } catch (Exception e) { - System.out.println(" โŒ Client functionality test failed: " + e.getMessage()); - throw e; - } - - // Test 5: OkHttp version information - System.out.println("\n5. OkHttp version information:"); - try { - // Try to get OkHttp version through reflection or manifest - Package okHttpPackage = OkHttpClient.class.getPackage(); - String version = okHttpPackage.getImplementationVersion(); - if (version != null) { - System.out.println(" OkHttp Version: " + version); - if (version.startsWith("4.")) { - System.out.println(" โœ… Successfully upgraded to OkHttp 4.x"); - } else { - System.out.println(" โš ๏ธ Unexpected version: " + version); - } - } else { - System.out.println(" โ„น๏ธ Version information not available"); - } - } catch (Exception e) { - System.out.println(" โ„น๏ธ Could not determine OkHttp version: " + e.getMessage()); - } - - System.out.println("\n๐ŸŽ‰ All OkHttp upgrade tests passed successfully!"); - System.out.println(" The Nylas Java SDK is compatible with OkHttp 4.x"); - - } catch (Exception e) { - System.out.println("\nโŒ OkHttp upgrade test failed: " + e.getMessage()); - e.printStackTrace(); - System.exit(1); - } - } -} \ No newline at end of file diff --git a/src/test/kotlin/com/nylas/NylasClientTest.kt b/src/test/kotlin/com/nylas/NylasClientTest.kt index 73c8439c..65ad3846 100644 --- a/src/test/kotlin/com/nylas/NylasClientTest.kt +++ b/src/test/kotlin/com/nylas/NylasClientTest.kt @@ -173,6 +173,30 @@ class NylasClientTest { val result = nylasClient.webhooks() assertNotNull(result) } + + @Test + fun `grants returns a valid Grants instance`() { + val result = nylasClient.grants() + assertNotNull(result) + } + + @Test + fun `contacts returns a valid Contacts instance`() { + val result = nylasClient.contacts() + assertNotNull(result) + } + + @Test + fun `scheduler returns a valid Scheduler instance`() { + val result = nylasClient.scheduler() + assertNotNull(result) + } + + @Test + fun `notetakers returns a valid Notetakers instance`() { + val result = nylasClient.notetakers() + assertNotNull(result) + } } @Nested @@ -407,6 +431,30 @@ class NylasClientTest { assertEquals(capturedRequest.method, "GET") } + @Test + fun `executeGet should handle Double query parameters correctly`() { + val mockQueryParams: IQueryParams = mock() + whenever(mockQueryParams.convertToMap()).thenReturn( + mapOf( + "doubleValue" to 3.14, + "anotherDouble" to 2.5, + ), + ) + whenever(mockResponseBody.source()).thenReturn(Buffer().writeUtf8("{ \"foo\": \"bar\" }")) + nylasClient.executeGet>( + "test/path", + JsonHelper.mapTypeOf(String::class.java, String::class.java), + mockQueryParams, + ) + + val requestCaptor = argumentCaptor() + verify(mockHttpClient).newCall(requestCaptor.capture()) + val capturedRequest = requestCaptor.firstValue + + assertEquals(capturedRequest.url.toString(), "https://api.us.nylas.com/test/path?doubleValue=3&anotherDouble=2") + assertEquals(capturedRequest.method, "GET") + } + @Test fun `executePut should set up the request with the correct params`() { val putBody = "{ \"test\": \"updated\" }" From 51a596fdb0e596b73aa5e7564756a73e5d5130bf Mon Sep 17 00:00:00 2001 From: Aaron de Mello Date: Thu, 31 Jul 2025 12:39:21 -0400 Subject: [PATCH 3/3] Adde an example for sending attachments --- examples/.env.example | 5 +- examples/Makefile | 4 + examples/README.md | 29 +- examples/build.gradle.kts | 1 + .../examples/LargeAttachmentsExample.java | 372 ++++++++++++++++++ 5 files changed, 406 insertions(+), 5 deletions(-) create mode 100644 examples/src/main/java/com/nylas/examples/LargeAttachmentsExample.java diff --git a/examples/.env.example b/examples/.env.example index 9b015c6e..7d6d0112 100644 --- a/examples/.env.example +++ b/examples/.env.example @@ -12,4 +12,7 @@ NYLAS_API_URI=https://api.us.nylas.com # Grant ID - Required for message and event examples # You can get this from your Nylas Dashboard after connecting an account -NYLAS_GRANT_ID=your_grant_id_here \ No newline at end of file +NYLAS_GRANT_ID=your_grant_id_here + +# Test email +NYLAS_TEST_EMAIL=your@email.com \ No newline at end of file diff --git a/examples/Makefile b/examples/Makefile index cb5a09b5..712eb2ba 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -10,6 +10,7 @@ help: @echo " java-notetaker - Run the Java Notetaker example" @echo " java-events - Run the Java Events example" @echo " java-folders - Run the Java Folders example" + @echo " java-large-attachments - Run the Java Large Attachments example" @echo " kotlin-notetaker - Run the Kotlin Notetaker example" @echo " kotlin-folders - Run the Kotlin Folders example" @@ -24,6 +25,9 @@ java-notetaker: java-messages: @cd .. && ./gradlew :examples:run -PmainClass=com.nylas.examples.MessagesExample +java-large-attachments: + @cd .. && ./gradlew :examples:run -PmainClass=com.nylas.examples.LargeAttachmentsExample + java-events: @cd .. && ./gradlew :examples:run -PmainClass=com.nylas.examples.EventsExample diff --git a/examples/README.md b/examples/README.md index 1d80ea85..7818a3ad 100644 --- a/examples/README.md +++ b/examples/README.md @@ -40,6 +40,17 @@ The `FoldersExample` and `KotlinFoldersExample` demonstrate how to use the Nylas - Demonstrate the builder pattern with various query parameters - Show folder details including parent relationships and unread counts +### Large Attachments Example + +The `LargeAttachmentsExample` demonstrates how to send emails with large file attachments using the Nylas Java SDK: + +- Create and send emails with 3MB and 10MB test files +- Demonstrate the SDK's automatic handling of large attachments (switches to multipart form data for files โ‰ฅ 3MB) +- Send multiple large attachments in a single email +- Compare small vs large attachment handling mechanisms +- Use the `FileUtils.attachFileRequestBuilder()` helper method for easy file attachment +- Automatic cleanup of temporary test files + ## Setup ### 1. Environment Setup @@ -58,6 +69,9 @@ NYLAS_API_KEY=your_api_key_here # Your grant ID (required for message examples) NYLAS_GRANT_ID=your_grant_id_here +# Test email address (required for large attachments example) +NYLAS_TEST_EMAIL=test@example.com + # Add your meeting link (Zoom, Google Meet, or Microsoft Teams) - for Notetaker example MEETING_LINK=your_meeting_link_here ``` @@ -101,6 +115,11 @@ Run Kotlin Folders example: ./gradlew :examples:run -PmainClass=com.nylas.examples.KotlinFoldersExampleKt ``` +Run Java Large Attachments example: +```bash +./gradlew :examples:run -PmainClass=com.nylas.examples.LargeAttachmentsExample +``` + #### Option 2: Using the Makefile List available examples: @@ -127,6 +146,7 @@ make kotlin-way - `KotlinMessagesExample.kt` (Kotlin - demonstrates new message features) - `EventsExample.java` (Java - demonstrates events) - `FoldersExample.java` (Java - demonstrates folders and single_level parameter) + - `LargeAttachmentsExample.java` (Java - demonstrates large file attachments) - `NotetakerExample.java` (Java - demonstrates notetakers) - `KotlinNotetakerExample.kt` (Kotlin - demonstrates notetakers) - `KotlinFoldersExample.kt` (Kotlin - demonstrates folders and single_level parameter) @@ -143,10 +163,11 @@ examples/ โ””โ”€โ”€ main/ โ”œโ”€โ”€ java/ # Java examples โ”‚ โ””โ”€โ”€ com/nylas/examples/ - โ”‚ โ”œโ”€โ”€ MessagesExample.java # NEW: Message features demo - โ”‚ โ”œโ”€โ”€ EventsExample.java # Events API demo - โ”‚ โ”œโ”€โ”€ FoldersExample.java # NEW: Folders API demo with single_level parameter - โ”‚ โ””โ”€โ”€ NotetakerExample.java # Notetaker API demo + โ”‚ โ”œโ”€โ”€ MessagesExample.java # NEW: Message features demo + โ”‚ โ”œโ”€โ”€ EventsExample.java # Events API demo + โ”‚ โ”œโ”€โ”€ FoldersExample.java # NEW: Folders API demo with single_level parameter + โ”‚ โ”œโ”€โ”€ LargeAttachmentsExample.java # NEW: Large file attachments demo + โ”‚ โ””โ”€โ”€ NotetakerExample.java # Notetaker API demo โ””โ”€โ”€ kotlin/ # Kotlin examples โ””โ”€โ”€ com/nylas/examples/ โ”œโ”€โ”€ KotlinMessagesExample.kt # NEW: Message features demo diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 27e6d52b..3c637bbf 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -55,6 +55,7 @@ tasks.register("listExamples") { println("- Java-Events: com.nylas.examples.EventsExample") println("- Java-Messages: com.nylas.examples.MessagesExample") println("- Java-Folders: com.nylas.examples.FoldersExample") + println("- Java-Large-Attachments: com.nylas.examples.LargeAttachmentsExample") println("- Kotlin-Notetaker: com.nylas.examples.KotlinNotetakerExampleKt") println("- Kotlin-Messages: com.nylas.examples.KotlinMessagesExampleKt") println("- Kotlin-Folders: com.nylas.examples.KotlinFoldersExampleKt") diff --git a/examples/src/main/java/com/nylas/examples/LargeAttachmentsExample.java b/examples/src/main/java/com/nylas/examples/LargeAttachmentsExample.java new file mode 100644 index 00000000..a9450f13 --- /dev/null +++ b/examples/src/main/java/com/nylas/examples/LargeAttachmentsExample.java @@ -0,0 +1,372 @@ +package com.nylas.examples; + +import com.nylas.NylasClient; +import com.nylas.models.CreateAttachmentRequest; +import com.nylas.models.EmailName; +import com.nylas.models.Message; +import com.nylas.models.NylasApiError; +import com.nylas.models.NylasSdkTimeoutError; +import com.nylas.models.Response; +import com.nylas.models.SendMessageRequest; +import com.nylas.models.TrackingOptions; +import com.nylas.util.FileUtils; +import okhttp3.OkHttpClient; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.stream.Collectors; + +/** + * Example demonstrating sending large file attachments with Nylas Java SDK: + * - Creating test files of 3MB and 10MB + * - Sending messages with large attachments (automatically handled via multipart form data) + * - Demonstrating the SDK's automatic switching between JSON and form data based on attachment size + * - Using the FileUtils.attachFileRequestBuilder() helper method + */ +public class LargeAttachmentsExample { + // File sizes for testing + private static final int FILE_SIZE_3MB = 3 * 1024 * 1024; // 3MB + private static final int FILE_SIZE_10MB = 10 * 1024 * 1024; // 10MB + private static final String TEMP_DIR = System.getProperty("java.io.tmpdir"); + + public static void main(String[] args) { + try { + // Load configuration from environment variables or .env file + Map config = loadConfig(); + + // Initialize the Nylas client with your API key + NylasClient nylas = new NylasClient( + config.get("NYLAS_API_KEY"), + new OkHttpClient.Builder(), + config.getOrDefault("NYLAS_API_URI", "https://api.us.nylas.com") + ); + + // Run the large attachments example workflow + runLargeAttachmentsExample(nylas, config); + + // Exit successfully + System.exit(0); + + } catch (NylasApiError e) { + System.out.println("\nโŒ Nylas API Error: " + e.getMessage()); + System.out.println(" Status code: " + e.getStatusCode()); + System.out.println(" Request ID: " + e.getRequestId()); + System.exit(1); + } catch (IllegalArgumentException e) { + System.out.println("\nโŒ Configuration Error: " + e.getMessage()); + System.exit(1); + } catch (Exception e) { + System.out.println("\nโŒ Unexpected Error: " + e.getMessage()); + e.printStackTrace(); + System.exit(1); + } + } + + /** + * Loads configuration from environment variables and .env file + * @throws IllegalArgumentException if required configuration is missing + */ + private static Map loadConfig() { + Map config = new HashMap<>(); + + // Try loading from environment variables first + System.getenv().entrySet().stream() + .filter(entry -> entry.getKey().startsWith("NYLAS_")) + .forEach(entry -> config.put(entry.getKey(), entry.getValue())); + + // Then try loading from .env file if needed + List envPaths = Arrays.asList("examples/.env", ".env"); + for (String path : envPaths) { + File envFile = new File(path); + if (envFile.exists()) { + System.out.println("๐Ÿ“ Loading configuration from " + envFile.getAbsolutePath()); + try { + Files.lines(envFile.toPath()) + .filter(line -> !line.trim().isEmpty() && !line.startsWith("#")) + .forEach(line -> { + String[] parts = line.split("=", 2); + if (parts.length == 2) { + String key = parts[0].trim(); + String value = parts[1].trim(); + if (!config.containsKey(key)) { + config.put(key, value); + } + } + }); + } catch (IOException e) { + System.out.println("Warning: Failed to load .env file: " + e.getMessage()); + } + } + } + + // Validate required configuration + List requiredKeys = Arrays.asList("NYLAS_API_KEY", "NYLAS_GRANT_ID", "NYLAS_TEST_EMAIL"); + List missingKeys = requiredKeys.stream() + .filter(key -> !config.containsKey(key)) + .collect(Collectors.toList()); + + if (!missingKeys.isEmpty()) { + throw new IllegalArgumentException( + "Missing required configuration: " + String.join(", ", missingKeys) + "\n" + + "Please set these in examples/.env or as environment variables.\n" + + "NYLAS_TEST_EMAIL should be set to a valid email address for testing." + ); + } + + return config; + } + + private static void runLargeAttachmentsExample(NylasClient nylas, Map config) + throws NylasApiError, NylasSdkTimeoutError, IOException { + String grantId = config.get("NYLAS_GRANT_ID"); + String testEmail = config.get("NYLAS_TEST_EMAIL"); + + System.out.println("๐Ÿ”— Demonstrating Nylas Large Attachments API...\n"); + System.out.println("Test email recipient: " + testEmail); + System.out.println("Temp directory: " + TEMP_DIR); + System.out.println(); + + File testFile3MB = null; + File testFile10MB = null; + + try { + // 1. Create test files + testFile3MB = createTestFile("test-3mb.txt", FILE_SIZE_3MB); + testFile10MB = createTestFile("test-10mb.txt", FILE_SIZE_10MB); + + // 2. Send email with 3MB attachment (should use form data) + demonstrateLargeAttachmentSending(nylas, grantId, testEmail, testFile3MB, "3MB"); + + // 3. Send email with 10MB attachment (should use form data) + demonstrateLargeAttachmentSending(nylas, grantId, testEmail, testFile10MB, "10MB"); + + // 4. Send email with both attachments + demonstrateMultipleLargeAttachments(nylas, grantId, testEmail, testFile3MB, testFile10MB); + + // 5. Demonstrate small vs large attachment handling + demonstrateAttachmentSizeHandling(nylas, grantId, testEmail); + + } finally { + // Clean up test files + if (testFile3MB != null && testFile3MB.exists()) { + testFile3MB.delete(); + System.out.println("๐Ÿงน Cleaned up: " + testFile3MB.getName()); + } + if (testFile10MB != null && testFile10MB.exists()) { + testFile10MB.delete(); + System.out.println("๐Ÿงน Cleaned up: " + testFile10MB.getName()); + } + } + } + + /** + * Creates a test file with the specified name and size + */ + private static File createTestFile(String filename, int sizeInBytes) throws IOException { + System.out.println("๐Ÿ“ Creating test file: " + filename + " (" + formatFileSize(sizeInBytes) + ")"); + + File file = new File(TEMP_DIR, filename); + + // Generate random content to make the file realistic + Random random = new Random(); + byte[] buffer = new byte[8192]; // 8KB buffer + + try (FileOutputStream fos = new FileOutputStream(file)) { + int remainingBytes = sizeInBytes; + + while (remainingBytes > 0) { + int bytesToWrite = Math.min(buffer.length, remainingBytes); + + // Fill buffer with random data + random.nextBytes(buffer); + + // For readability, occasionally add line breaks + if (random.nextInt(20) == 0 && bytesToWrite > 1) { + buffer[bytesToWrite - 1] = '\n'; + } + + fos.write(buffer, 0, bytesToWrite); + remainingBytes -= bytesToWrite; + } + } + + System.out.println(" โœ… Created: " + file.getAbsolutePath()); + return file; + } + + private static void demonstrateLargeAttachmentSending(NylasClient nylas, String grantId, + String testEmail, File attachmentFile, String fileDescription) + throws NylasApiError, NylasSdkTimeoutError { + + System.out.println("๐Ÿ“ง Sending email with " + fileDescription + " attachment:"); + System.out.println(" File: " + attachmentFile.getName()); + System.out.println(" Size: " + formatFileSize((int) attachmentFile.length())); + + // Create attachment request using FileUtils helper + CreateAttachmentRequest attachment = FileUtils.attachFileRequestBuilder(attachmentFile.getAbsolutePath()); + + // Create the email request + SendMessageRequest sendRequest = new SendMessageRequest.Builder(Arrays.asList(new EmailName(testEmail, "Test Recipient"))) + .subject("Large Attachment Test - " + fileDescription + " File") + .body(createEmailBody(fileDescription, attachmentFile)) + .attachments(Arrays.asList(attachment)) + .trackingOptions(new TrackingOptions("large-attachment-test", true, true, true)) + .build(); + + // Send the message + long startTime = System.currentTimeMillis(); + Response response = nylas.messages().send(grantId, sendRequest); + long endTime = System.currentTimeMillis(); + + Message sentMessage = response.getData(); + System.out.println(" โœ… Email sent successfully!"); + System.out.println(" Message ID: " + sentMessage.getId()); + System.out.println(" Send time: " + (endTime - startTime) + "ms"); + System.out.println(" Attachments in response: " + + (sentMessage.getAttachments() != null ? sentMessage.getAttachments().size() : 0)); + System.out.println(); + } + + private static void demonstrateMultipleLargeAttachments(NylasClient nylas, String grantId, + String testEmail, File file3MB, File file10MB) + throws NylasApiError, NylasSdkTimeoutError { + + System.out.println("๐Ÿ“ง Sending email with multiple large attachments:"); + System.out.println(" File 1: " + file3MB.getName() + " (" + formatFileSize((int) file3MB.length()) + ")"); + System.out.println(" File 2: " + file10MB.getName() + " (" + formatFileSize((int) file10MB.length()) + ")"); + System.out.println(" Total size: " + formatFileSize((int) (file3MB.length() + file10MB.length()))); + + // Create attachment requests + CreateAttachmentRequest attachment3MB = FileUtils.attachFileRequestBuilder(file3MB.getAbsolutePath()); + CreateAttachmentRequest attachment10MB = FileUtils.attachFileRequestBuilder(file10MB.getAbsolutePath()); + + // Create the email request with multiple attachments + SendMessageRequest sendRequest = new SendMessageRequest.Builder(Arrays.asList(new EmailName(testEmail, "Test Recipient"))) + .subject("Multiple Large Attachments Test - 13MB Total") + .body(createMultipleAttachmentsEmailBody(file3MB, file10MB)) + .attachments(Arrays.asList(attachment3MB, attachment10MB)) + .trackingOptions(new TrackingOptions("multiple-large-attachments-test", true, true, null)) + .build(); + + // Send the message + long startTime = System.currentTimeMillis(); + Response response = nylas.messages().send(grantId, sendRequest); + long endTime = System.currentTimeMillis(); + + Message sentMessage = response.getData(); + System.out.println(" โœ… Email sent successfully!"); + System.out.println(" Message ID: " + sentMessage.getId()); + System.out.println(" Send time: " + (endTime - startTime) + "ms"); + System.out.println(" Attachments in response: " + + (sentMessage.getAttachments() != null ? sentMessage.getAttachments().size() : 0)); + System.out.println(); + } + + private static void demonstrateAttachmentSizeHandling(NylasClient nylas, String grantId, String testEmail) + throws IOException, NylasApiError, NylasSdkTimeoutError { + + System.out.println("๐Ÿ”„ Demonstrating SDK's automatic handling of different attachment sizes:"); + + // Create a small file (under 3MB threshold) + File smallFile = createTestFile("test-small.txt", 1024 * 1024); // 1MB + + try { + System.out.println(" ๐Ÿ“„ Small attachment (1MB) - will use JSON encoding:"); + CreateAttachmentRequest smallAttachment = FileUtils.attachFileRequestBuilder(smallFile.getAbsolutePath()); + + SendMessageRequest smallFileRequest = new SendMessageRequest.Builder(Arrays.asList(new EmailName(testEmail, "Test Recipient"))) + .subject("Small Attachment Test - 1MB File (JSON Encoding)") + .body("

This email contains a small (1MB) attachment that will be sent using JSON encoding.

" + + "

The Nylas SDK automatically chooses the optimal encoding method based on file size.

" + + "
    " + + "
  • Files under 3MB: JSON encoding (faster for small files)
  • " + + "
  • Files 3MB and above: Multipart form encoding (more efficient for large files)
  • " + + "
") + .attachments(Arrays.asList(smallAttachment)) + .build(); + + long startTime = System.currentTimeMillis(); + Response response = nylas.messages().send(grantId, smallFileRequest); + long endTime = System.currentTimeMillis(); + + System.out.println(" โœ… Small file sent via JSON encoding"); + System.out.println(" Message ID: " + response.getData().getId()); + System.out.println(" Send time: " + (endTime - startTime) + "ms"); + + } finally { + if (smallFile.exists()) { + smallFile.delete(); + System.out.println("๐Ÿงน Cleaned up: " + smallFile.getName()); + } + } + + System.out.println("\n ๐Ÿ“Š Summary of SDK attachment handling:"); + System.out.println(" โ€ข Files < 3MB: Automatic JSON encoding (base64)"); + System.out.println(" โ€ข Files โ‰ฅ 3MB: Automatic multipart form encoding (streaming)"); + System.out.println(" โ€ข The switch is transparent to the developer"); + System.out.println(" โ€ข Large files use streaming to minimize memory usage"); + System.out.println(); + } + + private static String createEmailBody(String fileDescription, File attachmentFile) { + return String.format( + "

Large Attachment Test - %s File

" + + "

This email demonstrates sending large file attachments using the Nylas Java SDK.

" + + "

Attachment Details:

" + + "
    " + + "
  • Filename: %s
  • " + + "
  • Size: %s
  • " + + "
  • Encoding: Multipart form data (automatic for files โ‰ฅ 3MB)
  • " + + "
" + + "

The Nylas SDK automatically handles large attachments by switching from JSON encoding " + + "to multipart form encoding when files are 3MB or larger. This provides optimal performance " + + "and memory usage for both small and large files.

" + + "

This is a test email sent from the Nylas Java SDK Large Attachments Example.

", + fileDescription, + attachmentFile.getName(), + formatFileSize((int) attachmentFile.length()) + ); + } + + private static String createMultipleAttachmentsEmailBody(File file3MB, File file10MB) { + return String.format( + "

Multiple Large Attachments Test

" + + "

This email demonstrates sending multiple large file attachments in a single message.

" + + "

Attached Files:

" + + "
    " + + "
  1. %s - %s
  2. " + + "
  3. %s - %s
  4. " + + "
" + + "

Total Size:

" + + "

%s across 2 files

" + + "

Both files exceed the 3MB threshold, so the entire message is sent using " + + "multipart form encoding for optimal performance.

" + + "

This is a test email sent from the Nylas Java SDK Large Attachments Example.

", + file3MB.getName(), + formatFileSize((int) file3MB.length()), + file10MB.getName(), + formatFileSize((int) file10MB.length()), + formatFileSize((int) (file3MB.length() + file10MB.length())) + ); + } + + /** + * Formats file size in human-readable format + */ + private static String formatFileSize(int bytes) { + if (bytes < 1024) { + return bytes + " bytes"; + } else if (bytes < 1024 * 1024) { + return String.format("%.1f KB", bytes / 1024.0); + } else { + return String.format("%.1f MB", bytes / (1024.0 * 1024.0)); + } + } +} \ No newline at end of file