Skip to content

Commit 33889c3

Browse files
authored
fix: change CloudStorageFileSystemProvider to throw a FileAlreadyExistsException if copy receives a 412 (#815)
1 parent e103795 commit 33889c3

File tree

2 files changed

+67
-3
lines changed

2 files changed

+67
-3
lines changed

google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemProvider.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ private SeekableByteChannel newWriteChannel(Path path, Set<? extends OpenOption>
468468
infoBuilder.build(),
469469
writeOptions.toArray(new Storage.BlobWriteOption[writeOptions.size()])));
470470
} catch (StorageException oops) {
471-
throw asIoException(oops);
471+
throw asIoException(oops, false);
472472
}
473473
}
474474

@@ -688,7 +688,7 @@ public void copy(Path source, Path target, CopyOption... options) throws IOExcep
688688
retryHandler.handleStorageException(oops);
689689
// we're being aggressive by retrying even on scenarios where we'd normally reopen.
690690
} catch (StorageException retriesExhaustedException) {
691-
throw asIoException(retriesExhaustedException);
691+
throw asIoException(retriesExhaustedException, true);
692692
}
693693
}
694694
}
@@ -1013,12 +1013,18 @@ Page<Bucket> listBuckets(Storage.BucketListOption... options) {
10131013
return storage.list(options);
10141014
}
10151015

1016-
private IOException asIoException(StorageException oops) {
1016+
private IOException asIoException(StorageException oops, boolean operationWasCopy) {
10171017
// RPC API can only throw StorageException, but CloudStorageFileSystemProvider
10181018
// can only throw IOException. Square peg, round hole.
10191019
// TODO(#810): Research if other codes should be translated similarly.
10201020
if (oops.getCode() == 404) {
10211021
return new NoSuchFileException(oops.getReason());
1022+
} else if (operationWasCopy && oops.getCode() == 412) {
1023+
return new FileAlreadyExistsException(
1024+
String.format(
1025+
"Copy failed for reason '%s'. This most likely means the destination already exists"
1026+
+ " and java.nio.file.StandardCopyOption.REPLACE_EXISTING was not specified.",
1027+
oops.getReason()));
10221028
}
10231029

10241030
Throwable cause = oops.getCause();

google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/it/ITGcsNio.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import java.nio.channels.FileChannel;
5454
import java.nio.channels.ReadableByteChannel;
5555
import java.nio.channels.SeekableByteChannel;
56+
import java.nio.file.FileAlreadyExistsException;
5657
import java.nio.file.FileSystem;
5758
import java.nio.file.FileVisitResult;
5859
import java.nio.file.Files;
@@ -1108,6 +1109,63 @@ public void testListObject() throws IOException {
11081109
assertThat(objects.size()).isEqualTo(1);
11091110
}
11101111

1112+
@Test(expected = FileAlreadyExistsException.class)
1113+
public void testCopy_replaceFile_withoutOption() throws IOException {
1114+
CloudStorageFileSystem fs = getTestBucket();
1115+
String uuid = UUID.randomUUID().toString();
1116+
1117+
CloudStoragePath foo = fs.getPath(uuid, "foo.txt");
1118+
CloudStoragePath bar = fs.getPath(uuid, "bar.txt");
1119+
1120+
try {
1121+
Files.createFile(foo);
1122+
Files.createFile(bar);
1123+
1124+
Files.copy(foo, bar);
1125+
} finally {
1126+
Files.deleteIfExists(foo);
1127+
Files.deleteIfExists(bar);
1128+
}
1129+
}
1130+
1131+
@Test
1132+
public void testCopy_replaceFile_withOption() throws IOException {
1133+
CloudStorageFileSystem fs = getTestBucket();
1134+
String uuid = UUID.randomUUID().toString();
1135+
1136+
CloudStoragePath foo = fs.getPath(uuid, "foo.txt");
1137+
CloudStoragePath bar = fs.getPath(uuid, "bar.txt");
1138+
1139+
try {
1140+
Files.createFile(foo);
1141+
Files.createFile(bar);
1142+
1143+
Files.copy(foo, bar, StandardCopyOption.REPLACE_EXISTING);
1144+
} finally {
1145+
Files.deleteIfExists(foo);
1146+
Files.deleteIfExists(bar);
1147+
}
1148+
}
1149+
1150+
@Test(expected = NoSuchFileException.class)
1151+
public void testCopy_replaceFile_withOption_srcDoesNotExist() throws IOException {
1152+
CloudStorageFileSystem fs = getTestBucket();
1153+
String uuid = UUID.randomUUID().toString();
1154+
1155+
CloudStoragePath foo = fs.getPath(uuid, "foo.txt");
1156+
CloudStoragePath bar = fs.getPath(uuid, "bar.txt");
1157+
1158+
try {
1159+
// explicitly do not create foo
1160+
Files.createFile(bar);
1161+
1162+
Files.copy(foo, bar);
1163+
} finally {
1164+
Files.deleteIfExists(foo);
1165+
Files.deleteIfExists(bar);
1166+
}
1167+
}
1168+
11111169
private CloudStorageFileSystem getTestBucket() throws IOException {
11121170
// in typical usage we use the single-argument version of forBucket
11131171
// and rely on the user being logged into their project with the

0 commit comments

Comments
 (0)