diff --git a/gcloud-java-contrib/gcloud-java-nio/pom.xml b/gcloud-java-contrib/gcloud-java-nio/pom.xml index b3c2a99eea10..099ce0d470e6 100644 --- a/gcloud-java-contrib/gcloud-java-nio/pom.xml +++ b/gcloud-java-contrib/gcloud-java-nio/pom.xml @@ -1,7 +1,6 @@ 4.0.0 - com.google.gcloud gcloud-java-nio jar GCloud Java NIO @@ -37,18 +36,40 @@ javax.inject 1 - - com.google.auto.service - auto-service - 1.0-rc2 - provided - com.google.auto.value auto-value 1.1 provided + + com.google.auto.factory + auto-factory + 1.0-beta3 + provided + + + com.google.guava + guava + + + + + com.google.auto.service + auto-service + 1.0-rc2 + provided + + + com.google.guava + guava + + + com.google.auto + auto-common + + + junit junit diff --git a/gcloud-java-contrib/gcloud-java-nio/src/main/java/com/google/gcloud/storage/contrib/nio/CloudStorageConfiguration.java b/gcloud-java-contrib/gcloud-java-nio/src/main/java/com/google/gcloud/storage/contrib/nio/CloudStorageConfiguration.java index 5d92c8e2063e..80c00b9f0dc1 100644 --- a/gcloud-java-contrib/gcloud-java-nio/src/main/java/com/google/gcloud/storage/contrib/nio/CloudStorageConfiguration.java +++ b/gcloud-java-contrib/gcloud-java-nio/src/main/java/com/google/gcloud/storage/contrib/nio/CloudStorageConfiguration.java @@ -19,43 +19,26 @@ import static com.google.common.base.Preconditions.checkArgument; import com.google.auto.value.AutoValue; +import com.google.common.base.Strings; import java.util.Map; +import javax.annotation.Nullable; + /** * Configuration for {@link CloudStorageFileSystem} instances. */ @AutoValue public abstract class CloudStorageConfiguration { - /** - * Returns path of current working directory. This defaults to the root directory. - */ - public abstract String workingDirectory(); - - /** - * Returns {@code true} if we shouldn't throw an exception when encountering object names - * containing superfluous slashes, e.g. {@code a//b}. - */ - public abstract boolean permitEmptyPathComponents(); - - /** - * Returns {@code true} if '/' prefix on absolute object names should be removed before I/O. - * - *

If you disable this feature, please take into consideration that all paths created from a - * URI will have the leading slash. - */ - public abstract boolean stripPrefixSlash(); - - /** - * Returns {@code true} if paths with a trailing slash should be treated as fake directories. - */ - public abstract boolean usePseudoDirectories(); + private static final CloudStorageConfiguration DEFAULT = builder().build(); /** - * Returns block size (in bytes) used when talking to the GCS HTTP server. + * Returns default GCS NIO configuration. */ - public abstract int blockSize(); + public static CloudStorageConfiguration defaultInstance() { + return DEFAULT; + } /** * Creates a new builder, initialized with the following settings: @@ -70,22 +53,33 @@ public static Builder builder() { return new Builder(); } + abstract String workingDirectory(); + + abstract boolean permitEmptyPathComponents(); + + abstract boolean stripPrefixSlash(); + + abstract boolean usePseudoDirectories(); + + abstract int blockSize(); + /** * Builder for {@link CloudStorageConfiguration}. */ public static final class Builder { private String workingDirectory = UnixPath.ROOT; - private boolean permitEmptyPathComponents = false; + private boolean permitEmptyPathComponents; private boolean stripPrefixSlash = true; private boolean usePseudoDirectories = true; private int blockSize = CloudStorageFileSystem.BLOCK_SIZE_DEFAULT; /** - * Changes current working directory for new filesystem. This cannot be changed once it's - * been set. You'll need to create another {@link CloudStorageFileSystem} object. + * Changes current working directory for new filesystem. This defaults to the root directory. + * The working directory cannot be changed once it's been set. You'll need to create another + * {@link CloudStorageFileSystem} object. * - * @throws IllegalArgumentException if {@code path} is not absolute. + * @throws IllegalArgumentException if {@code path} is not absolute */ public Builder workingDirectory(String path) { checkArgument(UnixPath.getPath(false, path).isAbsolute(), "not absolute: %s", path); @@ -95,7 +89,7 @@ public Builder workingDirectory(String path) { /** * Configures whether or not we should throw an exception when encountering object names - * containing superfluous slashes, e.g. {@code a//b} + * containing superfluous slashes, e.g. {@code a//b}. */ public Builder permitEmptyPathComponents(boolean value) { permitEmptyPathComponents = value; @@ -146,15 +140,13 @@ public CloudStorageConfiguration build() { Builder() {} } - public static final CloudStorageConfiguration DEFAULT = builder().build(); - - static CloudStorageConfiguration fromMap(Map env) { + static CloudStorageConfiguration fromMap(@Nullable String workingDirectory, Map env) { Builder builder = builder(); + if (!Strings.isNullOrEmpty(workingDirectory)) { + builder.workingDirectory(workingDirectory); + } for (Map.Entry entry : env.entrySet()) { switch (entry.getKey()) { - case "workingDirectory": - builder.workingDirectory((String) entry.getValue()); - break; case "permitEmptyPathComponents": builder.permitEmptyPathComponents((Boolean) entry.getValue()); break; diff --git a/gcloud-java-contrib/gcloud-java-nio/src/main/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileSystem.java b/gcloud-java-contrib/gcloud-java-nio/src/main/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileSystem.java index aafb1c786ec9..29f2b7e29ca2 100644 --- a/gcloud-java-contrib/gcloud-java-nio/src/main/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileSystem.java +++ b/gcloud-java-contrib/gcloud-java-nio/src/main/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileSystem.java @@ -19,8 +19,11 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import com.google.auto.factory.AutoFactory; +import com.google.auto.factory.Provided; +import com.google.common.base.Predicates; import com.google.common.collect.ImmutableSet; -import com.google.gcloud.storage.StorageOptions; +import com.google.common.collect.Iterables; import java.io.IOException; import java.net.URI; @@ -32,11 +35,13 @@ import java.nio.file.WatchService; import java.nio.file.attribute.FileTime; import java.nio.file.attribute.UserPrincipalLookupService; +import java.nio.file.spi.FileSystemProvider; import java.util.Objects; import java.util.Set; +import java.util.logging.Logger; -import javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; +import javax.annotation.CheckReturnValue; +import javax.annotation.concurrent.ThreadSafe; /** * Google Cloud Storage {@link FileSystem} implementation. @@ -46,49 +51,62 @@ * @see * Bucket and Object Naming Guidelines */ -@Immutable +@ThreadSafe public final class CloudStorageFileSystem extends FileSystem { + private static final Logger logger = Logger.getLogger(CloudStorageFileSystem.class.getName()); + /** - * Returns Google Cloud Storage {@link FileSystem} object for {@code bucket}. - * - *

NOTE: You may prefer to use Java's standard API instead:

   {@code
-   *
-   *   FileSystem fs = FileSystems.getFileSystem(URI.create("gs://bucket"));}
- * - *

However some systems and build environments might be flaky when it comes to Java SPI. This - * is because services are generally runtime dependencies and depend on a META-INF file being - * present in your jar (generated by Google Auto at compile-time). In such cases, this method - * provides a simpler alternative. - * - * @see #forBucket(String, CloudStorageConfiguration) - * @see java.nio.file.FileSystems#getFileSystem(URI) + * Invokes {@link #forBucket(String, CloudStorageConfiguration)} with + * {@link CloudStorageConfiguration#defaultInstance()}. */ + @CheckReturnValue public static CloudStorageFileSystem forBucket(String bucket) { - return forBucket(bucket, CloudStorageConfiguration.DEFAULT); + return forBucket(bucket, CloudStorageConfiguration.defaultInstance()); } /** - * Creates new file system instance for {@code bucket}, with customizable settings. + * Returns Google Cloud Storage {@link FileSystem} object for {@code bucket}. + * + *

GCS file system objects are basically free. You can create as many as you want, even if you + * have multiple instances for the same bucket. There's no actual system resources associated + * with this object. Therefore calling {@link #close()} on the returned value is optional. * - * @see #forBucket(String) + *

Note: It is also possible to instantiate this class via Java's Service Provider + * Interface, e.g. {@code FileSystems.getFileSystem(URI.create("gs://bucket"))}. We discourage you + * from using that if possible, for the reasons documented in + * {@link CloudStorageFileSystemProvider#newFileSystem(URI, java.util.Map)} + * + * @see java.nio.file.FileSystems#getFileSystem(URI) */ + @CheckReturnValue public static CloudStorageFileSystem forBucket(String bucket, CloudStorageConfiguration config) { - return forBucket(bucket, config, null); + checkNotNull(config); + checkArgument( + !bucket.startsWith(URI_SCHEME + ":"), "Bucket name must not have schema: %s", bucket); + return new CloudStorageFileSystem(getProvider(), config, bucket); } - /** - * Creates a new filesystem for a particular bucket, with customizable settings and storage - * options. - * - * @see #forBucket(String) - */ - public static CloudStorageFileSystem forBucket(String bucket, CloudStorageConfiguration config, - @Nullable StorageOptions storageOptions) { - checkArgument(!bucket.startsWith(URI_SCHEME + ":"), - "Bucket name must not have schema: %s", bucket); - return new CloudStorageFileSystem(new CloudStorageFileSystemProvider(storageOptions), - bucket, checkNotNull(config)); + private static CloudStorageFileSystemProvider getProvider() { + // We want to get the provider instance from the service loader if possible. This is important + // because the behavior of NIO (as implemented in classes like java.nio.files.Files) changes + // quite a bit if the provider instances aren't identical. + FileSystemProvider provider = + Iterables.getOnlyElement( + Iterables.filter( + FileSystemProvider.installedProviders(), + Predicates.instanceOf(CloudStorageFileSystemProvider.class)), + null); + if (provider != null) { + return (CloudStorageFileSystemProvider) provider; + } + // If the provider can not be found via the service loader, then we fall back to instantiating + // it ourselves. This should safeguard against needless user frustration in situations where the + // weird provider file created by @AutoService doesn't find its way into the jar. However this + // could lead to unexpected changes in behavior under the rare circumstance that the user + // instantiates multiple instances and uses them together on operations like copy. + logger.warning("Could not find CloudStorageFileSystemProvider via service loader"); + return new CloudStorageFileSystemProvider(); } public static final String URI_SCHEME = "gs"; @@ -98,12 +116,15 @@ public static CloudStorageFileSystem forBucket(String bucket, CloudStorageConfig public static final FileTime FILE_TIME_UNKNOWN = FileTime.fromMillis(0); public static final ImmutableSet SUPPORTED_VIEWS = ImmutableSet.of(BASIC_VIEW, GCS_VIEW); - private final CloudStorageFileSystemProvider provider; private final String bucket; + private final CloudStorageFileSystemProvider provider; private final CloudStorageConfiguration config; + @AutoFactory CloudStorageFileSystem( - CloudStorageFileSystemProvider provider, String bucket, CloudStorageConfiguration config) { + @Provided CloudStorageFileSystemProvider provider, + @Provided CloudStorageConfiguration config, + String bucket) { checkArgument(!bucket.isEmpty(), "bucket"); this.provider = provider; this.bucket = bucket; @@ -142,13 +163,17 @@ public CloudStoragePath getPath(String first, String... more) { } /** - * Does nothing. + * Does nothing currently. This method might be updated in the future to close all channels + * associated with this file system object. However it's unlikely that even then, calling this + * method will become mandatory. */ @Override - public void close() {} + public void close() throws IOException { + // TODO(#809): Synchronously close all channels associated with this FileSystem instance. + } /** - * Returns {@code true}. + * Returns {@code true}, even if you previously called the {@link #close()} method. */ @Override public boolean isOpen() { @@ -176,6 +201,9 @@ public Iterable getRootDirectories() { return ImmutableSet.of(CloudStoragePath.getPath(this, UnixPath.ROOT)); } + /** + * Returns nothing because GCS doesn't have disk partitions of limited size, or anything similar. + */ @Override public Iterable getFileStores() { return ImmutableSet.of(); @@ -191,7 +219,7 @@ public Set supportedFileAttributeViews() { */ @Override public PathMatcher getPathMatcher(String syntaxAndPattern) { - // TODO: Implement me. + // TODO(#813): Implement me. throw new UnsupportedOperationException(); } diff --git a/gcloud-java-contrib/gcloud-java-nio/src/main/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileSystemProvider.java b/gcloud-java-contrib/gcloud-java-nio/src/main/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileSystemProvider.java index 4c07a5eb22fe..09fde9ef277f 100644 --- a/gcloud-java-contrib/gcloud-java-nio/src/main/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileSystemProvider.java +++ b/gcloud-java-contrib/gcloud-java-nio/src/main/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileSystemProvider.java @@ -26,9 +26,7 @@ import static com.google.gcloud.storage.contrib.nio.CloudStorageUtil.stripPathFromUri; import com.google.auto.service.AutoService; -import com.google.common.annotations.VisibleForTesting; import com.google.common.base.MoreObjects; -import com.google.common.base.Throwables; import com.google.common.primitives.Ints; import com.google.gcloud.storage.Acl; import com.google.gcloud.storage.BlobId; @@ -69,50 +67,37 @@ import java.util.Objects; import java.util.Set; -import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; +import javax.inject.Inject; +import javax.inject.Singleton; /** * Google Cloud Storage {@link FileSystemProvider} implementation. + * + *

Note: This class should never be used directly. This class is instantiated by the + * service loader and called through a standardized API, e.g. {@link java.nio.file.Files}. However + * the javadocs in this class serve as useful documentation for the behavior of the GCS NIO library. */ +@Singleton @ThreadSafe @AutoService(FileSystemProvider.class) public final class CloudStorageFileSystemProvider extends FileSystemProvider { private final Storage storage; - // used only when we create a new instance of CloudStorageFileSystemProvider. - private static StorageOptions defaultStorageOptions; - - /** - * Sets default options that are only used by the constructor. - */ - @VisibleForTesting - public static void setGCloudOptions(StorageOptions newStorageOptions) { - defaultStorageOptions = newStorageOptions; + @Inject + CloudStorageFileSystemProvider(Storage storage) { + this.storage = storage; } /** - * Default constructor which should only be called by Java SPI. + * Constructs a new instance with the default options. * - * @see java.nio.file.FileSystems#getFileSystem(URI) - * @see CloudStorageFileSystem#forBucket(String) + *

Note: This should only be called by the Java service loader. Please use + * {@link CloudStorageFileSystem#forBucket(String, CloudStorageConfiguration)} instead. */ public CloudStorageFileSystemProvider() { - this(defaultStorageOptions); - } - - CloudStorageFileSystemProvider(@Nullable StorageOptions explicitOptions) { - // explicit options have priority over default options. - if (explicitOptions == null) { - if (defaultStorageOptions == null) { - this.storage = StorageOptions.defaultInstance().service(); - } else { - this.storage = defaultStorageOptions.service(); - } - } else { - this.storage = explicitOptions.service(); - } + this(StorageOptions.defaultInstance().service()); } @Override @@ -121,7 +106,7 @@ public String getScheme() { } /** - * Returns Cloud Storage file system, provided a URI with no path, e.g. {@code gs://bucket}. + * Calls {@link #newFileSystem(URI, Map)} with an empty configuration map. */ @Override public CloudStorageFileSystem getFileSystem(URI uri) { @@ -129,7 +114,21 @@ public CloudStorageFileSystem getFileSystem(URI uri) { } /** - * Returns Cloud Storage file system, provided a URI with no path, e.g. {@code gs://bucket}. + * Returns Cloud Storage file system, provided a URI with no path. + * + *

Note: This method should be invoked indirectly via the service provider by calling + * {@link java.nio.file.FileSystems#newFileSystem(URI, Map) FileSystems.newFileSystem()}; however, + * we recommend that you don't use the API if possible. The recommended approach is to write a + * dependency injection module that calls the statically-linked, type-safe version of this method: + * {@link CloudStorageFileSystem#forBucket(String, CloudStorageConfiguration)}. Please see that + * method for further documentation on creating GCS file systems. + * + * @param uri bucket and current working directory, e.g. {@code gs://bucket} + * @param env map of configuration options, whose keys correspond to the method names of + * {@link CloudStorageConfiguration.Builder}. However you are not allowed to set the working + * directory, as that should be provided in the {@code uri} + * @throws IllegalArgumentException if {@code uri} specifies a user, query, fragment, or scheme is + * not {@value CloudStorageFileSystem#URI_SCHEME} */ @Override public CloudStorageFileSystem newFileSystem(URI uri, Map env) { @@ -142,14 +141,14 @@ public CloudStorageFileSystem newFileSystem(URI uri, Map env) { !isNullOrEmpty(uri.getHost()), "%s:// URIs must have a host: %s", URI_SCHEME, uri); checkArgument( uri.getPort() == -1 - && isNullOrEmpty(uri.getPath()) && isNullOrEmpty(uri.getQuery()) && isNullOrEmpty(uri.getFragment()) && isNullOrEmpty(uri.getUserInfo()), "GCS FileSystem URIs mustn't have: port, userinfo, path, query, or fragment: %s", uri); checkBucket(uri.getHost()); - return new CloudStorageFileSystem(this, uri.getHost(), CloudStorageConfiguration.fromMap(env)); + return new CloudStorageFileSystem( + this, CloudStorageConfiguration.fromMap(uri.getPath(), env), uri.getHost()); } @Override @@ -503,9 +502,9 @@ public A readAttributes( @Override public Map readAttributes(Path path, String attributes, LinkOption... options) { - // Java 7 NIO defines at least eleven string attributes we'd want to support - // (eg. BasicFileAttributeView and PosixFileAttributeView), so rather than a partial - // implementation we rely on the other overload for now. + // TODO(#811): Java 7 NIO defines at least eleven string attributes we'd want to support (eg. + // BasicFileAttributeView and PosixFileAttributeView), so rather than a partial + // implementation we rely on the other overload for now. throw new UnsupportedOperationException(); } @@ -537,7 +536,7 @@ public void createDirectory(Path dir, FileAttribute... attrs) { */ @Override public DirectoryStream newDirectoryStream(Path dir, Filter filter) { - // TODO: Implement me. + // TODO(#813): Implement me. throw new UnsupportedOperationException(); } @@ -546,6 +545,7 @@ public DirectoryStream newDirectoryStream(Path dir, Filter f */ @Override public void setAttribute(Path path, String attribute, Object value, LinkOption... options) { + // TODO(#811): Implement me. throw new CloudStorageObjectImmutableException(); } @@ -575,23 +575,16 @@ public String toString() { } private IOException asIOException(StorageException oops) { + // RPC API can only throw StorageException, but CloudStorageFileSystemProvider + // can only throw IOException. Square peg, round hole. + // TODO(#810): Research if other codes should be translated similarly. if (oops.code() == 404) { return new NoSuchFileException(oops.reason()); } - // TODO: research if other codes should be translated to IOException. - - // RPC API can only throw StorageException, but CloudStorageFileSystemProvider - // can only throw IOException. Square peg, round hole. Throwable cause = oops.getCause(); - try { - if (cause instanceof FileAlreadyExistsException) { - throw new FileAlreadyExistsException(((FileAlreadyExistsException) cause).getReason()); - } - // fallback - Throwables.propagateIfInstanceOf(oops.getCause(), IOException.class); - } catch (IOException okEx) { - return okEx; + if (cause instanceof FileAlreadyExistsException) { + return (FileAlreadyExistsException) cause; } - return new IOException(oops.getMessage(), oops); + return new IOException("Storage operation failed", oops); } } diff --git a/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageConfigurationTest.java b/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageConfigurationTest.java index f3382188cc7c..9c98a9bd967d 100644 --- a/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageConfigurationTest.java +++ b/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageConfigurationTest.java @@ -55,8 +55,8 @@ public void testBuilder() { public void testFromMap() { CloudStorageConfiguration config = CloudStorageConfiguration.fromMap( + "/omg", new ImmutableMap.Builder() - .put("workingDirectory", "/omg") .put("permitEmptyPathComponents", true) .put("stripPrefixSlash", false) .put("usePseudoDirectories", false) @@ -72,6 +72,6 @@ public void testFromMap() { @Test public void testFromMap_badKey_throwsIae() { thrown.expect(IllegalArgumentException.class); - CloudStorageConfiguration.fromMap(ImmutableMap.of("lol", "/omg")); + CloudStorageConfiguration.fromMap(null, ImmutableMap.of("lol", "/omg")); } } diff --git a/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileAttributeViewTest.java b/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileAttributeViewTest.java index 9d9a65690bd8..e3bd7574c9c4 100644 --- a/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileAttributeViewTest.java +++ b/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileAttributeViewTest.java @@ -22,9 +22,8 @@ import com.google.common.testing.EqualsTester; import com.google.common.testing.NullPointerTester; -import com.google.gcloud.storage.testing.LocalGcsHelper; +import com.google.gcloud.storage.testing.FakeStorageRpc; -import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -32,11 +31,10 @@ import org.junit.runners.JUnit4; import java.io.IOException; -import java.net.URI; +import java.nio.file.FileSystem; import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.attribute.FileTime; /** @@ -49,67 +47,76 @@ public class CloudStorageFileAttributeViewTest { @Rule public final ExpectedException thrown = ExpectedException.none(); - private Path path; - - @Before - public void before() { - CloudStorageFileSystemProvider.setGCloudOptions(LocalGcsHelper.options()); - path = Paths.get(URI.create("gs://red/water")); - } + private final FakeStorageRpc storage = new FakeStorageRpc(true); + private final NioTestHelper helper = new NioTestHelper(storage); @Test public void testReadAttributes() throws IOException { - Files.write(path, HAPPY, withCacheControl("potato")); - CloudStorageFileAttributeView lazyAttributes = - Files.getFileAttributeView(path, CloudStorageFileAttributeView.class); - assertThat(lazyAttributes.readAttributes().cacheControl().get()).isEqualTo("potato"); + try (FileSystem fs = helper.forBucket("red")) { + Path path = fs.getPath("/water"); + Files.write(path, HAPPY, withCacheControl("potato")); + CloudStorageFileAttributeView lazyAttributes = + Files.getFileAttributeView(path, CloudStorageFileAttributeView.class); + assertThat(lazyAttributes.readAttributes().cacheControl().get()).isEqualTo("potato"); + } } @Test public void testReadAttributes_notFound_throwsNoSuchFileException() throws IOException { - CloudStorageFileAttributeView lazyAttributes = - Files.getFileAttributeView(path, CloudStorageFileAttributeView.class); - thrown.expect(NoSuchFileException.class); - lazyAttributes.readAttributes(); + try (FileSystem fs = helper.forBucket("red")) { + Path path = fs.getPath("/water"); + CloudStorageFileAttributeView lazyAttributes = + Files.getFileAttributeView(path, CloudStorageFileAttributeView.class); + thrown.expect(NoSuchFileException.class); + lazyAttributes.readAttributes(); + } } @Test public void testReadAttributes_pseudoDirectory() throws IOException { - Path dir = Paths.get(URI.create("gs://red/rum/")); - CloudStorageFileAttributeView lazyAttributes = - Files.getFileAttributeView(dir, CloudStorageFileAttributeView.class); - assertThat(lazyAttributes.readAttributes()) - .isInstanceOf(CloudStoragePseudoDirectoryAttributes.class); + try (FileSystem fs = helper.forBucket("red")) { + Path dir = fs.getPath("/rum/"); + CloudStorageFileAttributeView lazyAttributes = + Files.getFileAttributeView(dir, CloudStorageFileAttributeView.class); + assertThat(lazyAttributes.readAttributes()) + .isInstanceOf(CloudStoragePseudoDirectoryAttributes.class); + } } @Test public void testName() throws IOException { - Files.write(path, HAPPY, withCacheControl("potato")); - CloudStorageFileAttributeView lazyAttributes = - Files.getFileAttributeView(path, CloudStorageFileAttributeView.class); - assertThat(lazyAttributes.name()).isEqualTo("gcs"); + try (FileSystem fs = helper.forBucket("red")) { + Path path = fs.getPath("/water"); + Files.write(path, HAPPY, withCacheControl("potato")); + CloudStorageFileAttributeView lazyAttributes = + Files.getFileAttributeView(path, CloudStorageFileAttributeView.class); + assertThat(lazyAttributes.name()).isEqualTo("gcs"); + } } @Test - public void testEquals_equalsTester() { - new EqualsTester() - .addEqualityGroup( - Files.getFileAttributeView( - Paths.get(URI.create("gs://red/rum")), CloudStorageFileAttributeView.class), - Files.getFileAttributeView( - Paths.get(URI.create("gs://red/rum")), CloudStorageFileAttributeView.class)) - .addEqualityGroup( - Files.getFileAttributeView( - Paths.get(URI.create("gs://red/lol/dog")), CloudStorageFileAttributeView.class)) - .testEquals(); + public void testEquals_equalsTester() throws IOException { + try (FileSystem fs = helper.forBucket("red")) { + new EqualsTester() + .addEqualityGroup( + Files.getFileAttributeView(fs.getPath("/rum"), CloudStorageFileAttributeView.class), + Files.getFileAttributeView(fs.getPath("/rum"), CloudStorageFileAttributeView.class)) + .addEqualityGroup( + Files.getFileAttributeView( + fs.getPath("/lol/dog"), CloudStorageFileAttributeView.class)) + .testEquals(); + } } @Test - public void testNullness() throws NoSuchMethodException, SecurityException { - new NullPointerTester() - .ignore(CloudStorageFileAttributeView.class.getMethod("equals", Object.class)) - .setDefault(FileTime.class, FileTime.fromMillis(0)) - .testAllPublicInstanceMethods( - Files.getFileAttributeView(path, CloudStorageFileAttributeView.class)); + public void testNullness() throws NoSuchMethodException, SecurityException, IOException { + try (FileSystem fs = helper.forBucket("red")) { + Path path = fs.getPath("/water"); + new NullPointerTester() + .ignore(CloudStorageFileAttributeView.class.getMethod("equals", Object.class)) + .setDefault(FileTime.class, FileTime.fromMillis(0)) + .testAllPublicInstanceMethods( + Files.getFileAttributeView(path, CloudStorageFileAttributeView.class)); + } } } diff --git a/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileAttributesTest.java b/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileAttributesTest.java index 38ee4020dbcb..a1e82550ec37 100644 --- a/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileAttributesTest.java +++ b/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileAttributesTest.java @@ -28,18 +28,16 @@ import com.google.common.testing.EqualsTester; import com.google.common.testing.NullPointerTester; import com.google.gcloud.storage.Acl; -import com.google.gcloud.storage.testing.LocalGcsHelper; +import com.google.gcloud.storage.testing.FakeStorageRpc; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.io.IOException; -import java.net.URI; +import java.nio.file.FileSystem; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; /** * Unit tests for {@link CloudStorageFileAttributes}. @@ -49,137 +47,178 @@ public class CloudStorageFileAttributesTest { private static final byte[] HAPPY = "(✿◕ ‿◕ )ノ".getBytes(UTF_8); - private Path path; - private Path dir; - - @Before - public void before() { - CloudStorageFileSystemProvider.setGCloudOptions(LocalGcsHelper.options()); - path = Paths.get(URI.create("gs://bucket/randompath")); - dir = Paths.get(URI.create("gs://bucket/randompath/")); - } + private final FakeStorageRpc storage = new FakeStorageRpc(true); + private final NioTestHelper helper = new NioTestHelper(storage); @Test public void testCacheControl() throws IOException { - Files.write(path, HAPPY, withCacheControl("potato")); - assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).cacheControl().get()) - .isEqualTo("potato"); + try (FileSystem fs = helper.forBucket("red")) { + Path path = fs.getPath("/water"); + Files.write(path, HAPPY, withCacheControl("potato")); + assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).cacheControl().get()) + .isEqualTo("potato"); + } } @Test public void testMimeType() throws IOException { - Files.write(path, HAPPY, withMimeType("text/potato")); - assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).mimeType().get()) - .isEqualTo("text/potato"); + try (FileSystem fs = helper.forBucket("red")) { + Path path = fs.getPath("/water"); + Files.write(path, HAPPY, withMimeType("text/potato")); + assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).mimeType().get()) + .isEqualTo("text/potato"); + } } @Test public void testAcl() throws IOException { - Acl acl = Acl.of(new Acl.User("serf@example.com"), Acl.Role.READER); - Files.write(path, HAPPY, withAcl(acl)); - assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).acl().get()) - .contains(acl); + try (FileSystem fs = helper.forBucket("red")) { + Path path = fs.getPath("/water"); + Acl acl = Acl.of(new Acl.User("serf@example.com"), Acl.Role.READER); + Files.write(path, HAPPY, withAcl(acl)); + assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).acl().get()) + .contains(acl); + } } @Test public void testContentDisposition() throws IOException { - Files.write(path, HAPPY, withContentDisposition("crash call")); - assertThat( - Files.readAttributes(path, CloudStorageFileAttributes.class).contentDisposition().get()) - .isEqualTo("crash call"); + try (FileSystem fs = helper.forBucket("red")) { + Path path = fs.getPath("/water"); + Files.write(path, HAPPY, withContentDisposition("crash call")); + assertThat( + Files.readAttributes(path, CloudStorageFileAttributes.class) + .contentDisposition() + .get()) + .isEqualTo("crash call"); + } } @Test public void testContentEncoding() throws IOException { - Files.write(path, HAPPY, withContentEncoding("my content encoding")); - assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).contentEncoding().get()) - .isEqualTo("my content encoding"); + try (FileSystem fs = helper.forBucket("red")) { + Path path = fs.getPath("/water"); + Files.write(path, HAPPY, withContentEncoding("my content encoding")); + assertThat( + Files.readAttributes(path, CloudStorageFileAttributes.class).contentEncoding().get()) + .isEqualTo("my content encoding"); + } } @Test public void testUserMetadata() throws IOException { - Files.write(path, HAPPY, withUserMetadata("green", "bean")); - assertThat( - Files.readAttributes(path, CloudStorageFileAttributes.class) - .userMetadata() - .get("green")) - .isEqualTo("bean"); + try (FileSystem fs = helper.forBucket("red")) { + Path path = fs.getPath("/water"); + Files.write(path, HAPPY, withUserMetadata("green", "bean")); + assertThat( + Files.readAttributes(path, CloudStorageFileAttributes.class) + .userMetadata() + .get("green")) + .isEqualTo("bean"); + } } @Test public void testIsDirectory() throws IOException { - Files.write(path, HAPPY); - assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).isDirectory()) - .isFalse(); - assertThat(Files.readAttributes(dir, CloudStorageFileAttributes.class).isDirectory()).isTrue(); + try (FileSystem fs = helper.forBucket("red")) { + Path path = fs.getPath("/water"); + Path dir = fs.getPath("/rum/"); + Files.write(path, HAPPY); + assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).isDirectory()) + .isFalse(); + assertThat(Files.readAttributes(dir, CloudStorageFileAttributes.class).isDirectory()) + .isTrue(); + } } @Test public void testIsRegularFile() throws IOException { - Files.write(path, HAPPY); - assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).isRegularFile()) - .isTrue(); - assertThat(Files.readAttributes(dir, CloudStorageFileAttributes.class).isRegularFile()) - .isFalse(); + try (FileSystem fs = helper.forBucket("red")) { + Path path = fs.getPath("/water"); + Path dir = fs.getPath("/rum/"); + Files.write(path, HAPPY); + assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).isRegularFile()) + .isTrue(); + assertThat(Files.readAttributes(dir, CloudStorageFileAttributes.class).isRegularFile()) + .isFalse(); + } } @Test public void testIsOther() throws IOException { - Files.write(path, HAPPY); - assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).isOther()).isFalse(); - assertThat(Files.readAttributes(dir, CloudStorageFileAttributes.class).isOther()).isFalse(); + try (FileSystem fs = helper.forBucket("red")) { + Path path = fs.getPath("/water"); + Path dir = fs.getPath("/rum/"); + Files.write(path, HAPPY); + assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).isOther()).isFalse(); + assertThat(Files.readAttributes(dir, CloudStorageFileAttributes.class).isOther()).isFalse(); + } } @Test public void testIsSymbolicLink() throws IOException { - Files.write(path, HAPPY); - assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).isSymbolicLink()) - .isFalse(); - assertThat(Files.readAttributes(dir, CloudStorageFileAttributes.class).isSymbolicLink()) - .isFalse(); + try (FileSystem fs = helper.forBucket("red")) { + Path path = fs.getPath("/water"); + Path dir = fs.getPath("/rum/"); + Files.write(path, HAPPY); + assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).isSymbolicLink()) + .isFalse(); + assertThat(Files.readAttributes(dir, CloudStorageFileAttributes.class).isSymbolicLink()) + .isFalse(); + } } @Test public void testEquals_equalsTester() throws IOException { - Files.write(path, HAPPY, withMimeType("text/plain")); - CloudStorageFileAttributes a1 = Files.readAttributes(path, CloudStorageFileAttributes.class); - CloudStorageFileAttributes a2 = Files.readAttributes(path, CloudStorageFileAttributes.class); - Files.write(path, HAPPY, withMimeType("text/potato")); - CloudStorageFileAttributes b1 = Files.readAttributes(path, CloudStorageFileAttributes.class); - CloudStorageFileAttributes b2 = Files.readAttributes(path, CloudStorageFileAttributes.class); - new EqualsTester().addEqualityGroup(a1, a2).addEqualityGroup(b1, b2).testEquals(); + try (FileSystem fs = helper.forBucket("red")) { + Path path = fs.getPath("/water"); + Files.write(path, HAPPY, withMimeType("text/plain")); + CloudStorageFileAttributes a1 = Files.readAttributes(path, CloudStorageFileAttributes.class); + CloudStorageFileAttributes a2 = Files.readAttributes(path, CloudStorageFileAttributes.class); + Files.write(path, HAPPY, withMimeType("text/potato")); + CloudStorageFileAttributes b1 = Files.readAttributes(path, CloudStorageFileAttributes.class); + CloudStorageFileAttributes b2 = Files.readAttributes(path, CloudStorageFileAttributes.class); + new EqualsTester().addEqualityGroup(a1, a2).addEqualityGroup(b1, b2).testEquals(); + } } @Test public void testFilekey() throws IOException { - Files.write(path, HAPPY, withMimeType("text/plain")); - Path path2 = Paths.get(URI.create("gs://bucket/anotherrandompath")); - Files.write(path2, HAPPY, withMimeType("text/plain")); - - // diff files cannot have same filekey - CloudStorageFileAttributes a1 = Files.readAttributes(path, CloudStorageFileAttributes.class); - CloudStorageFileAttributes a2 = Files.readAttributes(path2, CloudStorageFileAttributes.class); - assertThat(a1.fileKey()).isNotEqualTo(a2.fileKey()); - - // same for directories - CloudStorageFileAttributes b1 = Files.readAttributes(dir, CloudStorageFileAttributes.class); - CloudStorageFileAttributes b2 = - Files.readAttributes( - Paths.get(URI.create("gs://bucket/jacket/")), CloudStorageFileAttributes.class); - assertThat(a1.fileKey()).isNotEqualTo(b1.fileKey()); - assertThat(b1.fileKey()).isNotEqualTo(b2.fileKey()); + try (FileSystem fs = helper.forBucket("red")) { + Path dir = fs.getPath("/rum/"); + Path path = fs.getPath("/water"); + Files.write(path, HAPPY, withMimeType("text/plain")); + Path path2 = fs.getPath("/anotherrandompath"); + Files.write(path2, HAPPY, withMimeType("text/plain")); + + // diff files cannot have same filekey + CloudStorageFileAttributes a1 = Files.readAttributes(path, CloudStorageFileAttributes.class); + CloudStorageFileAttributes a2 = Files.readAttributes(path2, CloudStorageFileAttributes.class); + assertThat(a1.fileKey()).isNotEqualTo(a2.fileKey()); + + // same for directories + CloudStorageFileAttributes b1 = Files.readAttributes(dir, CloudStorageFileAttributes.class); + CloudStorageFileAttributes b2 = + Files.readAttributes(fs.getPath("/jacket/"), CloudStorageFileAttributes.class); + assertThat(a1.fileKey()).isNotEqualTo(b1.fileKey()); + assertThat(b1.fileKey()).isNotEqualTo(b2.fileKey()); + } } @Test public void testNullness() throws IOException, NoSuchMethodException, SecurityException { - Files.write(path, HAPPY); - CloudStorageFileAttributes pathAttributes = - Files.readAttributes(path, CloudStorageFileAttributes.class); - CloudStorageFileAttributes dirAttributes = - Files.readAttributes(dir, CloudStorageFileAttributes.class); - NullPointerTester tester = new NullPointerTester(); - tester.ignore(CloudStorageObjectAttributes.class.getMethod("equals", Object.class)); - tester.testAllPublicInstanceMethods(pathAttributes); - tester.testAllPublicInstanceMethods(dirAttributes); + try (FileSystem fs = helper.forBucket("red")) { + Path path = fs.getPath("/water"); + Path dir = fs.getPath("/rum/"); + Files.write(path, HAPPY); + CloudStorageFileAttributes pathAttributes = + Files.readAttributes(path, CloudStorageFileAttributes.class); + CloudStorageFileAttributes dirAttributes = + Files.readAttributes(dir, CloudStorageFileAttributes.class); + NullPointerTester tester = new NullPointerTester(); + tester.ignore(CloudStorageObjectAttributes.class.getMethod("equals", Object.class)); + tester.testAllPublicInstanceMethods(pathAttributes); + tester.testAllPublicInstanceMethods(dirAttributes); + } } } diff --git a/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileSystemProviderTest.java b/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileSystemProviderTest.java index fca592a99587..887ac996a1c7 100644 --- a/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileSystemProviderTest.java +++ b/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileSystemProviderTest.java @@ -17,12 +17,13 @@ package com.google.gcloud.storage.contrib.nio; import static com.google.common.truth.Truth.assertThat; -import static com.google.gcloud.storage.contrib.nio.CloudStorageFileSystem.forBucket; import static com.google.gcloud.storage.contrib.nio.CloudStorageOptions.withCacheControl; import static com.google.gcloud.storage.contrib.nio.CloudStorageOptions.withContentDisposition; import static com.google.gcloud.storage.contrib.nio.CloudStorageOptions.withContentEncoding; import static com.google.gcloud.storage.contrib.nio.CloudStorageOptions.withMimeType; import static com.google.gcloud.storage.contrib.nio.CloudStorageOptions.withUserMetadata; +import static com.google.gcloud.storage.contrib.nio.NioTestHelper.permitEmptyPathComponents; +import static com.google.gcloud.storage.contrib.nio.NioTestHelper.usePseudoDirectories; import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.file.StandardCopyOption.ATOMIC_MOVE; import static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES; @@ -33,9 +34,9 @@ import com.google.common.collect.ImmutableList; import com.google.common.testing.NullPointerTester; -import com.google.gcloud.storage.testing.LocalGcsHelper; +import com.google.gcloud.storage.testing.FakeStorageRpc; -import org.junit.Before; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -58,7 +59,6 @@ import java.nio.file.NoSuchFileException; import java.nio.file.OpenOption; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; import java.util.List; @@ -94,26 +94,28 @@ public class CloudStorageFileSystemProviderTest { @Rule public final ExpectedException thrown = ExpectedException.none(); - @Before - public void before() { - CloudStorageFileSystemProvider.setGCloudOptions(LocalGcsHelper.options()); - } + private final FakeStorageRpc storage = new FakeStorageRpc(true); + private final NioTestHelper helper = new NioTestHelper(storage); @Test public void testSize() throws IOException { - Path path = Paths.get(URI.create("gs://bucket/wat")); - Files.write(path, SINGULARITY.getBytes(UTF_8)); - assertThat(Files.size(path)).isEqualTo(SINGULARITY.getBytes(UTF_8).length); + try (FileSystem fs = helper.forBucket("bucket")) { + Path path = fs.getPath("/wat"); + Files.write(path, SINGULARITY.getBytes(UTF_8)); + assertThat(Files.size(path)).isEqualTo(SINGULARITY.getBytes(UTF_8).length); + } } @Test public void testSize_trailingSlash_returnsFakePseudoDirectorySize() throws IOException { - assertThat(Files.size(Paths.get(URI.create("gs://bucket/wat/")))).isEqualTo(1); + try (FileSystem fs = helper.forBucket("bucket")) { + assertThat(Files.size(fs.getPath("/wat/"))).isEqualTo(1); + } } @Test public void testSize_trailingSlash_disablePseudoDirectories() throws IOException { - try (CloudStorageFileSystem fs = forBucket("doodle", usePseudoDirectories(false))) { + try (CloudStorageFileSystem fs = helper.forBucket("doodle", usePseudoDirectories(false))) { Path path = fs.getPath("wat/"); byte[] rapture = SINGULARITY.getBytes(UTF_8); Files.write(path, rapture); @@ -123,190 +125,227 @@ public void testSize_trailingSlash_disablePseudoDirectories() throws IOException @Test public void testReadAllBytes() throws IOException { - 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); + try (FileSystem fs = helper.forBucket("bucket")) { + Path path = fs.getPath("/wat"); + Files.write(path, SINGULARITY.getBytes(UTF_8)); + assertThat(new String(Files.readAllBytes(path), UTF_8)).isEqualTo(SINGULARITY); + } } @Test public void testReadAllBytes_trailingSlash() throws IOException { - thrown.expect(CloudStoragePseudoDirectoryException.class); - Files.readAllBytes(Paths.get(URI.create("gs://bucket/wat/"))); + try (FileSystem fs = helper.forBucket("bucket")) { + thrown.expect(CloudStoragePseudoDirectoryException.class); + Files.readAllBytes(fs.getPath("/wat/")); + } } @Test public void testNewByteChannelRead() throws IOException { - Path path = Paths.get(URI.create("gs://bucket/wat")); - byte[] data = SINGULARITY.getBytes(UTF_8); - Files.write(path, data); - try (ReadableByteChannel input = Files.newByteChannel(path)) { - ByteBuffer buffer = ByteBuffer.allocate(data.length); - assertThat(input.read(buffer)).isEqualTo(data.length); - assertThat(new String(buffer.array(), UTF_8)).isEqualTo(SINGULARITY); - buffer.rewind(); - assertThat(input.read(buffer)).isEqualTo(-1); + try (FileSystem fs = helper.forBucket("bucket")) { + Path path = fs.getPath("/wat"); + byte[] data = SINGULARITY.getBytes(UTF_8); + Files.write(path, data); + try (ReadableByteChannel input = Files.newByteChannel(path)) { + ByteBuffer buffer = ByteBuffer.allocate(data.length); + assertThat(input.read(buffer)).isEqualTo(data.length); + assertThat(new String(buffer.array(), UTF_8)).isEqualTo(SINGULARITY); + buffer.rewind(); + assertThat(input.read(buffer)).isEqualTo(-1); + } } } @Test public void testNewByteChannelRead_seeking() throws IOException { - Path path = Paths.get(URI.create("gs://lol/cat")); - Files.write(path, "helloworld".getBytes(UTF_8)); - try (SeekableByteChannel input = Files.newByteChannel(path)) { - ByteBuffer buffer = ByteBuffer.allocate(5); - input.position(5); - assertThat(input.position()).isEqualTo(5); - assertThat(input.read(buffer)).isEqualTo(5); - assertThat(input.position()).isEqualTo(10); - assertThat(new String(buffer.array(), UTF_8)).isEqualTo("world"); - buffer.rewind(); - assertThat(input.read(buffer)).isEqualTo(-1); - input.position(0); - assertThat(input.position()).isEqualTo(0); - assertThat(input.read(buffer)).isEqualTo(5); - assertThat(input.position()).isEqualTo(5); - assertThat(new String(buffer.array(), UTF_8)).isEqualTo("hello"); + try (FileSystem fs = helper.forBucket("lol")) { + Path path = fs.getPath("/cat"); + Files.write(path, "helloworld".getBytes(UTF_8)); + try (SeekableByteChannel input = Files.newByteChannel(path)) { + ByteBuffer buffer = ByteBuffer.allocate(5); + input.position(5); + assertThat(input.position()).isEqualTo(5); + assertThat(input.read(buffer)).isEqualTo(5); + assertThat(input.position()).isEqualTo(10); + assertThat(new String(buffer.array(), UTF_8)).isEqualTo("world"); + buffer.rewind(); + assertThat(input.read(buffer)).isEqualTo(-1); + input.position(0); + assertThat(input.position()).isEqualTo(0); + assertThat(input.read(buffer)).isEqualTo(5); + assertThat(input.position()).isEqualTo(5); + assertThat(new String(buffer.array(), UTF_8)).isEqualTo("hello"); + } } } @Test public void testNewByteChannelRead_seekBeyondSize_reportsEofOnNextRead() throws IOException { - Path path = Paths.get(URI.create("gs://lol/cat")); - Files.write(path, "hellocat".getBytes(UTF_8)); - try (SeekableByteChannel input = Files.newByteChannel(path)) { - ByteBuffer buffer = ByteBuffer.allocate(5); - input.position(10); - assertThat(input.read(buffer)).isEqualTo(-1); - input.position(11); - assertThat(input.read(buffer)).isEqualTo(-1); - assertThat(input.size()).isEqualTo(8); + try (FileSystem fs = helper.forBucket("lol")) { + Path path = fs.getPath("/cat"); + Files.write(path, "hellocat".getBytes(UTF_8)); + try (SeekableByteChannel input = Files.newByteChannel(path)) { + ByteBuffer buffer = ByteBuffer.allocate(5); + input.position(10); + assertThat(input.read(buffer)).isEqualTo(-1); + input.position(11); + assertThat(input.read(buffer)).isEqualTo(-1); + assertThat(input.size()).isEqualTo(8); + } } } @Test public void testNewByteChannelRead_trailingSlash() throws IOException { - Path path = Paths.get(URI.create("gs://bucket/wat/")); - thrown.expect(CloudStoragePseudoDirectoryException.class); - Files.newByteChannel(path); + try (FileSystem fs = helper.forBucket("bucket")) { + Path path = fs.getPath("/wat/"); + thrown.expect(CloudStoragePseudoDirectoryException.class); + Files.newByteChannel(path); + } } @Test public void testNewByteChannelRead_notFound() throws IOException { - Path path = Paths.get(URI.create("gs://bucket/wednesday")); - thrown.expect(NoSuchFileException.class); - Files.newByteChannel(path); + try (FileSystem fs = helper.forBucket("bucket")) { + Path path = fs.getPath("/wednesday"); + thrown.expect(NoSuchFileException.class); + Files.newByteChannel(path); + } } @Test public void testNewByteChannelWrite() throws IOException { - Path path = Paths.get(URI.create("gs://bucket/tests")); - try (SeekableByteChannel output = Files.newByteChannel(path, WRITE)) { - assertThat(output.position()).isEqualTo(0); - assertThat(output.size()).isEqualTo(0); - ByteBuffer buffer = ByteBuffer.wrap("filec".getBytes(UTF_8)); - assertThat(output.write(buffer)).isEqualTo(5); - assertThat(output.position()).isEqualTo(5); - assertThat(output.size()).isEqualTo(5); - buffer = ByteBuffer.wrap("onten".getBytes(UTF_8)); - assertThat(output.write(buffer)).isEqualTo(5); - assertThat(output.position()).isEqualTo(10); - assertThat(output.size()).isEqualTo(10); + try (FileSystem fs = helper.forBucket("bucket")) { + Path path = fs.getPath("/tests"); + try (SeekableByteChannel output = Files.newByteChannel(path, WRITE)) { + assertThat(output.position()).isEqualTo(0); + assertThat(output.size()).isEqualTo(0); + ByteBuffer buffer = ByteBuffer.wrap("filec".getBytes(UTF_8)); + assertThat(output.write(buffer)).isEqualTo(5); + assertThat(output.position()).isEqualTo(5); + assertThat(output.size()).isEqualTo(5); + buffer = ByteBuffer.wrap("onten".getBytes(UTF_8)); + assertThat(output.write(buffer)).isEqualTo(5); + assertThat(output.position()).isEqualTo(10); + assertThat(output.size()).isEqualTo(10); + } + assertThat(new String(Files.readAllBytes(path), UTF_8)).isEqualTo("fileconten"); } - assertThat(new String(Files.readAllBytes(path), UTF_8)).isEqualTo("fileconten"); } @Test public void testNewInputStream() throws IOException { - Path path = Paths.get(URI.create("gs://bucket/wat")); - Files.write(path, SINGULARITY.getBytes(UTF_8)); - try (InputStream input = Files.newInputStream(path)) { - byte[] data = new byte[SINGULARITY.getBytes(UTF_8).length]; - input.read(data); - assertThat(new String(data, UTF_8)).isEqualTo(SINGULARITY); + try (FileSystem fs = helper.forBucket("bucket")) { + Path path = fs.getPath("/wat"); + Files.write(path, SINGULARITY.getBytes(UTF_8)); + try (InputStream input = Files.newInputStream(path)) { + byte[] data = new byte[SINGULARITY.getBytes(UTF_8).length]; + input.read(data); + assertThat(new String(data, UTF_8)).isEqualTo(SINGULARITY); + } } } @Test public void testNewInputStream_trailingSlash() throws IOException { - Path path = Paths.get(URI.create("gs://bucket/wat/")); - thrown.expect(CloudStoragePseudoDirectoryException.class); - try (InputStream input = Files.newInputStream(path)) { - input.read(); + try (FileSystem fs = helper.forBucket("bucket")) { + Path path = fs.getPath("/wat/"); + thrown.expect(CloudStoragePseudoDirectoryException.class); + try (InputStream input = Files.newInputStream(path)) { + input.read(); + } } } @Test public void testNewInputStream_notFound() throws IOException { - Path path = Paths.get(URI.create("gs://cry/wednesday")); - thrown.expect(NoSuchFileException.class); - try (InputStream input = Files.newInputStream(path)) { - input.read(); + try (FileSystem fs = helper.forBucket("cry")) { + Path path = fs.getPath("/wednesday"); + thrown.expect(NoSuchFileException.class); + try (InputStream input = Files.newInputStream(path)) { + input.read(); + } } } @Test public void testNewOutputStream() throws IOException { - Path path = Paths.get(URI.create("gs://bucket/wat")); - Files.write(path, SINGULARITY.getBytes(UTF_8)); - try (OutputStream output = Files.newOutputStream(path)) { - output.write(SINGULARITY.getBytes(UTF_8)); + try (FileSystem fs = helper.forBucket("bucket")) { + Path path = fs.getPath("/wat"); + Files.write(path, SINGULARITY.getBytes(UTF_8)); + 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(Files.readAllBytes(path), UTF_8)).isEqualTo(SINGULARITY); } @Test public void testNewOutputStream_truncateByDefault() throws IOException { - Path path = Paths.get(URI.create("gs://bucket/wat")); - Files.write(path, SINGULARITY.getBytes(UTF_8)); - Files.write(path, "hello".getBytes(UTF_8)); - try (OutputStream output = Files.newOutputStream(path)) { - output.write(SINGULARITY.getBytes(UTF_8)); + try (FileSystem fs = helper.forBucket("bucket")) { + Path path = fs.getPath("/wat"); + Files.write(path, SINGULARITY.getBytes(UTF_8)); + Files.write(path, "hello".getBytes(UTF_8)); + 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(Files.readAllBytes(path), UTF_8)).isEqualTo(SINGULARITY); } @Test public void testNewOutputStream_truncateExplicitly() throws IOException { - Path path = Paths.get(URI.create("gs://bucket/wat")); - Files.write(path, SINGULARITY.getBytes(UTF_8)); - Files.write(path, "hello".getBytes(UTF_8)); - try (OutputStream output = Files.newOutputStream(path, TRUNCATE_EXISTING)) { - output.write(SINGULARITY.getBytes(UTF_8)); + try (FileSystem fs = helper.forBucket("bucket")) { + Path path = fs.getPath("/wat"); + Files.write(path, SINGULARITY.getBytes(UTF_8)); + Files.write(path, "hello".getBytes(UTF_8)); + 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(Files.readAllBytes(path), UTF_8)).isEqualTo(SINGULARITY); } @Test public void testNewOutputStream_trailingSlash() throws IOException { - Path path = Paths.get(URI.create("gs://bucket/wat/")); - thrown.expect(CloudStoragePseudoDirectoryException.class); - Files.newOutputStream(path); + try (FileSystem fs = helper.forBucket("bucket")) { + Path path = fs.getPath("/wat/"); + thrown.expect(CloudStoragePseudoDirectoryException.class); + Files.newOutputStream(path); + } } @Test public void testNewOutputStream_createNew() throws IOException { - Path path = Paths.get(URI.create("gs://cry/wednesday")); - Files.newOutputStream(path, CREATE_NEW); + try (FileSystem fs = helper.forBucket("cry")) { + Path path = fs.getPath("/wednesday"); + Files.newOutputStream(path, CREATE_NEW); + } } @Test public void testNewOutputStream_createNew_alreadyExists() throws IOException { - Path path = Paths.get(URI.create("gs://cry/wednesday")); - Files.write(path, SINGULARITY.getBytes(UTF_8)); - thrown.expect(FileAlreadyExistsException.class); - Files.newOutputStream(path, CREATE_NEW); + try (FileSystem fs = helper.forBucket("cry")) { + Path path = fs.getPath("/wednesday"); + Files.write(path, SINGULARITY.getBytes(UTF_8)); + thrown.expect(FileAlreadyExistsException.class); + Files.newOutputStream(path, CREATE_NEW); + } } @Test public void testWrite_objectNameWithExtraSlashes_throwsIae() throws IOException { - Path path = Paths.get(URI.create("gs://double/slash//yep")); - thrown.expect(IllegalArgumentException.class); - Files.write(path, FILE_CONTENTS, UTF_8); + try (FileSystem fs = helper.forBucket("double")) { + Path path = fs.getPath("/slash//yep"); + thrown.expect(IllegalArgumentException.class); + Files.write(path, FILE_CONTENTS, UTF_8); + } } @Test public void testWrite_objectNameWithExtraSlashes_canBeNormalized() throws IOException { - try (CloudStorageFileSystem fs = forBucket("greenbean", permitEmptyPathComponents(false))) { + try (CloudStorageFileSystem fs = + helper.forBucket("greenbean", permitEmptyPathComponents(false))) { Path path = fs.getPath("adipose//yep").normalize(); Files.write(path, FILE_CONTENTS, UTF_8); assertThat(Files.readAllLines(path, UTF_8)).isEqualTo(FILE_CONTENTS); @@ -316,7 +355,8 @@ public void testWrite_objectNameWithExtraSlashes_canBeNormalized() throws IOExce @Test public void testWrite_objectNameWithExtraSlashes_permitEmptyPathComponents() throws IOException { - try (CloudStorageFileSystem fs = forBucket("greenbean", permitEmptyPathComponents(true))) { + try (CloudStorageFileSystem fs = + helper.forBucket("greenbean", permitEmptyPathComponents(true))) { Path path = fs.getPath("adipose//yep"); Files.write(path, FILE_CONTENTS, UTF_8); assertThat(Files.readAllLines(path, UTF_8)).isEqualTo(FILE_CONTENTS); @@ -326,17 +366,19 @@ public void testWrite_objectNameWithExtraSlashes_permitEmptyPathComponents() thr @Test public void testWrite_absoluteObjectName_prefixSlashGetsRemoved() throws IOException { - Path path = Paths.get(URI.create("gs://greenbean/adipose/yep")); - Files.write(path, FILE_CONTENTS, UTF_8); - assertThat(Files.readAllLines(path, UTF_8)).isEqualTo(FILE_CONTENTS); - assertThat(Files.exists(path)).isTrue(); + try (CloudStorageFileSystem fs = helper.forBucket("greenbean")) { + Path path = fs.getPath("/adipose/yep"); + Files.write(path, FILE_CONTENTS, UTF_8); + assertThat(Files.readAllLines(path, UTF_8)).isEqualTo(FILE_CONTENTS); + assertThat(Files.exists(path)).isTrue(); + } } @Test public void testWrite_absoluteObjectName_disableStrip_slashGetsPreserved() throws IOException { try (CloudStorageFileSystem fs = - forBucket( - "greenbean", CloudStorageConfiguration.builder().stripPrefixSlash(false).build())) { + helper.forBucket( + "greenbean", CloudStorageConfiguration.builder().stripPrefixSlash(false).build())) { Path path = fs.getPath("/adipose/yep"); Files.write(path, FILE_CONTENTS, UTF_8); assertThat(Files.readAllLines(path, UTF_8)).isEqualTo(FILE_CONTENTS); @@ -346,85 +388,101 @@ public void testWrite_absoluteObjectName_disableStrip_slashGetsPreserved() throw @Test public void testWrite() throws IOException { - Path path = Paths.get(URI.create("gs://greenbean/adipose")); - Files.write(path, FILE_CONTENTS, UTF_8); - assertThat(Files.readAllLines(path, UTF_8)).isEqualTo(FILE_CONTENTS); + try (FileSystem fs = helper.forBucket("greenbean")) { + Path path = fs.getPath("/adipose"); + Files.write(path, FILE_CONTENTS, UTF_8); + assertThat(Files.readAllLines(path, UTF_8)).isEqualTo(FILE_CONTENTS); + } } @Test public void testWriteOnClose() throws IOException { - Path path = Paths.get(URI.create("gs://greenbean/adipose")); - try (SeekableByteChannel chan = Files.newByteChannel(path, StandardOpenOption.WRITE)) { - // writing lots of contents to defeat channel-internal buffering. - for (int i = 0; i < 9999; i++) { - for (String s : FILE_CONTENTS) { - chan.write(ByteBuffer.wrap(s.getBytes(UTF_8))); + try (FileSystem fs = helper.forBucket("greenbean")) { + Path path = fs.getPath("/adipose"); + try (SeekableByteChannel chan = Files.newByteChannel(path, StandardOpenOption.WRITE)) { + // writing lots of contents to defeat channel-internal buffering. + for (int i = 0; i < 9999; i++) { + for (String s : FILE_CONTENTS) { + chan.write(ByteBuffer.wrap(s.getBytes(UTF_8))); + } + } + try { + Files.size(path); + // we shouldn't make it to this line. Not using thrown.expect because + // I still want to run a few lines after the exception. + assertThat(false).isTrue(); + } catch (NoSuchFileException nsf) { + // that's what we wanted, we're good. } } - try { - Files.size(path); - // we shouldn't make it to this line. Not using thrown.expect because - // I still want to run a few lines after the exception. - assertThat(false).isTrue(); - } catch (NoSuchFileException nsf) { - // that's what we wanted, we're good. - } + // channel now closed, the file should be there and with the new contents. + assertThat(Files.exists(path)).isTrue(); + assertThat(Files.size(path)).isGreaterThan(100L); } - // channel now closed, the file should be there and with the new contents. - assertThat(Files.exists(path)).isTrue(); - assertThat(Files.size(path)).isGreaterThan(100L); } @Test public void testWrite_trailingSlash() throws IOException { - thrown.expect(CloudStoragePseudoDirectoryException.class); - Files.write(Paths.get(URI.create("gs://greenbean/adipose/")), FILE_CONTENTS, UTF_8); + try (FileSystem fs = helper.forBucket("greenbean")) { + thrown.expect(CloudStoragePseudoDirectoryException.class); + Files.write(fs.getPath("/adipose/"), FILE_CONTENTS, UTF_8); + } } @Test public void testExists() throws IOException { - assertThat(Files.exists(Paths.get(URI.create("gs://military/fashion")))).isFalse(); - Files.write(Paths.get(URI.create("gs://military/fashion")), "(✿◕ ‿◕ )ノ".getBytes(UTF_8)); - assertThat(Files.exists(Paths.get(URI.create("gs://military/fashion")))).isTrue(); + try (FileSystem fs = helper.forBucket("military")) { + assertThat(Files.exists(fs.getPath("/fashion"))).isFalse(); + Files.write(fs.getPath("/fashion"), "(✿◕ ‿◕ )ノ".getBytes(UTF_8)); + assertThat(Files.exists(fs.getPath("/fashion"))).isTrue(); + } } @Test - public void testExists_trailingSlash() { - assertThat(Files.exists(Paths.get(URI.create("gs://military/fashion/")))).isTrue(); - assertThat(Files.exists(Paths.get(URI.create("gs://military/fashion/.")))).isTrue(); - assertThat(Files.exists(Paths.get(URI.create("gs://military/fashion/..")))).isTrue(); + public void testExists_trailingSlash() throws IOException { + try (FileSystem fs = helper.forBucket("military")) { + assertThat(Files.exists(fs.getPath("/fashion/"))).isTrue(); + assertThat(Files.exists(fs.getPath("/fashion/."))).isTrue(); + assertThat(Files.exists(fs.getPath("/fashion/.."))).isTrue(); + } } @Test - public void testExists_trailingSlash_disablePseudoDirectories() { - try (CloudStorageFileSystem fs = forBucket("military", usePseudoDirectories(false))) { + public void testExists_trailingSlash_disablePseudoDirectories() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("military", usePseudoDirectories(false))) { assertThat(Files.exists(fs.getPath("fashion/"))).isFalse(); } } @Test public void testDelete() throws IOException { - Files.write(Paths.get(URI.create("gs://love/fashion")), "(✿◕ ‿◕ )ノ".getBytes(UTF_8)); - assertThat(Files.exists(Paths.get(URI.create("gs://love/fashion")))).isTrue(); - Files.delete(Paths.get(URI.create("gs://love/fashion"))); - assertThat(Files.exists(Paths.get(URI.create("gs://love/fashion")))).isFalse(); + try (FileSystem fs = helper.forBucket("love")) { + Files.write(fs.getPath("/fashion"), "(✿◕ ‿◕ )ノ".getBytes(UTF_8)); + assertThat(Files.exists(fs.getPath("/fashion"))).isTrue(); + Files.delete(fs.getPath("/fashion")); + assertThat(Files.exists(fs.getPath("/fashion"))).isFalse(); + } } @Test public void testDelete_dotDirNotNormalized_throwsIae() throws IOException { - thrown.expect(IllegalArgumentException.class); - Files.delete(Paths.get(URI.create("gs://love/fly/../passion"))); + try (FileSystem fs = helper.forBucket("love")) { + thrown.expect(IllegalArgumentException.class); + Files.delete(fs.getPath("/fly/../passion")); + } } @Test public void testDelete_trailingSlash() throws IOException { - thrown.expect(CloudStoragePseudoDirectoryException.class); - Files.delete(Paths.get(URI.create("gs://love/passion/"))); + try (FileSystem fs = helper.forBucket("love")) { + thrown.expect(CloudStoragePseudoDirectoryException.class); + Files.delete(fs.getPath("/passion/")); + } } @Test public void testDelete_trailingSlash_disablePseudoDirectories() throws IOException { - try (CloudStorageFileSystem fs = forBucket("pumpkin", usePseudoDirectories(false))) { + try (CloudStorageFileSystem fs = helper.forBucket("pumpkin", usePseudoDirectories(false))) { Path path = fs.getPath("wat/"); Files.write(path, FILE_CONTENTS, UTF_8); assertThat(Files.exists(path)); @@ -435,106 +493,134 @@ public void testDelete_trailingSlash_disablePseudoDirectories() throws IOExcepti @Test public void testDelete_notFound() throws IOException { - thrown.expect(NoSuchFileException.class); - Files.delete(Paths.get(URI.create("gs://loveh/passionehu"))); + try (FileSystem fs = helper.forBucket("loveh")) { + thrown.expect(NoSuchFileException.class); + Files.delete(fs.getPath("/passionehu")); + } } @Test public void testDeleteIfExists() throws IOException { - Files.write(Paths.get(URI.create("gs://love/passionz")), "(✿◕ ‿◕ )ノ".getBytes(UTF_8)); - assertThat(Files.deleteIfExists(Paths.get(URI.create("gs://love/passionz")))).isTrue(); + try (FileSystem fs = helper.forBucket("love")) { + Files.write(fs.getPath("/passionz"), "(✿◕ ‿◕ )ノ".getBytes(UTF_8)); + assertThat(Files.deleteIfExists(fs.getPath("/passionz"))).isTrue(); + } } @Test public void testDeleteIfExists_trailingSlash() throws IOException { - thrown.expect(CloudStoragePseudoDirectoryException.class); - Files.deleteIfExists(Paths.get(URI.create("gs://love/passion/"))); + try (FileSystem fs = helper.forBucket("love")) { + thrown.expect(CloudStoragePseudoDirectoryException.class); + Files.deleteIfExists(fs.getPath("/passion/")); + } } @Test - public void testCopy() throws IOException { - Path source = Paths.get(URI.create("gs://military/fashion.show")); - 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(Files.exists(source)).isTrue(); - assertThat(Files.exists(target)).isTrue(); + public void testCopyAcrossBuckets() throws IOException { + try (FileSystem fsMilitary = helper.forBucket("military"); + FileSystem fsGreenbean = helper.forBucket("greenbean")) { + Path source = fsMilitary.getPath("/fashion.show"); + Path target = fsGreenbean.getPath("/adipose"); + Files.write(source, "(✿◕ ‿◕ )ノ".getBytes(UTF_8)); + Files.copy(source, target); + assertThat(new String(Files.readAllBytes(target), UTF_8)).isEqualTo("(✿◕ ‿◕ )ノ"); + assertThat(Files.exists(source)).isTrue(); + assertThat(Files.exists(target)).isTrue(); + } } @Test public void testCopy_sourceMissing_throwsNoSuchFileException() throws IOException { - thrown.expect(NoSuchFileException.class); - Files.copy( - Paths.get(URI.create("gs://military/fashion.show")), - Paths.get(URI.create("gs://greenbean/adipose"))); + try (FileSystem fsMilitary = helper.forBucket("military"); + FileSystem fsGreenbean = helper.forBucket("greenbean")) { + thrown.expect(NoSuchFileException.class); + Files.copy(fsMilitary.getPath("/fashion.show"), fsGreenbean.getPath("/adipose")); + } } @Test public void testCopy_targetExists_throwsFileAlreadyExistsException() throws IOException { - Path source = Paths.get(URI.create("gs://military/fashion.show")); - Path target = Paths.get(URI.create("gs://greenbean/adipose")); - Files.write(source, "(✿◕ ‿◕ )ノ".getBytes(UTF_8)); - Files.write(target, "(✿◕ ‿◕ )ノ".getBytes(UTF_8)); - thrown.expect(FileAlreadyExistsException.class); - Files.copy(source, target); + try (FileSystem fsMilitary = helper.forBucket("military"); + FileSystem fsGreenbean = helper.forBucket("greenbean")) { + Path source = fsMilitary.getPath("/fashion.show"); + Path target = fsGreenbean.getPath("/adipose"); + Files.write(source, "(✿◕ ‿◕ )ノ".getBytes(UTF_8)); + Files.write(target, "(✿◕ ‿◕ )ノ".getBytes(UTF_8)); + thrown.expect(FileAlreadyExistsException.class); + Files.copy(source, target); + } } @Test public void testCopyReplace_targetExists_works() throws IOException { - Path source = Paths.get(URI.create("gs://military/fashion.show")); - Path target = Paths.get(URI.create("gs://greenbean/adipose")); - Files.write(source, "(✿◕ ‿◕ )ノ".getBytes(UTF_8)); - Files.write(target, "(✿◕ ‿◕ )ノ".getBytes(UTF_8)); - Files.copy(source, target, REPLACE_EXISTING); + try (FileSystem fsMilitary = helper.forBucket("military"); + FileSystem fsGreenbean = helper.forBucket("greenbean")) { + Path source = fsMilitary.getPath("/fashion.show"); + Path target = fsGreenbean.getPath("/adipose"); + Files.write(source, "(✿◕ ‿◕ )ノ".getBytes(UTF_8)); + Files.write(target, "(✿◕ ‿◕ )ノ".getBytes(UTF_8)); + Files.copy(source, target, REPLACE_EXISTING); + } } @Test public void testCopy_directory_doesNothing() throws IOException { - Path source = Paths.get(URI.create("gs://military/fundir/")); - Path target = Paths.get(URI.create("gs://greenbean/loldir/")); - Files.copy(source, target); + try (FileSystem fs = helper.forBucket("greenbean", usePseudoDirectories(true))) { + Path source = fs.getPath("/fundir/"); + Path target = fs.getPath("/loldir/"); + Files.copy(source, target); + } } @Test public void testCopy_atomic_throwsUnsupported() throws IOException { - Path source = Paths.get(URI.create("gs://military/fashion.show")); - Path target = Paths.get(URI.create("gs://greenbean/adipose")); - Files.write(source, "(✿◕ ‿◕ )ノ".getBytes(UTF_8)); - thrown.expect(UnsupportedOperationException.class); - Files.copy(source, target, ATOMIC_MOVE); + try (FileSystem fsMilitary = helper.forBucket("military"); + FileSystem fsGreenbean = helper.forBucket("greenbean")) { + Path source = fsMilitary.getPath("/fashion.show"); + Path target = fsGreenbean.getPath("/adipose"); + Files.write(source, "(✿◕ ‿◕ )ノ".getBytes(UTF_8)); + thrown.expect(UnsupportedOperationException.class); + Files.copy(source, target, ATOMIC_MOVE); + } } @Test public void testMove() throws IOException { - Path source = Paths.get(URI.create("gs://military/fashion.show")); - 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(Files.exists(source)).isFalse(); - assertThat(Files.exists(target)).isTrue(); + try (FileSystem fs = helper.forBucket("greenbean")) { + Path source = fs.getPath("/fashion.show"); + Path target = fs.getPath("/adipose"); + Files.write(source, "(✿◕ ‿◕ )ノ".getBytes(UTF_8)); + Files.move(source, target); + assertThat(new String(Files.readAllBytes(target), UTF_8)).isEqualTo("(✿◕ ‿◕ )ノ"); + assertThat(Files.exists(source)).isFalse(); + assertThat(Files.exists(target)).isTrue(); + } } @Test public void testCreateDirectory() throws IOException { - Path path = Paths.get(URI.create("gs://greenbean/dir/")); - Files.createDirectory(path); - assertThat(Files.exists(path)).isTrue(); + try (FileSystem fsGreenbean = helper.forBucket("greenbean")) { + Path path = fsGreenbean.getPath("/dir/"); + Files.createDirectory(path); + assertThat(Files.exists(path)).isTrue(); + } } @Test public void testMove_atomicMove_notSupported() throws IOException { - Path source = Paths.get(URI.create("gs://military/fashion.show")); - Path target = Paths.get(URI.create("gs://greenbean/adipose")); - Files.write(source, "(✿◕ ‿◕ )ノ".getBytes(UTF_8)); - thrown.expect(AtomicMoveNotSupportedException.class); - Files.move(source, target, ATOMIC_MOVE); + try (FileSystem fsMilitary = helper.forBucket("military"); + FileSystem fsGreenbean = helper.forBucket("greenbean")) { + Path source = fsMilitary.getPath("/fashion.show"); + Path target = fsGreenbean.getPath("/adipose"); + Files.write(source, "(✿◕ ‿◕ )ノ".getBytes(UTF_8)); + thrown.expect(AtomicMoveNotSupportedException.class); + Files.move(source, target, ATOMIC_MOVE); + } } @Test public void testIsDirectory() throws IOException { - try (FileSystem fs = FileSystems.getFileSystem(URI.create("gs://doodle"))) { + try (FileSystem fs = helper.forBucket("doodle")) { assertThat(Files.isDirectory(fs.getPath(""))).isTrue(); assertThat(Files.isDirectory(fs.getPath("/"))).isTrue(); assertThat(Files.isDirectory(fs.getPath("."))).isTrue(); @@ -547,115 +633,120 @@ public void testIsDirectory() throws IOException { } @Test - public void testIsDirectory_trailingSlash_alwaysTrue() { - assertThat(Files.isDirectory(Paths.get(URI.create("gs://military/fundir/")))).isTrue(); + public void testIsDirectory_trailingSlash_alwaysTrue() throws IOException { + try (FileSystem fs = helper.forBucket("military")) { + assertThat(Files.isDirectory(fs.getPath("/fundir/"))).isTrue(); + } } @Test - public void testIsDirectory_trailingSlash_pseudoDirectoriesDisabled_false() { - try (CloudStorageFileSystem fs = forBucket("doodle", usePseudoDirectories(false))) { + public void testIsDirectory_trailingSlash_pseudoDirectoriesDisabled_false() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle", usePseudoDirectories(false))) { assertThat(Files.isDirectory(fs.getPath("fundir/"))).isFalse(); } } @Test public void testCopy_withCopyAttributes_preservesAttributes() throws IOException { - Path source = Paths.get(URI.create("gs://military/fashion.show")); - Path target = Paths.get(URI.create("gs://greenbean/adipose")); - Files.write( - source, - "(✿◕ ‿◕ )ノ".getBytes(UTF_8), - withMimeType("text/lolcat"), - withCacheControl("public; max-age=666"), - withContentEncoding("foobar"), - withContentDisposition("my-content-disposition"), - withUserMetadata("answer", "42")); - Files.copy(source, target, COPY_ATTRIBUTES); - - CloudStorageFileAttributes attributes = - Files.readAttributes(target, CloudStorageFileAttributes.class); - assertThat(attributes.mimeType()).hasValue("text/lolcat"); - assertThat(attributes.cacheControl()).hasValue("public; max-age=666"); - assertThat(attributes.contentEncoding()).hasValue("foobar"); - assertThat(attributes.contentDisposition()).hasValue("my-content-disposition"); - assertThat(attributes.userMetadata().containsKey("answer")).isTrue(); - assertThat(attributes.userMetadata().get("answer")).isEqualTo("42"); + try (FileSystem fsMilitary = helper.forBucket("military"); + FileSystem fsGreenbean = helper.forBucket("greenbean")) { + Path source = fsMilitary.getPath("/fashion.show"); + Path target = fsGreenbean.getPath("/adipose"); + Files.write( + source, + "(✿◕ ‿◕ )ノ".getBytes(UTF_8), + withMimeType("text/lolcat"), + withCacheControl("public; max-age=666"), + withContentEncoding("foobar"), + withContentDisposition("my-content-disposition"), + withUserMetadata("answer", "42")); + Files.copy(source, target, COPY_ATTRIBUTES); + + CloudStorageFileAttributes attributes = + Files.readAttributes(target, CloudStorageFileAttributes.class); + assertThat(attributes.mimeType()).hasValue("text/lolcat"); + assertThat(attributes.cacheControl()).hasValue("public; max-age=666"); + assertThat(attributes.contentEncoding()).hasValue("foobar"); + assertThat(attributes.contentDisposition()).hasValue("my-content-disposition"); + assertThat(attributes.userMetadata().containsKey("answer")).isTrue(); + assertThat(attributes.userMetadata().get("answer")).isEqualTo("42"); + } } @Test public void testCopy_withoutOptions_doesntPreservesAttributes() throws IOException { - Path source = Paths.get(URI.create("gs://military/fashion.show")); - Path target = Paths.get(URI.create("gs://greenbean/adipose")); - Files.write( - source, - "(✿◕ ‿◕ )ノ".getBytes(UTF_8), - withMimeType("text/lolcat"), - withCacheControl("public; max-age=666"), - withUserMetadata("answer", "42")); - Files.copy(source, target); - - CloudStorageFileAttributes attributes = - Files.readAttributes(target, CloudStorageFileAttributes.class); - String mimeType = attributes.mimeType().orNull(); - String cacheControl = attributes.cacheControl().orNull(); - assertThat(mimeType).isNotEqualTo("text/lolcat"); - assertThat(cacheControl).isNull(); - assertThat(attributes.userMetadata().containsKey("answer")).isFalse(); + try (FileSystem fsMilitary = helper.forBucket("military"); + FileSystem fsGreenbean = helper.forBucket("greenbean")) { + Path source = fsMilitary.getPath("/fashion.show"); + Path target = fsGreenbean.getPath("/adipose"); + Files.write( + source, + "(✿◕ ‿◕ )ノ".getBytes(UTF_8), + withMimeType("text/lolcat"), + withCacheControl("public; max-age=666"), + withUserMetadata("answer", "42")); + Files.copy(source, target); + + CloudStorageFileAttributes attributes = + Files.readAttributes(target, CloudStorageFileAttributes.class); + String mimeType = attributes.mimeType().orNull(); + String cacheControl = attributes.cacheControl().orNull(); + assertThat(mimeType).isNotEqualTo("text/lolcat"); + assertThat(cacheControl).isNull(); + assertThat(attributes.userMetadata().containsKey("answer")).isFalse(); + } } @Test public void testCopy_overwriteAttributes() throws IOException { - Path source = Paths.get(URI.create("gs://military/fashion.show")); - Path target1 = Paths.get(URI.create("gs://greenbean/adipose")); - Path target2 = Paths.get(URI.create("gs://greenbean/round")); - Files.write( - source, - "(✿◕ ‿◕ )ノ".getBytes(UTF_8), - withMimeType("text/lolcat"), - withCacheControl("public; max-age=666")); - Files.copy(source, target1, COPY_ATTRIBUTES); - Files.copy(source, target2, COPY_ATTRIBUTES, withMimeType("text/palfun")); - - CloudStorageFileAttributes attributes = - Files.readAttributes(target1, CloudStorageFileAttributes.class); - assertThat(attributes.mimeType()).hasValue("text/lolcat"); - assertThat(attributes.cacheControl()).hasValue("public; max-age=666"); - - attributes = Files.readAttributes(target2, CloudStorageFileAttributes.class); - assertThat(attributes.mimeType()).hasValue("text/palfun"); - assertThat(attributes.cacheControl()).hasValue("public; max-age=666"); + try (FileSystem fsMilitary = helper.forBucket("military"); + FileSystem fsGreenbean = helper.forBucket("greenbean")) { + Path source = fsMilitary.getPath("/fashion.show"); + Path target1 = fsGreenbean.getPath("/adipose"); + Path target2 = fsGreenbean.getPath("/round"); + Files.write( + source, + "(✿◕ ‿◕ )ノ".getBytes(UTF_8), + withMimeType("text/lolcat"), + withCacheControl("public; max-age=666")); + Files.copy(source, target1, COPY_ATTRIBUTES); + Files.copy(source, target2, COPY_ATTRIBUTES, withMimeType("text/palfun")); + + CloudStorageFileAttributes attributes = + Files.readAttributes(target1, CloudStorageFileAttributes.class); + assertThat(attributes.mimeType()).hasValue("text/lolcat"); + assertThat(attributes.cacheControl()).hasValue("public; max-age=666"); + + attributes = Files.readAttributes(target2, CloudStorageFileAttributes.class); + assertThat(attributes.mimeType()).hasValue("text/palfun"); + assertThat(attributes.cacheControl()).hasValue("public; max-age=666"); + } } @Test + @Ignore("TODO(#830): Figure out how to re-enable this.") public void testNullness() throws IOException, NoSuchMethodException, SecurityException { - try (FileSystem fs = FileSystems.getFileSystem(URI.create("gs://blood"))) { + try (FileSystem fs = helper.forBucket("blood")) { NullPointerTester tester = new NullPointerTester(); tester.ignore(CloudStorageFileSystemProvider.class.getMethod("equals", Object.class)); tester.setDefault(URI.class, URI.create("gs://blood")); tester.setDefault(Path.class, fs.getPath("and/one")); tester.setDefault(OpenOption.class, StandardOpenOption.CREATE); tester.setDefault(CopyOption.class, StandardCopyOption.COPY_ATTRIBUTES); - // can't do that, setGCloudOptions accepts a null argument. - // TODO(jart): Figure out how to re-enable this. - // tester.testAllPublicStaticMethods(CloudStorageFileSystemProvider.class); + tester.testAllPublicStaticMethods(CloudStorageFileSystemProvider.class); tester.testAllPublicInstanceMethods(new CloudStorageFileSystemProvider()); } } @Test - public void testProviderEquals() { - Path path1 = Paths.get(URI.create("gs://bucket/tuesday")); - Path path2 = Paths.get(URI.create("gs://blood/wednesday")); - Path path3 = Paths.get("tmp"); - assertThat(path1.getFileSystem().provider()).isEqualTo(path2.getFileSystem().provider()); - assertThat(path1.getFileSystem().provider()).isNotEqualTo(path3.getFileSystem().provider()); - } - - private static CloudStorageConfiguration permitEmptyPathComponents(boolean value) { - return CloudStorageConfiguration.builder().permitEmptyPathComponents(value).build(); - } - - private static CloudStorageConfiguration usePseudoDirectories(boolean value) { - return CloudStorageConfiguration.builder().usePseudoDirectories(value).build(); + public void testProviderEquals() throws IOException { + try (FileSystem fs1 = helper.forBucket("bucket"); + FileSystem fs2 = helper.forBucket("blood")) { + Path path1 = fs1.getPath("/tuesday"); + Path path2 = fs2.getPath("/wednesday"); + Path path3 = FileSystems.getDefault().getPath("tmp"); + assertThat(path1.getFileSystem().provider()).isEqualTo(path2.getFileSystem().provider()); + assertThat(path1.getFileSystem().provider()).isNotEqualTo(path3.getFileSystem().provider()); + } } } diff --git a/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileSystemTest.java b/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileSystemTest.java index aacdb24268c6..d4774ea429c8 100644 --- a/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileSystemTest.java +++ b/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageFileSystemTest.java @@ -21,20 +21,15 @@ import com.google.common.testing.EqualsTester; import com.google.common.testing.NullPointerTester; -import com.google.gcloud.storage.StorageOptions; -import com.google.gcloud.storage.testing.LocalGcsHelper; +import com.google.gcloud.storage.testing.FakeStorageRpc; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.io.IOException; -import java.net.URI; import java.nio.file.FileSystem; -import java.nio.file.FileSystems; import java.nio.file.Files; -import java.nio.file.Paths; /** * Unit tests for {@link CloudStorageFileSystem}. @@ -52,14 +47,12 @@ public class CloudStorageFileSystemTest { + "The Heart-ache, and the thousand Natural shocks\n" + "That Flesh is heir to? 'Tis a consummation\n"; - @Before - public void before() { - CloudStorageFileSystemProvider.setGCloudOptions(LocalGcsHelper.options()); - } + private final FakeStorageRpc storage = new FakeStorageRpc(true); + private final NioTestHelper helper = new NioTestHelper(storage); @Test public void testGetPath() throws IOException { - try (FileSystem fs = CloudStorageFileSystem.forBucket("bucket")) { + try (FileSystem fs = helper.forBucket("bucket")) { assertThat(fs.getPath("/angel").toString()).isEqualTo("/angel"); assertThat(fs.getPath("/angel").toUri().toString()).isEqualTo("gs://bucket/angel"); } @@ -67,39 +60,38 @@ public void testGetPath() throws IOException { @Test public void testWrite() throws IOException { - try (FileSystem fs = CloudStorageFileSystem.forBucket("bucket")) { + try (FileSystem fs = helper.forBucket("bucket")) { Files.write(fs.getPath("/angel"), ALONE.getBytes(UTF_8)); + assertThat(new String(Files.readAllBytes(fs.getPath("/angel")), UTF_8)).isEqualTo(ALONE); } - assertThat(new String(Files.readAllBytes(Paths.get(URI.create("gs://bucket/angel"))), UTF_8)) - .isEqualTo(ALONE); } @Test public void testRead() throws IOException { - Files.write(Paths.get(URI.create("gs://bucket/angel")), ALONE.getBytes(UTF_8)); - try (FileSystem fs = CloudStorageFileSystem.forBucket("bucket")) { + try (FileSystem fs = helper.forBucket("bucket")) { + Files.write(fs.getPath("/angel"), ALONE.getBytes(UTF_8)); assertThat(new String(Files.readAllBytes(fs.getPath("/angel")), UTF_8)).isEqualTo(ALONE); } } @Test public void testExists_false() throws IOException { - try (FileSystem fs = FileSystems.getFileSystem(URI.create("gs://bucket"))) { + try (FileSystem fs = helper.forBucket("bucket")) { assertThat(Files.exists(fs.getPath("/angel"))).isFalse(); } } @Test public void testExists_true() throws IOException { - Files.write(Paths.get(URI.create("gs://bucket/angel")), ALONE.getBytes(UTF_8)); - try (FileSystem fs = CloudStorageFileSystem.forBucket("bucket")) { + try (FileSystem fs = helper.forBucket("bucket")) { + Files.write(fs.getPath("/angel"), ALONE.getBytes(UTF_8)); assertThat(Files.exists(fs.getPath("/angel"))).isTrue(); } } @Test public void testGetters() throws IOException { - try (FileSystem fs = CloudStorageFileSystem.forBucket("bucket")) { + try (FileSystem fs = helper.forBucket("bucket")) { assertThat(fs.isOpen()).isTrue(); assertThat(fs.isReadOnly()).isFalse(); assertThat(fs.getRootDirectories()).containsExactly(fs.getPath("/")); @@ -111,10 +103,10 @@ public void testGetters() throws IOException { @Test public void testEquals() throws IOException { - try (FileSystem bucket1 = CloudStorageFileSystem.forBucket("bucket"); - FileSystem bucket2 = FileSystems.getFileSystem(URI.create("gs://bucket")); - FileSystem doge1 = CloudStorageFileSystem.forBucket("doge"); - FileSystem doge2 = FileSystems.getFileSystem(URI.create("gs://doge"))) { + try (FileSystem bucket1 = helper.forBucket("bucket"); + FileSystem bucket2 = helper.forBucket("bucket"); + FileSystem doge1 = helper.forBucket("doge"); + FileSystem doge2 = helper.forBucket("doge")) { new EqualsTester() .addEqualityGroup(bucket1, bucket2) .addEqualityGroup(doge1, doge2) @@ -124,12 +116,12 @@ public void testEquals() throws IOException { @Test public void testNullness() throws IOException, NoSuchMethodException, SecurityException { - try (FileSystem fs = FileSystems.getFileSystem(URI.create("gs://bucket"))) { + try (FileSystem fs = helper.forBucket("bucket")) { NullPointerTester tester = new NullPointerTester() .ignore(CloudStorageFileSystem.class.getMethod("equals", Object.class)) - .setDefault(CloudStorageConfiguration.class, CloudStorageConfiguration.DEFAULT) - .setDefault(StorageOptions.class, LocalGcsHelper.options()); + .setDefault( + CloudStorageConfiguration.class, CloudStorageConfiguration.defaultInstance()); tester.testAllPublicStaticMethods(CloudStorageFileSystem.class); tester.testAllPublicInstanceMethods(fs); } diff --git a/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageOptionsTest.java b/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageOptionsTest.java index 411bf64170a1..2f479e68b68c 100644 --- a/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageOptionsTest.java +++ b/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageOptionsTest.java @@ -28,18 +28,16 @@ import com.google.common.testing.NullPointerTester; import com.google.gcloud.storage.Acl; -import com.google.gcloud.storage.testing.LocalGcsHelper; +import com.google.gcloud.storage.testing.FakeStorageRpc; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.io.IOException; -import java.net.URI; +import java.nio.file.FileSystem; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; /** * Unit tests for {@link CloudStorageOptions}. @@ -47,77 +45,94 @@ @RunWith(JUnit4.class) public class CloudStorageOptionsTest { - @Before - public void before() { - CloudStorageFileSystemProvider.setGCloudOptions(LocalGcsHelper.options()); - } + private final FakeStorageRpc storage = new FakeStorageRpc(true); + private final NioTestHelper helper = new NioTestHelper(storage); @Test public void testWithoutCaching() throws IOException { - Path path = Paths.get(URI.create("gs://bucket/path")); - Files.write(path, "(✿◕ ‿◕ )ノ".getBytes(UTF_8), withoutCaching()); - assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).cacheControl().get()) - .isEqualTo("no-cache"); + try (FileSystem fs = helper.forBucket("bucket")) { + Path path = fs.getPath("/path"); + Files.write(path, "(✿◕ ‿◕ )ノ".getBytes(UTF_8), withoutCaching()); + assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).cacheControl().get()) + .isEqualTo("no-cache"); + } } @Test public void testCacheControl() throws IOException { - Path path = Paths.get(URI.create("gs://bucket/path")); - Files.write(path, "(✿◕ ‿◕ )ノ".getBytes(UTF_8), withCacheControl("potato")); - assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).cacheControl().get()) - .isEqualTo("potato"); + try (FileSystem fs = helper.forBucket("bucket")) { + Path path = fs.getPath("/path"); + Files.write(path, "(✿◕ ‿◕ )ノ".getBytes(UTF_8), withCacheControl("potato")); + assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).cacheControl().get()) + .isEqualTo("potato"); + } } @Test public void testWithAcl() throws IOException { - Path path = Paths.get(URI.create("gs://bucket/path")); - Acl acl = Acl.of(new Acl.User("king@example.com"), Acl.Role.OWNER); - Files.write(path, "(✿◕ ‿◕ )ノ".getBytes(UTF_8), withAcl(acl)); - assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).acl().get()) - .contains(acl); + try (FileSystem fs = helper.forBucket("bucket")) { + Path path = fs.getPath("/path"); + Acl acl = Acl.of(new Acl.User("king@example.com"), Acl.Role.OWNER); + Files.write(path, "(✿◕ ‿◕ )ノ".getBytes(UTF_8), withAcl(acl)); + assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).acl().get()) + .contains(acl); + } } @Test public void testWithContentDisposition() throws IOException { - Path path = Paths.get(URI.create("gs://bucket/path")); - Files.write(path, "(✿◕ ‿◕ )ノ".getBytes(UTF_8), withContentDisposition("bubbly fun")); - assertThat( - Files.readAttributes(path, CloudStorageFileAttributes.class).contentDisposition().get()) - .isEqualTo("bubbly fun"); + try (FileSystem fs = helper.forBucket("bucket")) { + Path path = fs.getPath("/path"); + Files.write(path, "(✿◕ ‿◕ )ノ".getBytes(UTF_8), withContentDisposition("bubbly fun")); + assertThat( + Files.readAttributes(path, CloudStorageFileAttributes.class) + .contentDisposition() + .get()) + .isEqualTo("bubbly fun"); + } } @Test public void testWithContentEncoding() throws IOException { - Path path = Paths.get(URI.create("gs://bucket/path")); - Files.write(path, "(✿◕ ‿◕ )ノ".getBytes(UTF_8), withContentEncoding("gzip")); - assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).contentEncoding().get()) - .isEqualTo("gzip"); + try (FileSystem fs = helper.forBucket("bucket")) { + Path path = fs.getPath("/path"); + Files.write(path, "(✿◕ ‿◕ )ノ".getBytes(UTF_8), withContentEncoding("gzip")); + assertThat( + Files.readAttributes(path, CloudStorageFileAttributes.class).contentEncoding().get()) + .isEqualTo("gzip"); + } } @Test public void testWithUserMetadata() throws IOException { - Path path = Paths.get(URI.create("gs://bucket/path")); - Files.write( - path, - "(✿◕ ‿◕ )ノ".getBytes(UTF_8), - withUserMetadata("nolo", "contendere"), - withUserMetadata("eternal", "sadness")); - assertThat( - Files.readAttributes(path, CloudStorageFileAttributes.class).userMetadata().get("nolo")) - .isEqualTo("contendere"); - assertThat( - Files.readAttributes(path, CloudStorageFileAttributes.class) - .userMetadata() - .get("eternal")) - .isEqualTo("sadness"); + try (FileSystem fs = helper.forBucket("bucket")) { + Path path = fs.getPath("/path"); + Files.write( + path, + "(✿◕ ‿◕ )ノ".getBytes(UTF_8), + withUserMetadata("nolo", "contendere"), + withUserMetadata("eternal", "sadness")); + assertThat( + Files.readAttributes(path, CloudStorageFileAttributes.class) + .userMetadata() + .get("nolo")) + .isEqualTo("contendere"); + assertThat( + Files.readAttributes(path, CloudStorageFileAttributes.class) + .userMetadata() + .get("eternal")) + .isEqualTo("sadness"); + } } @Test public void testWithMimeType_string() throws IOException { - Path path = Paths.get(URI.create("gs://bucket/path")); - Files.write(path, "(✿◕ ‿◕ )ノ".getBytes(UTF_8), withMimeType("text/plain")); - assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).mimeType().get()) - .isEqualTo("text/plain"); + try (FileSystem fs = helper.forBucket("bucket")) { + Path path = fs.getPath("/path"); + Files.write(path, "(✿◕ ‿◕ )ノ".getBytes(UTF_8), withMimeType("text/plain")); + assertThat(Files.readAttributes(path, CloudStorageFileAttributes.class).mimeType().get()) + .isEqualTo("text/plain"); + } } @Test diff --git a/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStoragePathTest.java b/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStoragePathTest.java index a5c440c23772..e1a6db4bcb69 100644 --- a/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStoragePathTest.java +++ b/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStoragePathTest.java @@ -17,14 +17,15 @@ package com.google.gcloud.storage.contrib.nio; import static com.google.common.truth.Truth.assertThat; -import static com.google.gcloud.storage.contrib.nio.CloudStorageFileSystem.forBucket; +import static com.google.gcloud.storage.contrib.nio.NioTestHelper.permitEmptyPathComponents; +import static com.google.gcloud.storage.contrib.nio.NioTestHelper.stripPrefixSlash; +import static com.google.gcloud.storage.contrib.nio.NioTestHelper.workingDirectory; import com.google.common.collect.Iterables; import com.google.common.testing.EqualsTester; import com.google.common.testing.NullPointerTester; -import com.google.gcloud.storage.testing.LocalGcsHelper; +import com.google.gcloud.storage.testing.FakeStorageRpc; -import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -32,7 +33,6 @@ import org.junit.runners.JUnit4; import java.io.IOException; -import java.net.URI; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Path; @@ -46,75 +46,74 @@ public class CloudStoragePathTest { @Rule public final ExpectedException thrown = ExpectedException.none(); - @Before - public void before() { - CloudStorageFileSystemProvider.setGCloudOptions(LocalGcsHelper.options()); - } + private final FakeStorageRpc storage = new FakeStorageRpc(true); + private final NioTestHelper helper = new NioTestHelper(storage); @Test - public void testCreate_neverRemoveExtraSlashes() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testCreate_neverRemoveExtraSlashes() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("lol//cat").toString()).isEqualTo("lol//cat"); assertThat((Object) fs.getPath("lol//cat")).isEqualTo(fs.getPath("lol//cat")); } } @Test - public void testCreate_preservesTrailingSlash() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testCreate_preservesTrailingSlash() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("lol/cat/").toString()).isEqualTo("lol/cat/"); assertThat((Object) fs.getPath("lol/cat/")).isEqualTo(fs.getPath("lol/cat/")); } } @Test - public void testGetGcsFilename_empty_notAllowed() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testGetGcsFilename_empty_notAllowed() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { thrown.expect(IllegalArgumentException.class); fs.getPath("").getBlobId(); } } @Test - public void testGetGcsFilename_stripsPrefixSlash() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testGetGcsFilename_stripsPrefixSlash() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("/hi").getBlobId().name()).isEqualTo("hi"); } } @Test - public void testGetGcsFilename_overrideStripPrefixSlash_doesntStripPrefixSlash() { - try (CloudStorageFileSystem fs = forBucket("doodle", stripPrefixSlash(false))) { + public void testGetGcsFilename_overrideStripPrefixSlash_doesntStripPrefixSlash() + throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle", stripPrefixSlash(false))) { assertThat(fs.getPath("/hi").getBlobId().name()).isEqualTo("/hi"); } } @Test - public void testGetGcsFilename_extraSlashes_throwsIae() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testGetGcsFilename_extraSlashes_throwsIae() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { thrown.expect(IllegalArgumentException.class); fs.getPath("a//b").getBlobId().name(); } } @Test - public void testGetGcsFilename_overridepermitEmptyPathComponents() { - try (CloudStorageFileSystem fs = forBucket("doodle", permitEmptyPathComponents(true))) { + public void testGetGcsFilename_overridepermitEmptyPathComponents() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle", permitEmptyPathComponents(true))) { assertThat(fs.getPath("a//b").getBlobId().name()).isEqualTo("a//b"); } } @Test - public void testGetGcsFilename_freaksOutOnExtraSlashesAndDotDirs() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testGetGcsFilename_freaksOutOnExtraSlashesAndDotDirs() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { thrown.expect(IllegalArgumentException.class); fs.getPath("a//b/..").getBlobId().name(); } } @Test - public void testNameCount() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testNameCount() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("").getNameCount()).isEqualTo(1); assertThat(fs.getPath("/").getNameCount()).isEqualTo(0); assertThat(fs.getPath("/hi/").getNameCount()).isEqualTo(1); @@ -124,8 +123,8 @@ public void testNameCount() { } @Test - public void testGetName() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testGetName() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("").getName(0).toString()).isEqualTo(""); assertThat(fs.getPath("/hi").getName(0).toString()).isEqualTo("hi"); assertThat(fs.getPath("hi/there").getName(1).toString()).isEqualTo("there"); @@ -133,24 +132,24 @@ public void testGetName() { } @Test - public void testGetName_negative_throwsIae() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testGetName_negative_throwsIae() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { thrown.expect(IllegalArgumentException.class); fs.getPath("angel").getName(-1); } } @Test - public void testGetName_overflow_throwsIae() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testGetName_overflow_throwsIae() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { thrown.expect(IllegalArgumentException.class); fs.getPath("angel").getName(1); } } @Test - public void testIterator() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testIterator() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(Iterables.get(fs.getPath("/dog/mog"), 0).toString()).isEqualTo("dog"); assertThat(Iterables.get(fs.getPath("/dog/mog"), 1).toString()).isEqualTo("mog"); assertThat(Iterables.size(fs.getPath("/"))).isEqualTo(0); @@ -160,8 +159,8 @@ public void testIterator() { } @Test - public void testNormalize() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testNormalize() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("/").normalize().toString()).isEqualTo("/"); assertThat(fs.getPath("a/x/../b/x/..").normalize().toString()).isEqualTo("a/b/"); assertThat(fs.getPath("/x/x/../../♡").normalize().toString()).isEqualTo("/♡"); @@ -170,38 +169,38 @@ public void testNormalize() { } @Test - public void testNormalize_dot_becomesBlank() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testNormalize_dot_becomesBlank() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("").normalize().toString()).isEqualTo(""); assertThat(fs.getPath(".").normalize().toString()).isEqualTo(""); } } @Test - public void testNormalize_trailingSlash_isPreserved() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testNormalize_trailingSlash_isPreserved() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("o/").normalize().toString()).isEqualTo("o/"); } } @Test - public void testNormalize_doubleDot_becomesBlank() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testNormalize_doubleDot_becomesBlank() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("..").normalize().toString()).isEqualTo(""); assertThat(fs.getPath("../..").normalize().toString()).isEqualTo(""); } } @Test - public void testNormalize_extraSlashes_getRemoved() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testNormalize_extraSlashes_getRemoved() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("//life///b/good//").normalize().toString()).isEqualTo("/life/b/good/"); } } @Test - public void testToRealPath_hasDotDir_throwsIae() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testToRealPath_hasDotDir_throwsIae() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { fs.getPath("a/hi./b").toRealPath(); fs.getPath("a/.hi/b").toRealPath(); thrown.expect(IllegalArgumentException.class); @@ -211,8 +210,8 @@ public void testToRealPath_hasDotDir_throwsIae() { } @Test - public void testToRealPath_hasDotDotDir_throwsIae() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testToRealPath_hasDotDotDir_throwsIae() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { fs.getPath("a/hi../b").toRealPath(); fs.getPath("a/..hi/b").toRealPath(); thrown.expect(IllegalArgumentException.class); @@ -222,8 +221,8 @@ public void testToRealPath_hasDotDotDir_throwsIae() { } @Test - public void testToRealPath_extraSlashes_throwsIae() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testToRealPath_extraSlashes_throwsIae() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { thrown.expect(IllegalArgumentException.class); thrown.expectMessage("extra slashes"); fs.getPath("a//b").toRealPath(); @@ -231,16 +230,17 @@ public void testToRealPath_extraSlashes_throwsIae() { } @Test - public void testToRealPath_overridePermitEmptyPathComponents_extraSlashes_slashesRemain() { - try (CloudStorageFileSystem fs = forBucket("doodle", permitEmptyPathComponents(true))) { + public void testToRealPath_overridePermitEmptyPathComponents_extraSlashes_slashesRemain() + throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle", permitEmptyPathComponents(true))) { assertThat(fs.getPath("/life///b/./good/").toRealPath().toString()) .isEqualTo("life///b/./good/"); } } @Test - public void testToRealPath_permitEmptyPathComponents_doesNotNormalize() { - try (CloudStorageFileSystem fs = forBucket("doodle", permitEmptyPathComponents(true))) { + public void testToRealPath_permitEmptyPathComponents_doesNotNormalize() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle", permitEmptyPathComponents(true))) { assertThat(fs.getPath("a").toRealPath().toString()).isEqualTo("a"); assertThat(fs.getPath("a//b").toRealPath().toString()).isEqualTo("a//b"); assertThat(fs.getPath("a//./b//..").toRealPath().toString()).isEqualTo("a//./b//.."); @@ -248,45 +248,45 @@ public void testToRealPath_permitEmptyPathComponents_doesNotNormalize() { } @Test - public void testToRealPath_withWorkingDirectory_makesAbsolute() { - try (CloudStorageFileSystem fs = forBucket("doodle", workingDirectory("/lol"))) { + public void testToRealPath_withWorkingDirectory_makesAbsolute() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle", workingDirectory("/lol"))) { assertThat(fs.getPath("a").toRealPath().toString()).isEqualTo("lol/a"); } } @Test - public void testToRealPath_disableStripPrefixSlash_makesPathAbsolute() { - try (CloudStorageFileSystem fs = forBucket("doodle", stripPrefixSlash(false))) { + public void testToRealPath_disableStripPrefixSlash_makesPathAbsolute() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle", stripPrefixSlash(false))) { assertThat(fs.getPath("a").toRealPath().toString()).isEqualTo("/a"); assertThat(fs.getPath("/a").toRealPath().toString()).isEqualTo("/a"); } } @Test - public void testToRealPath_trailingSlash_getsPreserved() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testToRealPath_trailingSlash_getsPreserved() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("a/b/").toRealPath().toString()).isEqualTo("a/b/"); } } @Test - public void testNormalize_empty_returnsEmpty() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testNormalize_empty_returnsEmpty() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("").normalize().toString()).isEqualTo(""); } } @Test - public void testNormalize_preserveTrailingSlash() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testNormalize_preserveTrailingSlash() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("a/b/../c/").normalize().toString()).isEqualTo("a/c/"); assertThat(fs.getPath("a/b/./c/").normalize().toString()).isEqualTo("a/b/c/"); } } @Test - public void testGetParent_preserveTrailingSlash() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testGetParent_preserveTrailingSlash() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("a/b/c").getParent().toString()).isEqualTo("a/b/"); assertThat(fs.getPath("a/b/c/").getParent().toString()).isEqualTo("a/b/"); assertThat((Object) fs.getPath("").getParent()).isNull(); @@ -297,16 +297,16 @@ public void testGetParent_preserveTrailingSlash() { } @Test - public void testGetRoot() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testGetRoot() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("/hello").getRoot().toString()).isEqualTo("/"); assertThat((Object) fs.getPath("hello").getRoot()).isNull(); } } @Test - public void testRelativize() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testRelativize() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat( fs.getPath("/foo/bar/lol/cat").relativize(fs.getPath("/foo/a/b/../../c")).toString()) .isEqualTo("../../../a/b/../../c"); @@ -314,8 +314,8 @@ public void testRelativize() { } @Test - public void testRelativize_providerMismatch() { - try (CloudStorageFileSystem gcs = forBucket("doodle")) { + public void testRelativize_providerMismatch() throws IOException { + try (CloudStorageFileSystem gcs = helper.forBucket("doodle")) { thrown.expect(ProviderMismatchException.class); gcs.getPath("/etc").relativize(FileSystems.getDefault().getPath("/dog")); } @@ -323,63 +323,63 @@ public void testRelativize_providerMismatch() { @Test @SuppressWarnings("ReturnValueIgnored") // testing that an Exception is thrown - public void testRelativize_providerMismatch2() { - try (CloudStorageFileSystem gcs = forBucket("doodle")) { + public void testRelativize_providerMismatch2() throws IOException { + try (CloudStorageFileSystem gcs = helper.forBucket("doodle")) { thrown.expect(ProviderMismatchException.class); gcs.getPath("/dog").relativize(FileSystems.getDefault().getPath("/etc")); } } @Test - public void testResolve() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testResolve() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("/hi").resolve("there").toString()).isEqualTo("/hi/there"); assertThat(fs.getPath("hi").resolve("there").toString()).isEqualTo("hi/there"); } } @Test - public void testResolve_providerMismatch() { - try (CloudStorageFileSystem gcs = forBucket("doodle")) { + public void testResolve_providerMismatch() throws IOException { + try (CloudStorageFileSystem gcs = helper.forBucket("doodle")) { thrown.expect(ProviderMismatchException.class); gcs.getPath("etc").resolve(FileSystems.getDefault().getPath("/dog")); } } @Test - public void testIsAbsolute() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testIsAbsolute() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("/hi").isAbsolute()).isTrue(); assertThat(fs.getPath("hi").isAbsolute()).isFalse(); } } @Test - public void testToAbsolutePath() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testToAbsolutePath() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat((Object) fs.getPath("/hi").toAbsolutePath()).isEqualTo(fs.getPath("/hi")); assertThat((Object) fs.getPath("hi").toAbsolutePath()).isEqualTo(fs.getPath("/hi")); } } @Test - public void testToAbsolutePath_withWorkingDirectory() { - try (CloudStorageFileSystem fs = forBucket("doodle", workingDirectory("/lol"))) { + public void testToAbsolutePath_withWorkingDirectory() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle", workingDirectory("/lol"))) { assertThat(fs.getPath("a").toAbsolutePath().toString()).isEqualTo("/lol/a"); } } @Test - public void testGetFileName() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testGetFileName() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("/hi/there").getFileName().toString()).isEqualTo("there"); assertThat(fs.getPath("military/fashion/show").getFileName().toString()).isEqualTo("show"); } } @Test - public void testCompareTo() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testCompareTo() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("/hi/there").compareTo(fs.getPath("/hi/there"))).isEqualTo(0); assertThat(fs.getPath("/hi/there").compareTo(fs.getPath("/hi/therf"))).isEqualTo(-1); assertThat(fs.getPath("/hi/there").compareTo(fs.getPath("/hi/therd"))).isEqualTo(1); @@ -387,8 +387,8 @@ public void testCompareTo() { } @Test - public void testStartsWith() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testStartsWith() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("/hi/there").startsWith(fs.getPath("/hi/there"))).isTrue(); assertThat(fs.getPath("/hi/there").startsWith(fs.getPath("/hi/therf"))).isFalse(); assertThat(fs.getPath("/hi/there").startsWith(fs.getPath("/hi"))).isTrue(); @@ -400,8 +400,8 @@ public void testStartsWith() { } @Test - public void testEndsWith() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testEndsWith() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { assertThat(fs.getPath("/hi/there").endsWith(fs.getPath("there"))).isTrue(); assertThat(fs.getPath("/hi/there").endsWith(fs.getPath("therf"))).isFalse(); assertThat(fs.getPath("/hi/there").endsWith(fs.getPath("/blag/therf"))).isFalse(); @@ -418,8 +418,8 @@ public void testEndsWith() { @Test public void testResolve_willWorkWithRecursiveCopy() throws IOException { // See: http://stackoverflow.com/a/10068306 - try (FileSystem fsSource = FileSystems.getFileSystem(URI.create("gs://hello")); - FileSystem fsTarget = FileSystems.getFileSystem(URI.create("gs://cat"))) { + try (FileSystem fsSource = helper.forBucket("hello"); + FileSystem fsTarget = helper.forBucket("cat")) { Path targetPath = fsTarget.getPath("/some/folder/"); Path relSrcPath = fsSource.getPath("file.txt"); assertThat((Object) targetPath.resolve(relSrcPath)) @@ -430,8 +430,8 @@ public void testResolve_willWorkWithRecursiveCopy() throws IOException { @Test public void testRelativize_willWorkWithRecursiveCopy() throws IOException { // See: http://stackoverflow.com/a/10068306 - try (FileSystem fsSource = FileSystems.getFileSystem(URI.create("gs://hello")); - FileSystem fsTarget = FileSystems.getFileSystem(URI.create("gs://cat"))) { + try (FileSystem fsSource = helper.forBucket("hello"); + FileSystem fsTarget = helper.forBucket("cat")) { Path targetPath = fsTarget.getPath("/some/folder/"); Path sourcePath = fsSource.getPath("/sloth/"); Path file = fsSource.getPath("/sloth/file.txt"); @@ -441,8 +441,8 @@ public void testRelativize_willWorkWithRecursiveCopy() throws IOException { } @Test - public void testToFile_unsupported() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testToFile_unsupported() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { Path path = fs.getPath("/lol"); thrown.expect(UnsupportedOperationException.class); path.toFile(); @@ -450,8 +450,8 @@ public void testToFile_unsupported() { } @Test - public void testEquals() { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testEquals() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { new EqualsTester() // These are obviously equal. .addEqualityGroup(fs.getPath("/hello/cat"), fs.getPath("/hello/cat")) @@ -466,8 +466,8 @@ public void testEquals() { } @Test - public void testEquals_currentDirectoryIsTakenIntoConsideration() { - try (CloudStorageFileSystem fs = forBucket("doodle", workingDirectory("/hello"))) { + public void testEquals_currentDirectoryIsTakenIntoConsideration() throws IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle", workingDirectory("/hello"))) { new EqualsTester() .addEqualityGroup(fs.getPath("cat"), fs.getPath("/hello/cat")) .addEqualityGroup(fs.getPath(""), fs.getPath("/hello")) @@ -476,8 +476,8 @@ public void testEquals_currentDirectoryIsTakenIntoConsideration() { } @Test - public void testNullness() throws NoSuchMethodException, SecurityException { - try (CloudStorageFileSystem fs = forBucket("doodle")) { + public void testNullness() throws NoSuchMethodException, SecurityException, IOException { + try (CloudStorageFileSystem fs = helper.forBucket("doodle")) { NullPointerTester tester = new NullPointerTester(); tester.ignore(CloudStoragePath.class.getMethod("equals", Object.class)); tester.setDefault(Path.class, fs.getPath("sup")); @@ -485,16 +485,4 @@ public void testNullness() throws NoSuchMethodException, SecurityException { tester.testAllPublicInstanceMethods(fs.getPath("sup")); } } - - private static CloudStorageConfiguration stripPrefixSlash(boolean value) { - return CloudStorageConfiguration.builder().stripPrefixSlash(value).build(); - } - - private static CloudStorageConfiguration permitEmptyPathComponents(boolean value) { - return CloudStorageConfiguration.builder().permitEmptyPathComponents(value).build(); - } - - private static CloudStorageConfiguration workingDirectory(String value) { - return CloudStorageConfiguration.builder().workingDirectory(value).build(); - } } diff --git a/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageReadChannelTest.java b/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageReadChannelTest.java index be6cf58e24a8..82940095d972 100644 --- a/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageReadChannelTest.java +++ b/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/CloudStorageReadChannelTest.java @@ -22,14 +22,12 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import com.google.gcloud.ReadChannel; import com.google.gcloud.storage.Blob; import com.google.gcloud.storage.BlobId; -import com.google.gcloud.storage.BlobInfo; import com.google.gcloud.storage.Storage; import org.junit.Before; diff --git a/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/NioTestHelper.java b/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/NioTestHelper.java new file mode 100644 index 000000000000..4ddabe557e50 --- /dev/null +++ b/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/NioTestHelper.java @@ -0,0 +1,63 @@ +package com.google.gcloud.storage.contrib.nio; + +import com.google.gcloud.spi.ServiceRpcFactory; +import com.google.gcloud.storage.Storage; +import com.google.gcloud.storage.StorageOptions; +import com.google.gcloud.storage.spi.StorageRpc; + +/** + * Helper for creating NIO file system instances without using the SPI. + * + *

There's no way to create perfect isolation between unit tests when using the Java SPI, because + * it stores a list of loaded provider instances. We instead rely on integration tests to test our + * usage of the SPI. + */ +final class NioTestHelper { + + // Within a unit test we use the same provider for multiple file systems. Having a different + // provider instance causes the behavior of many operations, such as Files.copy, to change + // dramatically. + private final CloudStorageFileSystemProvider provider; + + NioTestHelper(StorageRpc storage) { + this.provider = new CloudStorageFileSystemProvider(makeStorage(storage)); + } + + CloudStorageFileSystem forBucket(String bucket) { + return forBucket(bucket, CloudStorageConfiguration.defaultInstance()); + } + + CloudStorageFileSystem forBucket(String bucket, CloudStorageConfiguration config) { + return new CloudStorageFileSystem(provider, config, bucket); + } + + private static Storage makeStorage(final StorageRpc storageRpc) { + return StorageOptions.builder() + .projectId("dummy-project-for-testing") + .serviceRpcFactory( + new ServiceRpcFactory() { + @Override + public StorageRpc create(StorageOptions options) { + return storageRpc; + } + }) + .build() + .service(); + } + + static CloudStorageConfiguration stripPrefixSlash(boolean value) { + return CloudStorageConfiguration.builder().stripPrefixSlash(value).build(); + } + + static CloudStorageConfiguration permitEmptyPathComponents(boolean value) { + return CloudStorageConfiguration.builder().permitEmptyPathComponents(value).build(); + } + + static CloudStorageConfiguration workingDirectory(String value) { + return CloudStorageConfiguration.builder().workingDirectory(value).build(); + } + + static CloudStorageConfiguration usePseudoDirectories(boolean value) { + return CloudStorageConfiguration.builder().usePseudoDirectories(value).build(); + } +} diff --git a/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/it/ITGcsNio.java b/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/it/ITGcsNio.java index e305b7373b58..6368d9b4f19d 100644 --- a/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/it/ITGcsNio.java +++ b/gcloud-java-contrib/gcloud-java-nio/src/test/java/com/google/gcloud/storage/contrib/nio/it/ITGcsNio.java @@ -8,7 +8,6 @@ import com.google.gcloud.storage.BucketInfo; import com.google.gcloud.storage.Storage; import com.google.gcloud.storage.StorageOptions; -import com.google.gcloud.storage.contrib.nio.CloudStorageConfiguration; import com.google.gcloud.storage.contrib.nio.CloudStorageFileSystem; import com.google.gcloud.storage.testing.RemoteGcsHelper; @@ -24,12 +23,14 @@ import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; +import java.net.URI; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; import java.nio.channels.SeekableByteChannel; import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.Arrays; import java.util.List; @@ -39,64 +40,63 @@ import java.util.logging.Level; import java.util.logging.Logger; - /** - * Integration test for gcloud-nio. This test actually talks to GCS (you need an account). - * Tests both reading and writing. - * - * You *must* set the GOOGLE_APPLICATION_CREDENTIALS environment variable - * for this test to work. It must contain the name of a local file that contains - * your Service Account JSON Key. + * Integration test for gcloud-nio. * - * The instructions for how to get the Service Account JSON Key are - * at https://cloud.google.com/storage/docs/authentication?hl=en#service_accounts + *

This test actually talks to GCS (you need an account) and tests both reading and writing. You + * *must* set the {@code GOOGLE_APPLICATION_CREDENTIALS} environment variable for this test to work. + * It must contain the name of a local file that contains your Service Account JSON Key. * - * The short version is this: go to cloud.google.com/console, - * select your project, search for "API manager", click "Credentials", - * click "create credentials/service account key", new service account, - * JSON. The contents of the file that's sent to your browsers is your - * "Service Account JSON Key". + *

The instructions for how to get the Service Account JSON Key are + * here. * + *

The short version is this: go to Cloud Console, + * select your project, search for "API manager", click "Credentials", click "create + * credentials/service account key", new service account, JSON. The contents of the file that's sent + * to your browsers is your "Service Account JSON Key". */ @RunWith(JUnit4.class) +@SuppressWarnings("resource") public class ITGcsNio { - private static final List FILE_CONTENTS = ImmutableList.of( - "Tous les êtres humains naissent libres et égaux en dignité et en droits.", - "Ils sont doués de raison et de conscience et doivent agir ", - "les uns envers les autres dans un esprit de fraternité."); + private static final List FILE_CONTENTS = + ImmutableList.of( + "Tous les êtres humains naissent libres et égaux en dignité et en droits.", + "Ils sont doués de raison et de conscience et doivent agir ", + "les uns envers les autres dans un esprit de fraternité."); - private static final Logger log = Logger.getLogger(ITGcsNio.class.getName()); - private static final String BUCKET = RemoteGcsHelper.generateBucketName(); private static final String SML_FILE = "tmp-test-small-file.txt"; private static final int SML_SIZE = 100; - // it's big, relatively speaking. - private static final String BIG_FILE = "tmp-test-big-file.txt"; - // arbitrary size that's not too round. - private static final int BIG_SIZE = 2 * 1024 * 1024 - 50; + private static final String BIG_FILE = "tmp-test-big-file.txt"; // it's big, relatively speaking. + private static final int BIG_SIZE = 2 * 1024 * 1024 - 50; // arbitrary size that's not too round. private static final String PREFIX = "tmp-test-file"; + + private static final Logger logger = Logger.getLogger(ITGcsNio.class.getName()); + private static final Random random = new Random(); + + private static String bucket; private static Storage storage; private static StorageOptions storageOptions; - private final Random rnd = new Random(); - @BeforeClass - public static void beforeClass() throws IOException { + public static void beforeClass() { + bucket = RemoteGcsHelper.generateBucketName(); // loads the credentials from local disk as par README RemoteGcsHelper gcsHelper = RemoteGcsHelper.create(); storageOptions = gcsHelper.options(); storage = storageOptions.service(); // create and populate test bucket - storage.create(BucketInfo.of(BUCKET)); + storage.create(BucketInfo.of(bucket)); fillFile(storage, SML_FILE, SML_SIZE); fillFile(storage, BIG_FILE, BIG_SIZE); } @AfterClass public static void afterClass() throws ExecutionException, InterruptedException { - if (storage != null && !RemoteGcsHelper.forceDelete(storage, BUCKET, 5, TimeUnit.SECONDS) && - log.isLoggable(Level.WARNING)) { - log.log(Level.WARNING, "Deletion of bucket {0} timed out, bucket is not empty", BUCKET); + if (storage != null + && !RemoteGcsHelper.forceDelete(storage, bucket, 5, TimeUnit.SECONDS) + && logger.isLoggable(Level.WARNING)) { + logger.log(Level.WARNING, "Deletion of bucket {0} timed out, bucket is not empty", bucket); } } @@ -106,27 +106,33 @@ private static byte[] randomContents(int size) { return bytes; } - private static void fillFile(Storage storage, String fname, int size) throws IOException { - storage.create(BlobInfo.builder(BUCKET, fname).build(), randomContents(size)); + private static void fillFile(Storage storage, String fname, int size) { + storage.create(BlobInfo.builder(bucket, fname).build(), randomContents(size)); } @Test - public void testFileExists() throws IOException { - CloudStorageFileSystem testBucket = getTestBucket(); + public void testFileExists() { + CloudStorageFileSystem testBucket = CloudStorageFileSystem.forBucket(bucket); Path path = testBucket.getPath(SML_FILE); assertThat(Files.exists(path)).isTrue(); } + @Test + public void testFileExistsUsingSpi() { + Path path = Paths.get(URI.create(String.format("gs://%s/%s", bucket, SML_FILE))); + assertThat(Files.exists(path)).isTrue(); + } + @Test public void testFileSize() throws IOException { - CloudStorageFileSystem testBucket = getTestBucket(); + CloudStorageFileSystem testBucket = CloudStorageFileSystem.forBucket(bucket); Path path = testBucket.getPath(SML_FILE); assertThat(Files.size(path)).isEqualTo(SML_SIZE); } @Test(timeout = 60_000) public void testReadByteChannel() throws IOException { - CloudStorageFileSystem testBucket = getTestBucket(); + CloudStorageFileSystem testBucket = CloudStorageFileSystem.forBucket(bucket); Path path = testBucket.getPath(SML_FILE); long size = Files.size(path); SeekableByteChannel chan = Files.newByteChannel(path, StandardOpenOption.READ); @@ -152,7 +158,7 @@ public void testReadByteChannel() throws IOException { @Test public void testSeek() throws IOException { - CloudStorageFileSystem testBucket = getTestBucket(); + CloudStorageFileSystem testBucket = CloudStorageFileSystem.forBucket(bucket); Path path = testBucket.getPath(BIG_FILE); int size = BIG_SIZE; byte[] contents = randomContents(size); @@ -181,7 +187,7 @@ public void testSeek() throws IOException { @Test public void testCreate() throws IOException { - CloudStorageFileSystem testBucket = getTestBucket(); + CloudStorageFileSystem testBucket = CloudStorageFileSystem.forBucket(bucket); Path path = testBucket.getPath(PREFIX + randomSuffix()); // file shouldn't exist initially. If it does it's either because it's a leftover // from a previous run (so we should delete the file) @@ -203,7 +209,7 @@ public void testCreate() throws IOException { @Test public void testWrite() throws IOException { - CloudStorageFileSystem testBucket = getTestBucket(); + CloudStorageFileSystem testBucket = CloudStorageFileSystem.forBucket(bucket); Path path = testBucket.getPath(PREFIX + randomSuffix()); // file shouldn't exist initially. If it does it's either because it's a leftover // from a previous run (so we should delete the file) @@ -235,7 +241,7 @@ public void testWrite() throws IOException { @Test public void testCreateAndWrite() throws IOException { - CloudStorageFileSystem testBucket = getTestBucket(); + CloudStorageFileSystem testBucket = CloudStorageFileSystem.forBucket(bucket); Path path = testBucket.getPath(PREFIX + randomSuffix()); // file shouldn't exist initially (see above). assertThat(Files.exists(path)).isFalse(); @@ -264,7 +270,7 @@ public void testCreateAndWrite() throws IOException { @Test public void testWriteOnClose() throws Exception { - CloudStorageFileSystem testBucket = getTestBucket(); + CloudStorageFileSystem testBucket = CloudStorageFileSystem.forBucket(bucket); Path path = testBucket.getPath(PREFIX + randomSuffix()); // file shouldn't exist initially (see above) assertThat(Files.exists(path)).isFalse(); @@ -298,7 +304,7 @@ public void testWriteOnClose() throws Exception { @Test public void testCopy() throws IOException { - CloudStorageFileSystem testBucket = getTestBucket(); + CloudStorageFileSystem testBucket = CloudStorageFileSystem.forBucket(bucket); Path src = testBucket.getPath(SML_FILE); Path dst = testBucket.getPath(PREFIX + randomSuffix()); // file shouldn't exist initially (see above). @@ -332,21 +338,6 @@ private int readFully(ReadableByteChannel chan, byte[] outputBuf) throws IOExcep } private String randomSuffix() { - return "-" + rnd.nextInt(99999); - } - - - private CloudStorageFileSystem getTestBucket() throws IOException { - // in typical usage we use the single-argument version of forBucket - // and rely on the user being logged into their project with the - // gcloud tool, and then everything authenticates automagically - // (or we just use paths that start with "gs://" and rely on NIO's magic). - // - // However for the tests we want to be able to run in automated environments - // where we can set environment variables but not necessarily install gcloud - // or run it. That's why we're setting the credentials programmatically. - return CloudStorageFileSystem.forBucket( - BUCKET, CloudStorageConfiguration.DEFAULT, storageOptions); + return "-" + random.nextInt(99999); } - } diff --git a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/testing/FakeStorageRpc.java b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/testing/FakeStorageRpc.java index b874a467f962..f2f47cbaed5e 100644 --- a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/testing/FakeStorageRpc.java +++ b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/testing/FakeStorageRpc.java @@ -18,9 +18,11 @@ import com.google.api.services.storage.model.Bucket; import com.google.api.services.storage.model.StorageObject; -import com.google.gcloud.storage.spi.StorageRpc; +import com.google.common.collect.Maps; +import com.google.common.io.ByteStreams; import com.google.gcloud.storage.Storage; import com.google.gcloud.storage.StorageException; +import com.google.gcloud.storage.spi.StorageRpc; import java.io.IOException; import java.io.InputStream; @@ -33,36 +35,31 @@ import javax.annotation.concurrent.NotThreadSafe; /** - * A bare-bones in-memory implementation of Storage, meant for testing. - * See LocalGcsHelper. - * - * This class is NOT thread-safe. + * Bare-bones in-memory implementation of {@link Storage} for testing. */ @NotThreadSafe -public class FakeStorageRpc implements StorageRpc { +public final class FakeStorageRpc implements StorageRpc { + + // TODO(#829): Generation support. // fullname -> metadata - Map stuff = new HashMap<>(); + private final Map stuff = new HashMap<>(); + // fullname -> contents - Map contents = new HashMap<>(); + private final Map contents = new HashMap<>(); + // fullname -> future contents that will be visible on close. - Map futureContents = new HashMap<>(); + private final Map futureContents = new HashMap<>(); private final boolean throwIfOption; /** - * @param throwIfOption if true, we throw when given any option. + * @param throwIfOption if true, we throw when given any option */ public FakeStorageRpc(boolean throwIfOption) { this.throwIfOption = throwIfOption; } - // remove all files - void reset() { - stuff = new HashMap<>(); - contents = new HashMap<>(); - } - @Override public Bucket create(Bucket bucket, Map options) throws StorageException { throw new UnsupportedOperationException(); @@ -75,7 +72,7 @@ public StorageObject create(StorageObject object, InputStream content, Map options) throws StorageException public StorageObject get(StorageObject object, Map options) throws StorageException { // we allow the "ID" option because we need to, but then we give a whole answer anyways // because the caller won't mind the extra fields. - if (throwIfOption && !options.isEmpty() && options.size()>1 - && options.keySet().toArray()[0] != Storage.BlobGetOption.fields(Storage.BlobField.ID)) { + if (throwIfOption && !options.isEmpty() && options.size() > 1 + && !options.keySet().toArray()[0] + .equals(Storage.BlobGetOption.fields(Storage.BlobField.ID))) { throw new UnsupportedOperationException(); } @@ -203,17 +201,7 @@ public Tuple read( @Override public String open(StorageObject object, Map options) throws StorageException { String key = fullname(object); - boolean mustNotExist = false; - for (Option option : options.keySet()) { - if (option instanceof StorageRpc.Option) { - // this is a bit of a hack, since we don't implement generations. - if ((StorageRpc.Option) option == Option.IF_GENERATION_MATCH - && ((Long) options.get(option)).longValue() == 0L) { - mustNotExist = true; - } - } - } - if (mustNotExist && stuff.containsKey(key)) { + if (wantsObjectToNotExist(options) && stuff.containsKey(key)) { throw new StorageException(new FileAlreadyExistsException(key)); } stuff.put(key, object); @@ -252,19 +240,8 @@ public RewriteResponse openRewrite(RewriteRequest rewriteRequest) throws Storage throw new StorageException(404, "File not found: " + sourceKey); } - boolean mustNotExist = false; - for (Option option : rewriteRequest.targetOptions.keySet()) { - if (option instanceof StorageRpc.Option) { - // this is a bit of a hack, since we don't implement generations. - if ((StorageRpc.Option) option == Option.IF_GENERATION_MATCH - && ((Long) rewriteRequest.targetOptions.get(option)).longValue() == 0L) { - mustNotExist = true; - } - } - } - String destKey = fullname(rewriteRequest.target); - if (mustNotExist && contents.containsKey(destKey)) { + if (wantsObjectToNotExist(rewriteRequest.targetOptions) && contents.containsKey(destKey)) { throw new StorageException(new FileAlreadyExistsException(destKey)); } @@ -290,4 +267,16 @@ private void potentiallyThrow(Map options) throws UnsupportedOperatio throw new UnsupportedOperationException(); } } + + /** + * Returns {@code true} if {@code options} request that object being created must not exist. + * + *

Quoth Object Versioning + * Docs: If you set the {@code x-goog-if-generation-match} header to {@code 0} when uploading + * an object, Google Cloud Storage only performs the specified request if the object does not + * currently exist. + */ + private static boolean wantsObjectToNotExist(Map options) { + return options.entrySet().contains(Maps.immutableEntry(Option.IF_GENERATION_MATCH, 0L)); + } } diff --git a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/testing/LocalGcsHelper.java b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/testing/LocalGcsHelper.java deleted file mode 100644 index 7749ad160096..000000000000 --- a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/testing/LocalGcsHelper.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2015 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.gcloud.storage.testing; - -import com.google.gcloud.spi.ServiceRpcFactory; -import com.google.gcloud.storage.spi.StorageRpc; -import com.google.gcloud.storage.StorageOptions; - -/** - * Utility to create an in-memory storage configuration for testing. Storage options can be - * obtained via the {@link #options()} method. Returned options will point to FakeStorageRpc. - */ -public class LocalGcsHelper { - - // used for testing. Will throw if you pass it an option. - private static final FakeStorageRpc instance = new FakeStorageRpc(true); - - /** - * Returns a {@link StorageOptions} that use the static FakeStorageRpc instance, - * and resets it first so you start from a clean slate. - * That instance will throw if you pass it any option. * - */ - public static StorageOptions options() { - instance.reset(); - return StorageOptions.builder() - .projectId("dummy-project-for-testing") - .serviceRpcFactory( - new ServiceRpcFactory() { - @Override - public StorageRpc create(StorageOptions options) { - return instance; - } - }) - .build(); - } - - /** - * Returns a {@link StorageOptions} that creates a new FakeStorageRpc instance - * with the given option. - */ - public static StorageOptions customOptions(final boolean throwIfOptions) { - return StorageOptions.builder() - .projectId("dummy-project-for-testing") - .serviceRpcFactory( - new ServiceRpcFactory() { - @Override - public StorageRpc create(StorageOptions options) { - return new FakeStorageRpc(throwIfOptions); - } - }) - .build(); - } - -}