diff --git a/changelog.md b/changelog.md index c98e8d7..80f1373 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,12 @@ # Changelog +## v1.11.1 + +### Apr 06, 2026 + +- Fix: `setTimeout` now applies to OkHttp connect, read, and write timeouts (previously only connect). Optional `setConnectTimeout`, `setReadTimeout`, and `setWriteTimeout` override individual phases. +- Build: Maven Surefire updated with `surefire-junit-platform` so JUnit 5 tests run when enabled. + ## v1.11.0 ### Feb 09, 2026 diff --git a/pom.xml b/pom.xml index b978879..a0bbd32 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ cms jar contentstack-management-java - 1.11.0 + 1.11.1 Contentstack Java Management SDK for Content Management API, Contentstack is a headless CMS with an API-first approach @@ -89,11 +89,11 @@ 3.0.0 5.2.2 3.1.12 - 2.12.0 - 2.12.0 - 5.1.0 + 3.0.0 + 3.0.0 + 5.3.2 0.8.13 - 1.18.38 + 1.18.42 5.11.4 5.10.1 2.13.2 @@ -101,6 +101,7 @@ 1.5 3.8.0 2.5.3 + 3.5.2 @@ -242,7 +243,14 @@ org.apache.maven.plugins maven-surefire-plugin - 3.0.0-M5 + ${maven-surefire-plugin.version} + + + org.apache.maven.surefire + surefire-junit-platform + ${maven-surefire-plugin.version} + + @@ -252,8 +260,9 @@ **/*TestCase.java **/*TestSuite.java - ${project.build.directory}/surefire-reports - true + ${project.build.directory}/surefire-reports + + true true diff --git a/src/main/java/com/contentstack/cms/Contentstack.java b/src/main/java/com/contentstack/cms/Contentstack.java index 1bcad23..ebe847b 100644 --- a/src/main/java/com/contentstack/cms/Contentstack.java +++ b/src/main/java/com/contentstack/cms/Contentstack.java @@ -599,6 +599,9 @@ public static class Builder { private String port = Util.PORT; // Default PORT for Contentstack API private String version = Util.VERSION; // Default Version for Contentstack API private int timeout = Util.TIMEOUT; // Default timeout 30 seconds + private Integer connectTimeoutSeconds; + private Integer readTimeoutSeconds; + private Integer writeTimeoutSeconds; private Boolean retry = Util.RETRY_ON_FAILURE;// Default base url for contentstack private RetryConfig retryConfig = RetryConfig.defaultConfig(); /** @@ -687,10 +690,37 @@ public Builder setVersion(@NotNull String version) { * @return Client timeout */ public Builder setTimeout(int timeout) { + validateTimeoutSeconds(timeout, "timeout"); this.timeout = timeout; return this; } + public Builder setReadTimeout(int readTimeoutSeconds) { + validateTimeoutSeconds(readTimeoutSeconds, "readTimeout"); + this.readTimeoutSeconds = readTimeoutSeconds; + return this; + } + + public Builder setWriteTimeout(int writeTimeoutSeconds) { + validateTimeoutSeconds(writeTimeoutSeconds, "writeTimeout"); + this.writeTimeoutSeconds = writeTimeoutSeconds; + return this; + } + + public Builder setConnectTimeout(int connectTimeoutSeconds) { + validateTimeoutSeconds(connectTimeoutSeconds, "connectTimeout"); + this.connectTimeoutSeconds = connectTimeoutSeconds; + return this; + } + + private static void validateTimeoutSeconds(int seconds, String name) { + if (seconds <= 0) { + throw new IllegalArgumentException(name + " must be positive."); + } + } + + + /** * Create a new connection pool with tuning parameters appropriate for a * single-user application. The tuning parameters in this pool are @@ -840,11 +870,16 @@ private void validateClient(Contentstack contentstack) { } private OkHttpClient httpClient(Contentstack contentstack, Boolean retryOnFailure) { + int connectSec = this.connectTimeoutSeconds != null ? this.connectTimeoutSeconds : this.timeout; + int readSec = this.readTimeoutSeconds != null ? this.readTimeoutSeconds : this.timeout; + int writeSec = this.writeTimeoutSeconds != null ? this.writeTimeoutSeconds : this.timeout; OkHttpClient.Builder builder = new OkHttpClient.Builder() .connectionPool(this.connectionPool) .addInterceptor(logger()) .proxy(this.proxy) - .connectTimeout(Duration.ofSeconds(this.timeout)) + .connectTimeout(Duration.ofSeconds(connectSec)) + .readTimeout(Duration.ofSeconds(readSec)) + .writeTimeout(Duration.ofSeconds(writeSec)) .retryOnConnectionFailure(retryOnFailure); // Add either OAuth or traditional auth interceptor diff --git a/src/test/java/com/contentstack/cms/ContentstackUnitTest.java b/src/test/java/com/contentstack/cms/ContentstackUnitTest.java index b2666c4..9e84c9b 100644 --- a/src/test/java/com/contentstack/cms/ContentstackUnitTest.java +++ b/src/test/java/com/contentstack/cms/ContentstackUnitTest.java @@ -19,6 +19,7 @@ import java.net.Proxy; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.TimeUnit; public class ContentstackUnitTest { @@ -167,6 +168,68 @@ void setTimeout() { Assertions.assertEquals(3, contentstack.timeout); } + @Test + void setTimeoutZeroThrows() { + Assertions.assertThrows(IllegalArgumentException.class, + () -> new Contentstack.Builder().setTimeout(0)); + } + + @Test + void setTimeoutNegativeThrows() { + Assertions.assertThrows(IllegalArgumentException.class, + () -> new Contentstack.Builder().setTimeout(-1)); + } + + @Test + void setReadTimeoutZeroThrows() { + Assertions.assertThrows(IllegalArgumentException.class, + () -> new Contentstack.Builder().setReadTimeout(0)); + } + + @Test + void setWriteTimeoutNegativeThrows() { + Assertions.assertThrows(IllegalArgumentException.class, + () -> new Contentstack.Builder().setWriteTimeout(-5)); + } + + @Test + void setConnectTimeoutInvalidThrows() { + Assertions.assertThrows(IllegalArgumentException.class, + () -> new Contentstack.Builder().setConnectTimeout(-1)); + } + + @Test + void okHttpTimeoutsMatchSetTimeout() { + Contentstack client = new Contentstack.Builder().setTimeout(45).build(); + OkHttpClient ok = (OkHttpClient) client.instance.callFactory(); + Assertions.assertEquals(45_000, ok.connectTimeoutMillis()); + Assertions.assertEquals(45_000, ok.readTimeoutMillis()); + Assertions.assertEquals(45_000, ok.writeTimeoutMillis()); + } + + @Test + void okHttpDefaultTimeoutsUseUtilTimeout() { + Contentstack client = new Contentstack.Builder().build(); + OkHttpClient ok = (OkHttpClient) client.instance.callFactory(); + int expectedMs = (int) TimeUnit.SECONDS.toMillis(30); + Assertions.assertEquals(expectedMs, ok.connectTimeoutMillis()); + Assertions.assertEquals(expectedMs, ok.readTimeoutMillis()); + Assertions.assertEquals(expectedMs, ok.writeTimeoutMillis()); + } + + @Test + void okHttpPerLegOverridesFallBackToSetTimeout() { + Contentstack client = new Contentstack.Builder() + .setTimeout(10) + .setReadTimeout(90) + .build(); + OkHttpClient ok = (OkHttpClient) client.instance.callFactory(); + Assertions.assertEquals(10_000, ok.connectTimeoutMillis()); + Assertions.assertEquals(90_000, ok.readTimeoutMillis()); + Assertions.assertEquals(10_000, ok.writeTimeoutMillis()); + Assertions.assertEquals(10, client.timeout); + } + @Test void testSetAuthtoken() { Contentstack contentstack = new Contentstack.Builder()