Skip to content

Commit 309ff68

Browse files
committed
Fix fixture bug when writing files that are a multiple of the chunk size
1 parent 9cc696a commit 309ff68

File tree

2 files changed

+36
-17
lines changed

2 files changed

+36
-17
lines changed

modules/repository-gcs/src/internalClusterTest/java/org/elasticsearch/repositories/gcs/GoogleCloudStorageBlobStoreRepositoryTests.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.elasticsearch.common.blobstore.BlobPath;
3131
import org.elasticsearch.common.blobstore.BlobStore;
3232
import org.elasticsearch.common.bytes.BytesArray;
33+
import org.elasticsearch.common.bytes.BytesReference;
3334
import org.elasticsearch.common.collect.Iterators;
3435
import org.elasticsearch.common.io.Streams;
3536
import org.elasticsearch.common.regex.Regex;
@@ -59,6 +60,7 @@
5960
import java.util.regex.Matcher;
6061
import java.util.regex.Pattern;
6162

63+
import static org.elasticsearch.common.io.Streams.readFully;
6264
import static org.elasticsearch.repositories.blobstore.BlobStoreTestUtil.randomPurpose;
6365
import static org.elasticsearch.repositories.gcs.GoogleCloudStorageClientSettings.CREDENTIALS_FILE_SETTING;
6466
import static org.elasticsearch.repositories.gcs.GoogleCloudStorageClientSettings.ENDPOINT_SETTING;
@@ -206,6 +208,21 @@ public void testWriteReadLarge() throws IOException {
206208
}
207209
}
208210

211+
public void testWriteFileMultipleOfChunkSize() throws IOException {
212+
final int uploadSize = randomIntBetween(2, 4) * GoogleCloudStorageBlobStore.SDK_DEFAULT_CHUNK_SIZE;
213+
try (BlobStore store = newBlobStore()) {
214+
final BlobContainer container = store.blobContainer(BlobPath.EMPTY);
215+
final String key = randomIdentifier();
216+
byte[] initialValue = randomByteArrayOfLength(uploadSize);
217+
container.writeBlob(randomPurpose(), key, new BytesArray(initialValue), true);
218+
219+
BytesReference reference = readFully(container.readBlob(randomPurpose(), key));
220+
assertEquals(new BytesArray(initialValue), reference);
221+
222+
container.deleteBlobsIgnoringIfNotExists(randomPurpose(), Iterators.single(key));
223+
}
224+
}
225+
209226
public static class TestGoogleCloudStoragePlugin extends GoogleCloudStoragePlugin {
210227

211228
public TestGoogleCloudStoragePlugin(Settings settings) {

test/fixtures/gcs-fixture/src/main/java/fixture/gcs/MockGcsBlobStore.java

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -114,16 +114,14 @@ UpdateResponse updateResumableUpload(String uploadId, HttpHeaderParser.ContentRa
114114
throw failAndThrow("Attempted to update a non-existent resumable: " + uid);
115115
}
116116

117-
if (contentRange.hasRange() == false) {
118-
// Content-Range: */... is a status check https://cloud.google.com/storage/docs/performing-resumable-uploads#status-check
117+
ResumableUpload valueToReturn = existing;
118+
119+
// Handle the request, a range indicates a chunk of data was submitted
120+
if (contentRange.hasRange()) {
119121
if (existing.completed) {
120-
updateResponse.set(new UpdateResponse(RestStatus.OK.getStatus(), calculateRangeHeader(blobs.get(existing.path))));
121-
} else {
122-
final HttpHeaderParser.Range range = calculateRangeHeader(existing);
123-
updateResponse.set(new UpdateResponse(RESUME_INCOMPLETE, range));
122+
throw failAndThrow("Attempted to write more to a completed resumable upload");
124123
}
125-
return existing;
126-
} else {
124+
127125
if (contentRange.start() > contentRange.end()) {
128126
throw failAndThrow("Invalid content range " + contentRange);
129127
}
@@ -143,16 +141,20 @@ UpdateResponse updateResumableUpload(String uploadId, HttpHeaderParser.ContentRa
143141
existing.contents,
144142
requestBody.slice(offset, requestBody.length())
145143
);
146-
// We just received the last chunk, update the blob and remove the resumable upload from the map
147-
if (contentRange.hasSize() && updatedContent.length() == contentRange.size()) {
148-
updateBlob(existing.path(), existing.ifGenerationMatch, updatedContent);
149-
updateResponse.set(new UpdateResponse(RestStatus.OK.getStatus(), null));
150-
return existing.update(BytesArray.EMPTY, true);
151-
}
152-
final ResumableUpload updated = existing.update(updatedContent, false);
153-
updateResponse.set(new UpdateResponse(RESUME_INCOMPLETE, calculateRangeHeader(updated)));
154-
return updated;
144+
valueToReturn = existing.update(updatedContent, false);
145+
}
146+
147+
// Next we determine the response
148+
if (valueToReturn.completed) {
149+
updateResponse.set(new UpdateResponse(RestStatus.OK.getStatus(), calculateRangeHeader(valueToReturn)));
150+
} else if (contentRange.hasSize() && contentRange.size() == valueToReturn.contents.length()) {
151+
valueToReturn = existing.update(valueToReturn.contents, true);
152+
updateBlob(valueToReturn.path(), valueToReturn.ifGenerationMatch(), valueToReturn.contents);
153+
updateResponse.set(new UpdateResponse(RestStatus.OK.getStatus(), calculateRangeHeader(valueToReturn)));
154+
} else {
155+
updateResponse.set(new UpdateResponse(RESUME_INCOMPLETE, calculateRangeHeader(valueToReturn)));
155156
}
157+
return valueToReturn;
156158
});
157159
assert updateResponse.get() != null : "Should always produce an update response";
158160
return updateResponse.get();

0 commit comments

Comments
 (0)