Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -31,31 +31,49 @@

import com.google.api.core.BetaApi;
import com.google.auto.value.AutoValue;
import com.google.common.base.Preconditions;
import java.time.Duration;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

/**
* A settings class to configure a {@link ResumableUploadCallable} for executing resumable uploads.
* Encapsulates protocol options such as payload chunk size.
* Encapsulates protocol options such as payload chunk size and global upload timeout.
*/
@BetaApi
@AutoValue
@NullMarked
public abstract class ResumableUploadCallSettings {
private static final int DEFAULT_CHUNK_SIZE = 8 * 1024 * 1024; // 8 MB

/** Returns the configured chunk size in bytes (defaults to 8 MB / 8,388,608 bytes). */
public abstract int getChunkSize();

/**
* Returns the global upload timeout governing the entire upload duration, or {@code null} if
* disabled.
*/
public abstract @Nullable Duration getGlobalTimeout();

/**
* Merges another {@code ResumableUploadCallSettings} instance with this one. Fields set in {@code
* other} override fields in this instance.
*
* @param other settings to overlay; may be {@code null}
* @return a new, resolved {@code ResumableUploadCallSettings} instance
*/
public ResumableUploadCallSettings merge(ResumableUploadCallSettings other) {
public ResumableUploadCallSettings merge(@Nullable ResumableUploadCallSettings other) {
if (other == null) {
return this;
}
return toBuilder().setChunkSize(other.getChunkSize()).build();
Builder builder = toBuilder();
if (other.getChunkSize() > 0) {
builder.setChunkSize(other.getChunkSize());
}
if (other.getGlobalTimeout() != null) {
builder.setGlobalTimeout(other.getGlobalTimeout());
}
return builder.build();
}

public abstract Builder toBuilder();
Expand All @@ -71,6 +89,20 @@ public abstract static class Builder {

public abstract int getChunkSize();

public abstract ResumableUploadCallSettings build();
public abstract Builder setGlobalTimeout(@Nullable Duration globalTimeout);

public abstract @Nullable Duration getGlobalTimeout();

abstract ResumableUploadCallSettings autoBuild();

public ResumableUploadCallSettings build() {
Preconditions.checkArgument(getChunkSize() > 0, "chunkSize must be > 0");
if (getGlobalTimeout() != null) {
Preconditions.checkArgument(
!getGlobalTimeout().isNegative() && !getGlobalTimeout().isZero(),
"globalTimeout must be positive");
}
return autoBuild();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,47 +31,88 @@

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;

import java.time.Duration;
import org.junit.jupiter.api.Test;

public class ResumableUploadCallSettingsTest {

@Test
public void testDefaultChunkSizeInBuilder() {
ResumableUploadCallSettings settings = ResumableUploadCallSettings.newBuilder().build();
public void testCustomSettingsAndToBuilder() {
ResumableUploadCallSettings settings =
ResumableUploadCallSettings.newBuilder()
.setChunkSize(16 * 1024 * 1024)
.setGlobalTimeout(Duration.ofMinutes(15))
.build();

assertEquals(16 * 1024 * 1024, settings.getChunkSize());
assertEquals(Duration.ofMinutes(15), settings.getGlobalTimeout());
assertEquals(settings, settings.toBuilder().build());
}

assertEquals(8 * 1024 * 1024, settings.getChunkSize());
@Test
public void testInvalidChunkSize_throwsIllegalArgumentException() {
assertThrows(

Check warning on line 56 in sdk-platform-java/gax-java/gax/src/test/java/com/google/api/gax/rpc/ResumableUploadCallSettingsTest.java

View check run for this annotation

SonarQubeCloud / [gapic-generator-java-root] SonarCloud Code Analysis

Refactor the code of the lambda to have only one invocation possibly throwing a runtime exception.

See more on https://sonarcloud.io/project/issues?id=googleapis_google-cloud-java_showcase&issues=AaBumadI4VFARgn-a4gc&open=AaBumadI4VFARgn-a4gc&pullRequest=14253
IllegalArgumentException.class,
() -> ResumableUploadCallSettings.newBuilder().setChunkSize(0).build());
assertThrows(

Check warning on line 59 in sdk-platform-java/gax-java/gax/src/test/java/com/google/api/gax/rpc/ResumableUploadCallSettingsTest.java

View check run for this annotation

SonarQubeCloud / [gapic-generator-java-root] SonarCloud Code Analysis

Refactor the code of the lambda to have only one invocation possibly throwing a runtime exception.

See more on https://sonarcloud.io/project/issues?id=googleapis_google-cloud-java_showcase&issues=AaBumadI4VFARgn-a4gd&open=AaBumadI4VFARgn-a4gd&pullRequest=14253
IllegalArgumentException.class,
() -> ResumableUploadCallSettings.newBuilder().setChunkSize(-1).build());
}

@Test
public void testInvalidGlobalTimeout_throwsIllegalArgumentException() {
assertThrows(

Check warning on line 66 in sdk-platform-java/gax-java/gax/src/test/java/com/google/api/gax/rpc/ResumableUploadCallSettingsTest.java

View check run for this annotation

SonarQubeCloud / [gapic-generator-java-root] SonarCloud Code Analysis

Refactor the code of the lambda to have only one invocation possibly throwing a runtime exception.

See more on https://sonarcloud.io/project/issues?id=googleapis_google-cloud-java_showcase&issues=AaBumadI4VFARgn-a4ge&open=AaBumadI4VFARgn-a4ge&pullRequest=14253
IllegalArgumentException.class,
() -> ResumableUploadCallSettings.newBuilder().setGlobalTimeout(Duration.ZERO).build());
assertThrows(

Check warning on line 69 in sdk-platform-java/gax-java/gax/src/test/java/com/google/api/gax/rpc/ResumableUploadCallSettingsTest.java

View check run for this annotation

SonarQubeCloud / [gapic-generator-java-root] SonarCloud Code Analysis

Refactor the code of the lambda to have only one invocation possibly throwing a runtime exception.

See more on https://sonarcloud.io/project/issues?id=googleapis_google-cloud-java_showcase&issues=AaBumadI4VFARgn-a4gf&open=AaBumadI4VFARgn-a4gf&pullRequest=14253
IllegalArgumentException.class,
() ->
ResumableUploadCallSettings.newBuilder()
.setGlobalTimeout(Duration.ofSeconds(-5))
.build());
}

@Test
public void testCustomInitialization() {
public void testMerge_nullSettings_returnsSameInstance() {
ResumableUploadCallSettings settings =
ResumableUploadCallSettings.newBuilder().setChunkSize(16 * 1024 * 1024).build();
ResumableUploadCallSettings.newBuilder().setChunkSize(4 * 1024 * 1024).build();

assertEquals(16 * 1024 * 1024, settings.getChunkSize());
assertSame(settings, settings.merge(null));
}

@Test
public void testMerge_NullSettings() {
public void testMerge_overridesChunkSizeAndGlobalTimeout() {
ResumableUploadCallSettings stubSettings =
ResumableUploadCallSettings.newBuilder().setChunkSize(4 * 1024 * 1024).build();
ResumableUploadCallSettings.newBuilder()
.setChunkSize(4 * 1024 * 1024)
.setGlobalTimeout(Duration.ofMinutes(10))
.build();

ResumableUploadCallSettings perRequestSettings =
ResumableUploadCallSettings.newBuilder()
.setChunkSize(32 * 1024 * 1024)
.setGlobalTimeout(Duration.ofMinutes(30))
.build();

ResumableUploadCallSettings merged = stubSettings.merge(null);
ResumableUploadCallSettings merged = stubSettings.merge(perRequestSettings);

assertSame(stubSettings, merged);
assertEquals(32 * 1024 * 1024, merged.getChunkSize());
assertEquals(Duration.ofMinutes(30), merged.getGlobalTimeout());
}

@Test
public void testMerge_SettingsOverrides() {
public void testMerge_nullGlobalTimeoutDoesNotOverride() {
ResumableUploadCallSettings stubSettings =
ResumableUploadCallSettings.newBuilder().setChunkSize(4 * 1024 * 1024).build();
ResumableUploadCallSettings.newBuilder().setGlobalTimeout(Duration.ofMinutes(10)).build();

ResumableUploadCallSettings perRequestSettings =
ResumableUploadCallSettings.newBuilder().setChunkSize(32 * 1024 * 1024).build();

ResumableUploadCallSettings merged = stubSettings.merge(perRequestSettings);

// Chunk size overridden by Tier-1 per-request settings
assertEquals(32 * 1024 * 1024, merged.getChunkSize());
assertEquals(Duration.ofMinutes(10), merged.getGlobalTimeout());
}
}
Loading