From a645997839b7974d50e74ad2f4a8ab065c8478a3 Mon Sep 17 00:00:00 2001 From: BenWhitehead Date: Tue, 25 Jun 2024 12:12:44 -0400 Subject: [PATCH] fix: update CloudStorageFileSystemProvider#getFileAttributeView to return null rather than throw UnsupportedOperationException 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...) --- .../nio/CloudStorageFileSystemProvider.java | 6 ++- .../CloudStorageFileSystemProviderTest.java | 37 ++++++++++++++----- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemProvider.java b/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemProvider.java index c6f172710..e854fed15 100644 --- a/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemProvider.java +++ b/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemProvider.java @@ -1020,7 +1020,11 @@ public V getFileAttributeView( 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") diff --git a/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemProviderTest.java b/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemProviderTest.java index 7f6bc0df8..e0dc54f88 100644 --- a/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemProviderTest.java +++ b/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemProviderTest.java @@ -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; @@ -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; @@ -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 FILE_CONTENTS = ImmutableList.of( @@ -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(); @@ -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 @@ -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 @@ -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 @@ -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 @@ -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(); } @@ -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(); } @@ -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"))) {