Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .fernignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ src/main/java/com/merge/legacy
src/main/java/com/merge/api/core/QueryStringMapper.java

src/test/java/com/merge/api/integration/CursorPaginationIntegrationTest.java
src/main/java/com/merge/api/core/ClientOptions.java
src/test/java/com/merge/api/core/ClientOptionsTest.java
8 changes: 5 additions & 3 deletions src/main/java/com/merge/api/core/ClientOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,13 @@ public ClientOptions build() {
this.httpClient != null ? this.httpClient.newBuilder() : new OkHttpClient.Builder();

if (this.httpClient != null) {
timeout.ifPresent(timeout -> httpClientBuilder
.callTimeout(timeout, TimeUnit.SECONDS)
// Apply timeout configuration even when using custom client to ensure consistent behavior
int timeoutValue = this.timeout.orElse(60);
httpClientBuilder
.callTimeout(timeoutValue, TimeUnit.SECONDS)
.connectTimeout(0, TimeUnit.SECONDS)
.writeTimeout(0, TimeUnit.SECONDS)
.readTimeout(0, TimeUnit.SECONDS));
.readTimeout(0, TimeUnit.SECONDS);
} else {
httpClientBuilder
.callTimeout(this.timeout.orElse(60), TimeUnit.SECONDS)
Expand Down
135 changes: 135 additions & 0 deletions src/test/java/com/merge/api/core/ClientOptionsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package com.merge.api.core;

import okhttp3.OkHttpClient;
import org.junit.jupiter.api.Test;
import java.util.concurrent.TimeUnit;

import static org.junit.jupiter.api.Assertions.*;

public class ClientOptionsTest {

@Test
public void testDefaultClientTimeouts() {
// Test: No custom client, no explicit timeout -> uses 60s default
ClientOptions options = ClientOptions.builder()
.environment(Environment.PRODUCTION)
.build();

OkHttpClient client = options.httpClient();
assertEquals(60, client.callTimeoutMillis() / 1000);
assertEquals(0, client.connectTimeoutMillis());
assertEquals(0, client.readTimeoutMillis());
assertEquals(0, client.writeTimeoutMillis());
}

@Test
public void testDefaultClientWithExplicitTimeout() {
// Test: No custom client, explicit timeout -> uses explicit timeout
ClientOptions options = ClientOptions.builder()
.environment(Environment.PRODUCTION)
.timeout(120)
.build();

OkHttpClient client = options.httpClient();
assertEquals(120, client.callTimeoutMillis() / 1000);
assertEquals(0, client.connectTimeoutMillis());
assertEquals(0, client.readTimeoutMillis());
assertEquals(0, client.writeTimeoutMillis());
}

@Test
public void testCustomClientWithoutExplicitTimeout() {
// Test: Custom client with OkHttp defaults, no explicit SDK timeout -> uses 60s default
OkHttpClient customClient = new OkHttpClient.Builder().build();

ClientOptions options = ClientOptions.builder()
.environment(Environment.PRODUCTION)
.httpClient(customClient)
.build();

OkHttpClient client = options.httpClient();
assertEquals(60, client.callTimeoutMillis() / 1000);
assertEquals(0, client.connectTimeoutMillis());
assertEquals(0, client.readTimeoutMillis());
assertEquals(0, client.writeTimeoutMillis());
}

@Test
public void testCustomClientWithExplicitTimeout() {
// Test: Custom client with explicit SDK timeout -> uses explicit timeout
OkHttpClient customClient = new OkHttpClient.Builder().build();

ClientOptions options = ClientOptions.builder()
.environment(Environment.PRODUCTION)
.httpClient(customClient)
.timeout(90)
.build();

OkHttpClient client = options.httpClient();
assertEquals(90, client.callTimeoutMillis() / 1000);
assertEquals(0, client.connectTimeoutMillis());
assertEquals(0, client.readTimeoutMillis());
assertEquals(0, client.writeTimeoutMillis());
}

@Test
public void testCustomClientOverridesOriginalTimeouts() {
// Test: Custom client with different timeouts -> SDK overrides them
OkHttpClient customClient = new OkHttpClient.Builder()
.callTimeout(30, TimeUnit.SECONDS)
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.writeTimeout(25, TimeUnit.SECONDS)
.build();

ClientOptions options = ClientOptions.builder()
.environment(Environment.PRODUCTION)
.httpClient(customClient)
.timeout(120)
.build();

OkHttpClient client = options.httpClient();
// SDK should override all timeouts
assertEquals(120, client.callTimeoutMillis() / 1000);
assertEquals(0, client.connectTimeoutMillis());
assertEquals(0, client.readTimeoutMillis());
assertEquals(0, client.writeTimeoutMillis());
}

@Test
public void testTimeoutConsistencyBetweenCustomAndDefaultClients() {
// Test: Both custom and default clients should have same timeout behavior

// Default client
ClientOptions defaultOptions = ClientOptions.builder()
.environment(Environment.PRODUCTION)
.build();

// Custom client
OkHttpClient customClient = new OkHttpClient.Builder().build();
ClientOptions customOptions = ClientOptions.builder()
.environment(Environment.PRODUCTION)
.httpClient(customClient)
.build();

OkHttpClient defaultHttpClient = defaultOptions.httpClient();
OkHttpClient customHttpClient = customOptions.httpClient();

// Both should have same timeout configuration
assertEquals(defaultHttpClient.callTimeoutMillis(), customHttpClient.callTimeoutMillis());
assertEquals(defaultHttpClient.connectTimeoutMillis(), customHttpClient.connectTimeoutMillis());
assertEquals(defaultHttpClient.readTimeoutMillis(), customHttpClient.readTimeoutMillis());
assertEquals(defaultHttpClient.writeTimeoutMillis(), customHttpClient.writeTimeoutMillis());
}

@Test
public void testTimeoutReflectedInClientOptionsTimeout() {
// Test: ClientOptions.timeout() method returns actual client timeout
ClientOptions options = ClientOptions.builder()
.environment(Environment.PRODUCTION)
.timeout(75)
.build();

assertEquals(75, options.timeout(null));
}
}