Repository: googleapis/java-storage-nio
Pull request #724 (2021-09-27 15:40:33)

build: add jdk 17 to java units and dependency builds (#1216)


Patch:
diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml
index 9fb406b..284c8b6 100644
--- a/.github/.OwlBot.lock.yaml
+++ b/.github/.OwlBot.lock.yaml
@@ -1,3 +1,3 @@
 docker:
   image: gcr.io/repo-automation-bots/owlbot-java:latest
-  digest: sha256:52b5557b7155a80e6f1684c2376d5eef0df6d8d5c785551e1ff8cc000603b62a
+  digest: sha256:13b7387edb404234610d30473ac48210ae7fe42a136335ee2b2f8a07c4c7f6a5
diff --git a/.github/blunderbuss.yml b/.github/blunderbuss.yml
index 1a23ea4..2176b05 100644
--- a/.github/blunderbuss.yml
+++ b/.github/blunderbuss.yml
@@ -1,5 +1,5 @@
 # Configuration for the Blunderbuss GitHub app. For more info see
-# https://github.com/googleapis/repo-automation-bots/tree/master/packages/blunderbuss
+# https://github.com/googleapis/repo-automation-bots/tree/main/packages/blunderbuss
 assign_prs_by:
 - labels:
   - samples
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 3becb5c..2425d72 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -1,7 +1,7 @@
 on:
   push:
     branches:
-    - master
+    - main
   pull_request:
 name: ci
 jobs:
@@ -9,14 +9,15 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        java: [8, 11]
+        java: [8, 11, 17]
     steps:
     - uses: actions/checkout@v2
     - uses: stCarolas/setup-maven@v4
       with:
         maven-version: 3.8.1
-    - uses: actions/setup-java@v1
+    - uses: actions/setup-java@v2
       with:
+        distribution: zulu
         java-version: ${{matrix.java}}
     - run: java -version
     - run: .kokoro/build.sh
@@ -29,8 +30,9 @@ jobs:
     - uses: stCarolas/setup-maven@v4
       with:
         maven-version: 3.8.1
-    - uses: actions/setup-java@v1
+    - uses: actions/setup-java@v2
       with:
+        distribution: zulu
         java-version: 8
     - run: java -version
     - run: .kokoro/build.bat
@@ -40,14 +42,15 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        java: [8, 11]
+        java: [8, 11, 17]
     steps:
     - uses: actions/checkout@v2
     - uses: stCarolas/setup-maven@v4
       with:
         maven-version: 3.8.1
-    - uses: actions/setup-java@v1
+    - uses: actions/setup-java@v2
       with:
+        distribution: zulu
         java-version: ${{matrix.java}}
     - run: java -version
     - run: .kokoro/dependencies.sh
@@ -58,8 +61,9 @@ jobs:
     - uses: stCarolas/setup-maven@v4
       with:
         maven-version: 3.8.1
-    - uses: actions/setup-java@v1
+    - uses: actions/setup-java@v2
       with:
+        distribution: zulu
         java-version: 8
     - run: java -version
     - run: .kokoro/build.sh
@@ -72,8 +76,9 @@ jobs:
     - uses: stCarolas/setup-maven@v4
       with:
         maven-version: 3.8.1
-    - uses: actions/setup-java@v1
+    - uses: actions/setup-java@v2
       with:
+        distribution: zulu
         java-version: 8
     - run: java -version
     - run: .kokoro/build.sh
diff --git a/.kokoro/dependencies.sh b/.kokoro/dependencies.sh
index 9030ba8..9a5105d 100755
--- a/.kokoro/dependencies.sh
+++ b/.kokoro/dependencies.sh
@@ -28,7 +28,28 @@ source ${scriptDir}/common.sh
 java -version
 echo $JOB_TYPE
 
-export MAVEN_OPTS="-Xmx1024m -XX:MaxPermSize=128m"
+function determineMavenOpts() {
+  local javaVersion=$(
+    # filter down to the version line, then pull out the version between quotes,
+    # then trim the version number down to its minimal number (removing any
+    # update or suffix number).
+    java -version 2>&1 | grep "version" \
+      | sed -E 's/^.*"(.*?)".*$/\1/g' \
+      | sed -E 's/^(1\.[0-9]\.0).*$/\1/g'
+  )
+
+  case $javaVersion in
+    "17")
+      # MaxPermSize is no longer supported as of jdk 17
+      echo -n "-Xmx1024m"
+      ;;
+    *)
+      echo -n "-Xmx1024m -XX:MaxPermSize=128m"
+      ;;
+  esac
+}
+
+export MAVEN_OPTS=$(determineMavenOpts)
 
 # this should run maven enforcer
 retry_with_backoff 3 10 \
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9644548..7ce2695 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,20 @@
 # Changelog
 
