Repository: googleapis/java-storage
Pull request #1503 (2022-07-12 15:05:41)

test(deps): update dependency com.google.cloud:google-cloud-conformance-tests to v0.3.2
[![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [com.google.cloud:google-cloud-conformance-tests](https://togithub.com/googleapis/java-shared-config) | `0.3.1` -> `0.3.2` | [![age](https://badges.renovateapi.com/packages/maven/com.google.cloud:google-cloud-conformance-tests/0.3.2/age-slim)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://badges.renovateapi.com/packages/maven/com.google.cloud:google-cloud-conformance-tests/0.3.2/adoption-slim)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://badges.renovateapi.com/packages/maven/com.google.cloud:google-cloud-conformance-tests/0.3.2/compatibility-slim/0.3.1)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://badges.renovateapi.com/packages/maven/com.google.cloud:google-cloud-conformance-tests/0.3.2/confidence-slim/0.3.1)](https://docs.renovatebot.com/merge-confidence/) |

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, click this checkbox.

---

This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://app.renovatebot.com/dashboard#github/googleapis/java-storage).


Patch:
diff --git a/.github/sync-repo-settings.yaml b/.github/sync-repo-settings.yaml
index 5de852ee..897dbf7c 100644
--- a/.github/sync-repo-settings.yaml
+++ b/.github/sync-repo-settings.yaml
@@ -17,6 +17,8 @@ branchProtectionRules:
       - 'Kokoro - Test: Integration'
       - cla/google
       - OwlBot Post Processor
+      - 'Kokoro - Test: Java GraalVM Native Image'
+      - 'Kokoro - Test: Java 17 GraalVM Native Image'
   - pattern: 1.113.14-sp
     isAdminEnforced: true
     requiredApprovingReviewCount: 1
diff --git a/README.md b/README.md
index 61c0ef3a..e9704ac4 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ If you are using Maven with [BOM][libraries-bom], add this to your pom.xml file:
     <dependency>
       <groupId>com.google.cloud</groupId>
       <artifactId>libraries-bom</artifactId>
-      <version>25.4.0</version>
+      <version>26.0.0</version>
       <type>pom</type>
       <scope>import</scope>
     </dependency>
diff --git a/google-cloud-storage/clirr-ignored-differences.xml b/google-cloud-storage/clirr-ignored-differences.xml
index 8aabcf10..f160493a 100644
--- a/google-cloud-storage/clirr-ignored-differences.xml
+++ b/google-cloud-storage/clirr-ignored-differences.xml
@@ -2,13 +2,8 @@
 <!-- see https://www.mojohaus.org/clirr-maven-plugin/examples/ignored-differences.html -->
 <differences>
   <difference>
-    <className>com/google/cloud/storage/Storage*</className>
-    <differenceType>7012</differenceType>
-    <method>* downloadTo(com.google.cloud.storage.BlobId, java.io.OutputStream, com.google.cloud.storage.Storage$BlobSourceOption[])</method>
-  </difference>
-  <difference>
-    <className>com/google/cloud/storage/Storage*</className>
-    <differenceType>7012</differenceType>
-    <method>* downloadTo(com.google.cloud.storage.BlobId, java.nio.file.Path, com.google.cloud.storage.Storage$BlobSourceOption[])</method>
+    <className>com/google/cloud/storage/BucketInfo*</className>
+    <differenceType>7013</differenceType>
+    <method>* setCustomPlacementConfig(com.google.cloud.storage.BucketInfo$CustomPlacementConfig)</method>
   </difference>
 </differences>
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/Bucket.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/Bucket.java
index 95acd19d..20a6d8ad 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/Bucket.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/Bucket.java
@@ -691,6 +691,12 @@ public class Bucket extends BucketInfo {
       return this;
     }
 
+    @Override
+    public Builder setCustomPlacementConfig(CustomPlacementConfig customPlacementConfig) {
+      infoBuilder.setCustomPlacementConfig(customPlacementConfig);
+      return this;
+    }
+
     @Override
     public Bucket build() {
       return new Bucket(storage, infoBuilder);
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java
index 02990680..70a9817c 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java
@@ -103,6 +103,7 @@ public class BucketInfo implements Serializable {
   private final IamConfiguration iamConfiguration;
   private final String locationType;
   private final Logging logging;
+  private final CustomPlacementConfig customPlacementConfig;
 
   private static final Logger log = Logger.getLogger(BucketInfo.class.getName());
 
@@ -328,6 +329,76 @@ public class BucketInfo implements Serializable {
     }
   }
 
+  /**
+   * The bucket's custom placement configuration for Custom Dual Regions. If using `location` is
+   * also required.
+   */
+  public static class CustomPlacementConfig implements Serializable {
+
+    private static final long serialVersionUID = -3172255903331692127L;
+    private List<String> dataLocations;
+
+    @Override
+    public boolean equals(Object o) {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) {
+        return false;
+      }
+      CustomPlacementConfig other = (CustomPlacementConfig) o;
+      return Objects.equals(toPb(), other.toPb());
+    }
+
+    @Override
+    public int hashCode() {
+      return Objects.hashCode(dataLocations);
+    }
+
+    public static Builder newBuilder() {
+      return new Builder();
+    }
+
+    public Builder toBuilder() {
+      Builder builder = new Builder();
+      builder.dataLocations = dataLocations;
+      return builder;
+    }
+
+    public List<String> getDataLocations() {
+      return dataLocations;
+    }
+
+    Bucket.CustomPlacementConfig toPb() {
+      Bucket.CustomPlacementConfig customPlacementConfig = null;
+      if (dataLocations != null) {
+        customPlacementConfig = new Bucket.CustomPlacementConfig();
+        customPlacementConfig.setDataLocations(dataLocations);
+      }
+      return customPlacementConfig;
+    }
+
+    static CustomPlacementConfig fromPb(Bucket.CustomPlacementConfig customPlacementConfig) {
+      return newBuilder().setDataLocations(customPlacementConfig.getDataLocations()).build();
+    }
+
+    private CustomPlacementConfig(Builder builder) {
+      this.dataLocations = builder.dataLocations;
+    }
+
+    public static class Builder {
+      private List<String> dataLocations;
+
+      /** A list of regions for custom placement configurations. */
+      public Builder setDataLocations(List<String> dataLocations) {
+        this.dataLocations = dataLocations != null ? ImmutableList.copyOf(dataLocations) : null;
+        return this;
+      }
+
+      public CustomPlacementConfig build() {
+        return new CustomPlacementConfig(this);
+      }
+    }
+  }
+
   /**
    * The bucket's logging configuration, which defines the destination bucket and optional name
    * prefix for the current bucket's logs.
@@ -1361,6 +1432,8 @@ public class BucketInfo implements Serializable {
 
     public abstract Builder setLogging(Logging logging);
 
+    public abstract Builder setCustomPlacementConfig(CustomPlacementConfig customPlacementConfig);
+
     /** Creates a {@code BucketInfo} object. */
     public abstract BucketInfo build();
   }
@@ -1396,6 +1469,7 @@ public class BucketInfo implements Serializable {
     private IamConfiguration iamConfiguration;
     private String locationType;
     private Logging logging;
+    private CustomPlacementConfig customPlacementConfig;
 
     BuilderImpl(String name) {
       this.name = name;
@@ -1431,6 +1505,7 @@ public class BucketInfo implements Serializable {
       iamConfiguration = bucketInfo.iamConfiguration;
       locationType = bucketInfo.locationType;
       logging = bucketInfo.logging;
+      customPlacementConfig = bucketInfo.customPlacementConfig;
     }
 
     @Override
@@ -1626,6 +1701,12 @@ public class BucketInfo implements Serializable {
       return this;
     }
 
+    @Override
+    public Builder setCustomPlacementConfig(CustomPlacementConfig customPlacementConfig) {
+      this.customPlacementConfig = customPlacementConfig != null ? customPlacementConfig : null;
+      return this;
+    }
+
     @Override
     Builder setLocationType(String locationType) {
       this.locationType = locationType;
@@ -1669,6 +1750,7 @@ public class BucketInfo implements Serializable {
     iamConfiguration = builder.iamConfiguration;
     locationType = builder.locationType;
     logging = builder.logging;
+    customPlacementConfig = builder.customPlacementConfig;
   }
 
   /** Returns the service-generated id for the bucket. */
@@ -1792,7 +1874,8 @@ public class BucketInfo implements Serializable {
 
   /**
    * Returns the bucket's location. Data for blobs in the bucket resides in physical storage within
-   * this region or regions.
+   * this region or regions. If specifying more than one region `customPlacementConfig` should be
+   * set in conjunction.
    *
    * @see <a href="https://cloud.google.com/storage/docs/bucket-locations">Bucket Locations</a>
    */
@@ -1945,6 +2028,11 @@ public class BucketInfo implements Serializable {
     return logging;
   }
 
+  /** Returns the Custom Placement Configuration */
+  public CustomPlacementConfig getCustomPlacementConfig() {
+    return customPlacementConfig;
+  }
+
   /** Returns a builder for the current bucket. */
   public Builder toBuilder() {
     return new BuilderImpl(this);
@@ -2118,6 +2206,9 @@ public class BucketInfo implements Serializable {
     if (logging != null) {
       bucketPb.setLogging(logging.toPb());
     }
+    if (customPlacementConfig != null) {
+      bucketPb.setCustomPlacementConfig(customPlacementConfig.toPb());
+    }
     return bucketPb;
   }
 
@@ -2258,6 +2349,10 @@ public class BucketInfo implements Serializable {
     if (logging != null) {
       builder.setLogging(Logging.fromPb(logging));
     }
+    Bucket.CustomPlacementConfig customPlacementConfig = bucketPb.getCustomPlacementConfig();
+    if (customPlacementConfig != null) {
+      builder.setCustomPlacementConfig(CustomPlacementConfig.fromPb(customPlacementConfig));
+    }
     return builder.build();
   }
 }
diff --git a/pom.xml b/pom.xml
index 537d59f1..24c9351c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -126,7 +126,7 @@
       <dependency>
         <groupId>com.google.cloud</groupId>
         <artifactId>google-cloud-conformance-tests</artifactId>
-        <version>0.3.1</version>
+        <version>0.3.2</version>
         <scope>test</scope>
         <exclusions>
           <exclusion>
diff --git a/samples/native-image-sample/pom.xml b/samples/native-image-sample/pom.xml
index 86aba64b..d1618db9 100644
--- a/samples/native-image-sample/pom.xml
+++ b/samples/native-image-sample/pom.xml
@@ -29,7 +29,7 @@
       <dependency>
         <groupId>com.google.cloud</groupId>
         <artifactId>libraries-bom</artifactId>
-        <version>25.4.0</version>
+        <version>26.0.0</version>
         <type>pom</type>
         <scope>import</scope>
       </dependency>
@@ -117,21 +117,14 @@
           <version>5.8.2</version>
           <scope>test</scope>
         </dependency>
-        <dependency>
-          <groupId>org.graalvm.buildtools</groupId>
-          <artifactId>junit-platform-native</artifactId>
-          <version>0.9.12</version>
-          <scope>test</scope>
-        </dependency>
       </dependencies>
 
       <build>
         <plugins>
           <plugin>
             <groupId>org.apache.maven.plugins</groupId>
-            <artifactId>maven-surefire-plugin
-            </artifactId> <!-- Must use older version of surefire plugin for native-image testing. -->
-            <version>2.22.2</version>
+            <artifactId>maven-surefire-plugin</artifactId>
+            <version>3.0.0-M7</version>
             <configuration>
               <includes>
                 <include>**/*IT</include>
@@ -141,7 +134,7 @@
           <plugin>
             <groupId>org.graalvm.buildtools</groupId>
             <artifactId>native-maven-plugin</artifactId>
-            <version>0.9.12</version>
+            <version>0.9.13</version>
             <extensions>true</extensions>
             <configuration>
               <mainClass>com.example.storage.NativeImageStorageSample</mainClass>
diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml
index bd5eaac1..e1007b3c 100644
--- a/samples/snippets/pom.xml
+++ b/samples/snippets/pom.xml
@@ -31,7 +31,7 @@
       <dependency>
         <groupId>com.google.cloud</groupId>
         <artifactId>libraries-bom</artifactId>
-        <version>25.4.0</version>
+        <version>26.0.0</version>
         <type>pom</type>
         <scope>import</scope>
       </dependency>


Test patch:
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java
index 462b4bbd..fd0cc6e5 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java
@@ -65,6 +65,7 @@ import com.google.cloud.storage.BlobId;
 import com.google.cloud.storage.BlobInfo;
 import com.google.cloud.storage.Bucket;
 import com.google.cloud.storage.BucketInfo;
+import com.google.cloud.storage.BucketInfo.CustomPlacementConfig;
 import com.google.cloud.storage.BucketInfo.LifecycleRule;
 import com.google.cloud.storage.BucketInfo.LifecycleRule.AbortIncompleteMPUAction;
 import com.google.cloud.storage.BucketInfo.LifecycleRule.LifecycleAction;
@@ -3552,13 +3553,22 @@ public class ITStorageTest {
   }
 
   @Test
-  public void testBucketLocationDualRegion() {
+  public void testBucketCustomPlacmentConfigDualRegion() {
     String bucketName = RemoteStorageHelper.generateBucketName();
-    String dualRegionLocation = "US-EAST1+US-WEST1";
+    List<String> locations = new ArrayList<>();
+    locations.add("US-EAST1");
+    locations.add("US-WEST1");
+    CustomPlacementConfig customPlacementConfig =
+        CustomPlacementConfig.newBuilder().setDataLocations(locations).build();
     Bucket bucket =
-        storage.create(BucketInfo.newBuilder(bucketName).setLocation(dualRegionLocation).build());
-    assertEquals(bucket.getLocation(), dualRegionLocation);
-    assertEquals(bucket.getLocationType(), "dual-region");
+        storage.create(
+            BucketInfo.newBuilder(bucketName)
+                .setCustomPlacementConfig(customPlacementConfig)
+                .setLocation("us")
+                .build());
+    assertTrue(bucket.getCustomPlacementConfig().getDataLocations().contains("US-EAST1"));
+    assertTrue(bucket.getCustomPlacementConfig().getDataLocations().contains("US-WEST1"));
+    assertTrue(bucket.getLocation().equalsIgnoreCase("us"));
   }
 
   @Test