Skip to content

Commit

Permalink
fix: update CloudStorageFileSystemProvider#getFileAttributeView to re…
Browse files Browse the repository at this point in the history
…turn null rather than throw UnsupportedOperationException (#1427)

Currently, when CloudStorageFileSystemProvider#getFileAttributeView is invoked with a class it doesn't recognize it throws an UnsupportedOperationException. The javadocs for FileSystemProvider, however specify that #getFileAttributeView[1] return null if the attribute view type is not available.

This change updates the behavior of CloudStorageFileSystemProvider#getFileAttributeView to return null rather than throw an exception.

Fixes #1424

[1] https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/nio/file/spi/FileSystemProvider.html#getFileAttributeView(java.nio.file.Path,java.lang.Class,java.nio.file.LinkOption...)
  • Loading branch information
BenWhitehead committed Jun 25, 2024
1 parent 0d7429a commit b9e0362
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1017,10 +1017,15 @@ public String toString() {
@Override
public <V extends FileAttributeView> V getFileAttributeView(
Path path, Class<V> type, LinkOption... options) {
checkNotNull(path);
checkNotNull(type);
CloudStorageUtil.checkNotNullArray(options);
if (type != CloudStorageFileAttributeView.class && type != BasicFileAttributeView.class) {
throw new UnsupportedOperationException(type.getSimpleName());
// the javadocs for getFileAttributeView specify the following for @return
// a file attribute view of the specified type, or null if the attribute view type is not
// available
// Similar type of issue from the JDK itself https://bugs.openjdk.org/browse/JDK-8273935
return null;
}
CloudStoragePath cloudPath = CloudStorageUtil.checkPath(path);
@SuppressWarnings("unchecked")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static com.google.cloud.storage.contrib.nio.CloudStorageFileSystem.forBucket;
import static com.google.common.truth.Truth.assertThat;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.nio.file.Files.readAllBytes;
import static java.nio.file.StandardCopyOption.ATOMIC_MOVE;
import static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
Expand All @@ -36,7 +37,6 @@
import com.google.cloud.storage.Acl;
import com.google.cloud.storage.Acl.User;
import com.google.cloud.storage.contrib.nio.testing.LocalStorageHelper;
import com.google.cloud.testing.junit4.MultipleAttemptsRule;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.testing.NullPointerTester;
Expand Down Expand Up @@ -71,13 +71,17 @@
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Unit tests for {@link CloudStorageFileSystemProvider}. */
@RunWith(JUnit4.class)
public class CloudStorageFileSystemProviderTest {
@Rule public final MultipleAttemptsRule multipleAttemptsRule = new MultipleAttemptsRule(3);
// @Rule(order = 1) public final MultipleAttemptsRule multipleAttemptsRule = new
// MultipleAttemptsRule(3);
@Rule(order = 1)
public final TemporaryFolder temporaryFolder = new TemporaryFolder();

private static final List<String> FILE_CONTENTS =
ImmutableList.of(
Expand Down Expand Up @@ -153,14 +157,14 @@ public void testSize_trailingSlash_disablePseudoDirectories() throws Exception {
public void testReadAllBytes() throws Exception {
Path path = Paths.get(URI.create("gs://bucket/wat"));
Files.write(path, SINGULARITY.getBytes(UTF_8));
assertThat(new String(Files.readAllBytes(path), UTF_8)).isEqualTo(SINGULARITY);
assertThat(new String(readAllBytes(path), UTF_8)).isEqualTo(SINGULARITY);
Files.delete(path);
}

@Test
public void testReadAllBytes_trailingSlash() throws Exception {
try {
Files.readAllBytes(Paths.get(URI.create("gs://bucket/wat/")));
readAllBytes(Paths.get(URI.create("gs://bucket/wat/")));
Assert.fail();
} catch (CloudStoragePseudoDirectoryException ex) {
assertThat(ex.getMessage()).isNotNull();
Expand Down Expand Up @@ -255,7 +259,7 @@ public void testNewByteChannelWrite() throws Exception {
assertThat(output.position()).isEqualTo(10);
assertThat(output.size()).isEqualTo(10);
}
assertThat(new String(Files.readAllBytes(path), UTF_8)).isEqualTo("fileconten");
assertThat(new String(readAllBytes(path), UTF_8)).isEqualTo("fileconten");
}

@Test
Expand Down Expand Up @@ -298,7 +302,7 @@ public void testNewOutputStream() throws Exception {
try (OutputStream output = Files.newOutputStream(path)) {
output.write(SINGULARITY.getBytes(UTF_8));
}
assertThat(new String(Files.readAllBytes(path), UTF_8)).isEqualTo(SINGULARITY);
assertThat(new String(readAllBytes(path), UTF_8)).isEqualTo(SINGULARITY);
}

@Test
Expand All @@ -309,7 +313,7 @@ public void testNewOutputStream_truncateByDefault() throws Exception {
try (OutputStream output = Files.newOutputStream(path)) {
output.write(SINGULARITY.getBytes(UTF_8));
}
assertThat(new String(Files.readAllBytes(path), UTF_8)).isEqualTo(SINGULARITY);
assertThat(new String(readAllBytes(path), UTF_8)).isEqualTo(SINGULARITY);
}

@Test
Expand All @@ -320,7 +324,7 @@ public void testNewOutputStream_truncateExplicitly() throws Exception {
try (OutputStream output = Files.newOutputStream(path, TRUNCATE_EXISTING)) {
output.write(SINGULARITY.getBytes(UTF_8));
}
assertThat(new String(Files.readAllBytes(path), UTF_8)).isEqualTo(SINGULARITY);
assertThat(new String(readAllBytes(path), UTF_8)).isEqualTo(SINGULARITY);
}

@Test
Expand Down Expand Up @@ -577,7 +581,7 @@ public void testCopy() throws Exception {
Path target = Paths.get(URI.create("gs://greenbean/adipose"));
Files.write(source, "(✿◕ ‿◕ )ノ".getBytes(UTF_8));
Files.copy(source, target);
assertThat(new String(Files.readAllBytes(target), UTF_8)).isEqualTo("(✿◕ ‿◕ )ノ");
assertThat(new String(readAllBytes(target), UTF_8)).isEqualTo("(✿◕ ‿◕ )ノ");
assertThat(Files.exists(source)).isTrue();
assertThat(Files.exists(target)).isTrue();
}
Expand Down Expand Up @@ -641,7 +645,7 @@ public void testMove() throws Exception {
Path target = Paths.get(URI.create("gs://greenbean/adipose"));
Files.write(source, "(✿◕ ‿◕ )ノ".getBytes(UTF_8));
Files.move(source, target);
assertThat(new String(Files.readAllBytes(target), UTF_8)).isEqualTo("(✿◕ ‿◕ )ノ");
assertThat(new String(readAllBytes(target), UTF_8)).isEqualTo("(✿◕ ‿◕ )ノ");
assertThat(Files.exists(source)).isFalse();
assertThat(Files.exists(target)).isTrue();
}
Expand Down Expand Up @@ -763,6 +767,19 @@ public void testCopy_overwriteAttributes() throws Exception {
Files.delete(target2);
}

@Test
public void testCopy_path_toLocalFileSystem() throws IOException {
Path source = Paths.get(URI.create("gs://mybucket/myobject"));
byte[] helloWorldBytes = "Hello, World!".getBytes(UTF_8);
Files.write(source, helloWorldBytes);

Path path = temporaryFolder.newFile().toPath();
// The new file created by temporaryFolder is an empty file on disk, specify REPLACE_EXISTING
// so we can overwrite its contents.
Files.copy(source, path, REPLACE_EXISTING);
assertThat(Files.readAllBytes(path)).isEqualTo(helloWorldBytes);
}

@Test
public void testNullness() throws Exception {
try (FileSystem fs = FileSystems.getFileSystem(URI.create("gs://blood"))) {
Expand Down

0 comments on commit b9e0362

Please sign in to comment.