+### [0.123.13](https://www.github.com/googleapis/java-storage-nio/compare/v0.123.12...v0.123.13) (2021-09-27)
+
+
+### Bug Fixes
+
+* make CloudStorageFileSystem#forBucket thread safe ([#719](https://www.github.com/googleapis/java-storage-nio/issues/719)) ([ac8bfee](https://www.github.com/googleapis/java-storage-nio/commit/ac8bfeee367269a06d67c7a81adc770fb5bd83e4)), closes [#691](https://www.github.com/googleapis/java-storage-nio/issues/691) [#698](https://www.github.com/googleapis/java-storage-nio/issues/698)
+
+
+### Dependencies
+
+* update dependency com.google.apis:google-api-services-storage to v1-rev20210914-1.32.1 ([#711](https://www.github.com/googleapis/java-storage-nio/issues/711)) ([1b6e324](https://www.github.com/googleapis/java-storage-nio/commit/1b6e3241c8950ba9255074efa3356b81818f514f))
+* update dependency com.google.cloud:google-cloud-shared-dependencies to v2.3.0 ([#715](https://www.github.com/googleapis/java-storage-nio/issues/715)) ([2f42aa8](https://www.github.com/googleapis/java-storage-nio/commit/2f42aa8cf29af5d593285ba0c69902771b60c393))
+* update dependency com.google.cloud:google-cloud-storage to v2.1.4 ([#713](https://www.github.com/googleapis/java-storage-nio/issues/713)) ([7ae21d0](https://www.github.com/googleapis/java-storage-nio/commit/7ae21d0032c5c1b65f07c45b4c9d631dd19bedf8))
+* update dependency com.google.cloud:google-cloud-storage to v2.1.5 ([#716](https://www.github.com/googleapis/java-storage-nio/issues/716)) ([f3f2037](https://www.github.com/googleapis/java-storage-nio/commit/f3f2037af5b889d0e70afff730848cbd073e21e4))
+
 ### [0.123.12](https://www.github.com/googleapis/java-storage-nio/compare/v0.123.11...v0.123.12) (2021-09-15)
 
 
diff --git a/google-cloud-nio-examples/pom.xml b/google-cloud-nio-examples/pom.xml
index 0feebc1..0f4dfda 100644
--- a/google-cloud-nio-examples/pom.xml
+++ b/google-cloud-nio-examples/pom.xml
@@ -2,7 +2,7 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <artifactId>google-cloud-nio-examples</artifactId>
-  <version>0.123.13-SNAPSHOT</version><!-- {x-version-update:google-cloud-nio:current} -->
+  <version>0.123.14-SNAPSHOT</version><!-- {x-version-update:google-cloud-nio:current} -->
   <packaging>jar</packaging>
   <name>Google Cloud NIO Examples</name>
   <url>https://github.com/googleapis/java-storage-nio</url>
@@ -13,13 +13,13 @@
   <parent>
     <groupId>com.google.cloud</groupId>
     <artifactId>google-cloud-nio-parent</artifactId>
-    <version>0.123.13-SNAPSHOT</version><!-- {x-version-update:google-cloud-nio:current} -->
+    <version>0.123.14-SNAPSHOT</version><!-- {x-version-update:google-cloud-nio:current} -->
   </parent>
   <dependencies>
     <dependency>
       <groupId>com.google.guava</groupId>
       <artifactId>guava</artifactId>
-      <version>30.1-android</version>
+      <version>31.0-android</version>
     </dependency>
   </dependencies>
   <properties>
diff --git a/google-cloud-nio-retrofit/pom.xml b/google-cloud-nio-retrofit/pom.xml
index 9fe2448..c097b00 100644
--- a/google-cloud-nio-retrofit/pom.xml
+++ b/google-cloud-nio-retrofit/pom.xml
@@ -2,7 +2,7 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <artifactId>google-cloud-nio-retrofit</artifactId>
-  <version>0.123.13-SNAPSHOT</version><!-- {x-version-update:google-cloud-nio:current} -->
+  <version>0.123.14-SNAPSHOT</version><!-- {x-version-update:google-cloud-nio:current} -->
   <packaging>jar</packaging>
   <name>Google Cloud NIO Retrofit Example</name>
   <url>https://github.com/googleapis/java-storage-nio</url>
@@ -12,7 +12,7 @@
   <parent>
     <groupId>com.google.cloud</groupId>
     <artifactId>google-cloud-nio-parent</artifactId>
-    <version>0.123.13-SNAPSHOT</version><!-- {x-version-update:google-cloud-nio:current} -->
+    <version>0.123.14-SNAPSHOT</version><!-- {x-version-update:google-cloud-nio:current} -->
   </parent>
   <properties>
     <site.installationModule>google-cloud-nio-retrofit</site.installationModule>
diff --git a/google-cloud-nio/pom.xml b/google-cloud-nio/pom.xml
index 6463539..aaa52eb 100644
--- a/google-cloud-nio/pom.xml
+++ b/google-cloud-nio/pom.xml
@@ -2,7 +2,7 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <artifactId>google-cloud-nio</artifactId>
-  <version>0.123.13-SNAPSHOT</version><!-- {x-version-update:google-cloud-nio:current} -->
+  <version>0.123.14-SNAPSHOT</version><!-- {x-version-update:google-cloud-nio:current} -->
   <packaging>jar</packaging>
   <name>Google Cloud NIO</name>
   <url>https://github.com/googleapis/java-storage-nio</url>
@@ -12,7 +12,7 @@
   <parent>
     <groupId>com.google.cloud</groupId>
     <artifactId>google-cloud-nio-parent</artifactId>
-    <version>0.123.13-SNAPSHOT</version><!-- {x-version-update:google-cloud-nio:current} -->
+    <version>0.123.14-SNAPSHOT</version><!-- {x-version-update:google-cloud-nio:current} -->
   </parent>
   <properties>
     <site.installationModule>google-cloud-nio</site.installationModule>
@@ -71,6 +71,12 @@
       <artifactId>truth</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>com.google.auth</groupId>
+      <artifactId>google-auth-library-credentials</artifactId>
+      <scope>test</scope>
+    </dependency>
+
     <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-core</artifactId>
diff --git a/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystem.java b/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystem.java
index 8c1a13d..4718318 100644
--- a/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystem.java
+++ b/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystem.java
@@ -18,6 +18,7 @@ package com.google.cloud.storage.contrib.nio;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.Objects.requireNonNull;
 
 import com.google.api.gax.paging.Page;
 import com.google.cloud.storage.Bucket;
@@ -25,7 +26,11 @@ import com.google.cloud.storage.Storage;
 import com.google.cloud.storage.StorageException;
 import com.google.cloud.storage.StorageOptions;
 import com.google.common.base.Strings;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.UncheckedExecutionException;
 import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -38,10 +43,9 @@ import java.nio.file.WatchService;
 import java.nio.file.attribute.FileTime;
 import java.nio.file.attribute.UserPrincipalLookupService;
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.ExecutionException;
 import javax.annotation.CheckReturnValue;
 import javax.annotation.Nullable;
 import javax.annotation.concurrent.ThreadSafe;
@@ -66,8 +70,21 @@ public final class CloudStorageFileSystem extends FileSystem {
   private final CloudStorageFileSystemProvider provider;
   private final String bucket;
   private final CloudStorageConfiguration config;
-  private static final Map<CloudStorageConfiguration, Set<CloudStorageFileSystemProvider>>
-      CONFIG_TO_PROVIDERS_MAP = new HashMap<>();
+  private static final LoadingCache<ProviderCacheKey, CloudStorageFileSystemProvider>
+      PROVIDER_CACHE_BY_CONFIG =
+          CacheBuilder.newBuilder()
+              .build(
+                  new CacheLoader<ProviderCacheKey, CloudStorageFileSystemProvider>() {
+                    @Override
+                    public CloudStorageFileSystemProvider load(ProviderCacheKey key) {
+                      CloudStorageConfiguration config = key.cloudStorageConfiguration;
+                      StorageOptions storageOptions = key.storageOptions;
+                      String userProject = config.userProject();
+                      return (storageOptions == null)
+                          ? new CloudStorageFileSystemProvider(userProject)
+                          : new CloudStorageFileSystemProvider(userProject, storageOptions);
+                    }
+                  });
 
   // Users can change this: then this affects every filesystem object created
   // later, including via SPI. This is meant to be done only once, at the beginning
@@ -144,32 +161,7 @@ public final class CloudStorageFileSystem extends FileSystem {
    */
   @CheckReturnValue
   public static CloudStorageFileSystem forBucket(String bucket, CloudStorageConfiguration config) {
-    checkArgument(
-        !bucket.startsWith(URI_SCHEME + ":"), "Bucket name must not have schema: %s", bucket);
-    checkNotNull(config);
-    return new CloudStorageFileSystem(
-        getCloudStorageFileSystemProvider(config, null), bucket, config);
-  }
-
-  private static CloudStorageFileSystemProvider getCloudStorageFileSystemProvider(
-      CloudStorageConfiguration config, StorageOptions storageOptions) {
-    CloudStorageFileSystemProvider newProvider =
-        (storageOptions == null)
-            ? new CloudStorageFileSystemProvider(config.userProject())
-            : new CloudStorageFileSystemProvider(config.userProject(), storageOptions);
-    Set<CloudStorageFileSystemProvider> existingProviders = CONFIG_TO_PROVIDERS_MAP.get(config);
-    if (existingProviders == null) {
-      existingProviders = new HashSet<>();
-    } else {
-      for (CloudStorageFileSystemProvider existiningProvider : existingProviders) {
-        if (existiningProvider.equals(newProvider)) {
-          return existiningProvider;
-        }
-      }
-    }
-    existingProviders.add(newProvider);
-    CONFIG_TO_PROVIDERS_MAP.put(config, existingProviders);
-    return newProvider;
+    return forBucket(bucket, config, null);
   }
 
   /**
@@ -192,8 +184,16 @@ public final class CloudStorageFileSystem extends FileSystem {
       String bucket, CloudStorageConfiguration config, @Nullable StorageOptions storageOptions) {
     checkArgument(
         !bucket.startsWith(URI_SCHEME + ":"), "Bucket name must not have schema: %s", bucket);
-    return new CloudStorageFileSystem(
-        getCloudStorageFileSystemProvider(config, storageOptions), bucket, checkNotNull(config));
+    checkNotNull(config);
+    CloudStorageFileSystemProvider result;
+    ProviderCacheKey providerCacheKey = new ProviderCacheKey(config, storageOptions);
+    try {
+      result = PROVIDER_CACHE_BY_CONFIG.get(providerCacheKey);
+    } catch (ExecutionException | UncheckedExecutionException e) {
+      throw new IllegalStateException(
+          "Unable to resolve CloudStorageFileSystemProvider for the provided configuration", e);
+    }
+    return new CloudStorageFileSystem(result, bucket, config);
   }
 
   CloudStorageFileSystem(
@@ -335,4 +335,50 @@ public final class CloudStorageFileSystem extends FileSystem {
       throw new AssertionError(e);
     }
   }
+
+  /**
+   * In order to cache a {@link CloudStorageFileSystemProvider} we track the config used to
+   * instantiate that provider. This class creates an immutable key encapsulating the config to
+   * allow reliable resolution from the cache.
+   */
+  private static final class ProviderCacheKey {
+    private final CloudStorageConfiguration cloudStorageConfiguration;
+    @Nullable private final StorageOptions storageOptions;
+
+    public ProviderCacheKey(
+        CloudStorageConfiguration cloudStorageConfiguration,
+        @Nullable StorageOptions storageOptions) {
+      this.cloudStorageConfiguration =
+          requireNonNull(cloudStorageConfiguration, "cloudStorageConfiguration must be non null");
+      this.storageOptions = storageOptions;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (this == o) {
+        return true;
+      }
+      if (!(o instanceof ProviderCacheKey)) {
+        return false;
+      }
+      ProviderCacheKey that = (ProviderCacheKey) o;
+      return cloudStorageConfiguration.equals(that.cloudStorageConfiguration)
+          && Objects.equals(storageOptions, that.storageOptions);
+    }
+
+    @Override
+    public int hashCode() {
+      return Objects.hash(cloudStorageConfiguration, storageOptions);
+    }
+
+    @Override
+    public String toString() {
+      return "ConfigTuple{"
+          + "cloudStorageConfiguration="
+          + cloudStorageConfiguration
+          + ", storageOptions="
+          + storageOptions
+          + '}';
+    }
+  }
 }
diff --git a/pom.xml b/pom.xml
index 790ba34..d63fd41 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
   <groupId>com.google.cloud</groupId>
   <artifactId>google-cloud-nio-parent</artifactId>
   <packaging>pom</packaging>
-  <version>0.123.13-SNAPSHOT</version><!-- {x-version-update:google-cloud-nio:current} -->
+  <version>0.123.14-SNAPSHOT</version><!-- {x-version-update:google-cloud-nio:current} -->
   <name>Storage Parent</name>
   <url>https://github.com/googleapis/java-storage-nio</url>
   <description>
@@ -78,12 +78,12 @@
       <dependency>
         <groupId>com.google.cloud</groupId>
         <artifactId>google-cloud-storage</artifactId>
-        <version>2.1.5</version>
+        <version>2.1.6</version>
       </dependency>
       <dependency>
         <groupId>com.google.apis</groupId>
         <artifactId>google-api-services-storage</artifactId>
-        <version>v1-rev20210914-1.32.1</version>
+        <version>v1-rev20210918-1.32.1</version>
       </dependency>
       <dependency>
         <groupId>com.google.auto.value</groupId>
diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml
index 9065e15..e54e150 100644
--- a/samples/install-without-bom/pom.xml
+++ b/samples/install-without-bom/pom.xml
@@ -29,7 +29,7 @@
     <dependency>
       <groupId>com.google.cloud</groupId>
       <artifactId>google-cloud-nio</artifactId>
-      <version>0.123.12</version>
+      <version>0.123.13</version>
     </dependency>
     <!-- [END storage_nio_install_without_bom] -->
 
diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml
index 90d70ff..495e8ba 100644
--- a/samples/snapshot/pom.xml
+++ b/samples/snapshot/pom.xml
@@ -28,7 +28,7 @@
     <dependency>
       <groupId>com.google.cloud</groupId>
       <artifactId>google-cloud-nio</artifactId>
-      <version>0.123.13-SNAPSHOT</version>
+      <version>0.123.14-SNAPSHOT</version>
     </dependency>
     <!-- {x-version-update-end} -->
 
diff --git a/versions.txt b/versions.txt
index 0c2fad2..13f7d0a 100644
--- a/versions.txt
+++ b/versions.txt
@@ -1,4 +1,4 @@
 # Format:
 # module:released-version:current-version
 
-google-cloud-nio:0.123.12:0.123.13-SNAPSHOT
\ No newline at end of file
+google-cloud-nio:0.123.13:0.123.14-SNAPSHOT
\ No newline at end of file


Test patch:
diff --git a/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemTest.java b/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemTest.java
index 35b2e50..2819849 100644
--- a/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemTest.java
+++ b/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemTest.java
@@ -23,12 +23,16 @@ import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertSame;
 
+import com.google.api.gax.rpc.internal.QuotaProjectIdHidingCredentials;
+import com.google.auth.Credentials;
+import com.google.cloud.NoCredentials;
 import com.google.cloud.storage.StorageOptions;
 import com.google.cloud.storage.contrib.nio.testing.LocalStorageHelper;
 import com.google.cloud.testing.junit4.MultipleAttemptsRule;
 import com.google.common.testing.EqualsTester;
 import com.google.common.testing.NullPointerTester;
 import java.io.IOException;
+import java.lang.reflect.Field;
 import java.net.URI;
 import java.nio.channels.SeekableByteChannel;
 import java.nio.file.FileSystem;
@@ -374,6 +378,46 @@ public class CloudStorageFileSystemTest {
       assertEquals("new-bucket", destFileSystem.bucket());
     }
   }
+
+  // port of test from
+  // https://github.com/broadinstitute/cromwell/pull/6491/files#diff-758dbbe823e71cc26fee7bc89cd5c434dfb76e604d51005b8327db59aab96068R300-R336
+  @Test
+  public void ensureMultipleInstancesDoNotCorruptCredentials() throws Exception {
+
+    CloudStorageConfiguration config =
+        CloudStorageConfiguration.builder()
+            .permitEmptyPathComponents(true)
+            .stripPrefixSlash(true)
+            .usePseudoDirectories(true)
+            .build();
+
+    Credentials noCredentials = NoCredentials.getInstance();
+    Credentials saCredentials = new QuotaProjectIdHidingCredentials(noCredentials);
+
+    StorageOptions noOptions =
+        StorageOptions.newBuilder()
+            .setProjectId("public-project")
+            .setCredentials(noCredentials)
+            .build();
+
+    StorageOptions saOptions =
+        StorageOptions.newBuilder()
+            .setProjectId("private-project")
+            .setCredentials(saCredentials)
+            .build();
+
+    CloudStorageFileSystem noFs =
+        CloudStorageFileSystem.forBucket("public-bucket", config, noOptions);
+    CloudStorageFileSystem saFs =
+        CloudStorageFileSystem.forBucket("private-bucket", config, saOptions);
+
+    CloudStoragePath noPath = noFs.getPath("public-file");
+    CloudStoragePath saPath = saFs.getPath("private-file");
+
+    assertThat(credentialsForPath(noPath)).isEqualTo(noCredentials);
+    assertThat(credentialsForPath(saPath)).isEqualTo(saCredentials);
+  }
+
   /**
    * Delete the given directory and all of its contents if non-empty.
    *
@@ -402,4 +446,19 @@ public class CloudStorageFileSystemTest {
   private void assertMatches(FileSystem fs, PathMatcher matcher, String toMatch, boolean expected) {
     assertThat(matcher.matches(fs.getPath(toMatch).getFileName())).isEqualTo(expected);
   }
+
+  private static Credentials credentialsForPath(Path p)
+      throws NoSuchFieldException, IllegalAccessException {
+    CloudStorageFileSystemProvider cloudFilesystemProvider =
+        (CloudStorageFileSystemProvider) p.getFileSystem().provider();
+    Field storageOptionsField =
+        cloudFilesystemProvider.getClass().getDeclaredField("storageOptions");
+    storageOptionsField.setAccessible(true);
+    StorageOptions storageOptions =
+        (StorageOptions) storageOptionsField.get(cloudFilesystemProvider);
+    Field credentialsField =
+        storageOptions.getClass().getSuperclass().getDeclaredField("credentials");
+    credentialsField.setAccessible(true);
+    return (Credentials) credentialsField.get(storageOptions);
+  }
 }
diff --git a/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/CloudStorageIsDirectoryTest.java b/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/CloudStorageIsDirectoryTest.java
index ebd201d..16647fb 100644
--- a/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/CloudStorageIsDirectoryTest.java
+++ b/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/CloudStorageIsDirectoryTest.java
@@ -32,6 +32,7 @@ import java.nio.file.Files;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
@@ -40,12 +41,17 @@ import org.junit.runners.JUnit4;
 public class CloudStorageIsDirectoryTest {
   @Rule public final MultipleAttemptsRule multipleAttemptsRule = new MultipleAttemptsRule(3);
 
+  @Rule public final TestName testName = new TestName();
+
   private StorageOptions mockOptions;
   private Storage mockStorage;
 
   @Before
   public void before() {
-    mockOptions = mock(StorageOptions.class);
+    mockOptions =
+        mock(
+            StorageOptions.class,
+            String.format("storage-options-mock_%s", testName.getMethodName()));
     mockStorage = mock(Storage.class);
     when(mockOptions.getService()).thenReturn(mockStorage);
     CloudStorageFileSystemProvider.setStorageOptions(mockOptions);
@@ -54,7 +60,7 @@ public class CloudStorageIsDirectoryTest {
   @Test
   public void testIsDirectoryNoUserProject() {
     CloudStorageFileSystem fs =
-        CloudStorageFileSystem.forBucket("bucket", CloudStorageConfiguration.DEFAULT);
+        CloudStorageFileSystem.forBucket("bucket", CloudStorageConfiguration.DEFAULT, mockOptions);
     when(mockStorage.get(BlobId.of("bucket", "test", null)))
         .thenThrow(new IllegalArgumentException());
     Page<Blob> pages = mock(Page.class);
@@ -74,7 +80,9 @@ public class CloudStorageIsDirectoryTest {
   public void testIsDirectoryWithUserProject() {
     CloudStorageFileSystem fs =
         CloudStorageFileSystem.forBucket(
-            "bucket", CloudStorageConfiguration.builder().userProject("project-id").build());
+            "bucket",
+            CloudStorageConfiguration.builder().userProject("project-id").build(),
+            mockOptions);
     when(mockStorage.get(BlobId.of("bucket", "test", null)))
         .thenThrow(new IllegalArgumentException());
     Page<Blob> pages = mock(Page.class);