This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new eb036c7c23c5 CAMEL-26622: camel-google-storage - run the integration 
tests on Floci GCP (#29818)
eb036c7c23c5 is described below

commit eb036c7c23c51627bcae9e557d4ba08ef3f373cc
Author: Andrea Cosentino <[email protected]>
AuthorDate: Fri Nov 13 15:54:43 2026 +0100

    CAMEL-26622: camel-google-storage - run the integration tests on Floci GCP 
(#29818)
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../apache/camel/catalog/test-infra/metadata.json  |  11 +++
 .../camel-google/camel-google-storage/pom.xml      |  12 +++
 .../google/storage/integration/ComplexIT.java      |  97 +++++++++++++------
 test-infra/camel-test-infra-all/pom.xml            |  11 +++
 .../src/generated/resources/META-INF/metadata.json |  11 +++
 test-infra/camel-test-infra-google-common/pom.xml  |  40 ++++++++
 .../test/infra/google/common/GoogleProperties.java |  29 ++++++
 .../google/common/services/FlociGcpContainer.java  |  50 ++++++++++
 .../src/main/resources/META-INF/MANIFEST.MF        |   0
 .../google/common/services/container.properties    |  19 ++++
 test-infra/camel-test-infra-google-storage/pom.xml |  40 ++++++++
 .../storage/common/GoogleStorageProperties.java    |  27 ++++++
 .../services/GoogleStorageInfraService.java        |  37 ++++++++
 .../GoogleStorageLocalContainerInfraService.java   | 103 +++++++++++++++++++++
 .../services/GoogleStorageRemoteInfraService.java  |  57 ++++++++++++
 .../storage/services/GoogleStorageService.java     |  27 ++++++
 .../services/GoogleStorageServiceFactory.java      |  83 +++++++++++++++++
 .../src/main/resources/META-INF/MANIFEST.MF        |   0
 test-infra/pom.xml                                 |   2 +
 19 files changed, 626 insertions(+), 30 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/test-infra/metadata.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/test-infra/metadata.json
index 51503f728729..f53dfdae7abb 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/test-infra/metadata.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/test-infra/metadata.json
@@ -174,6 +174,17 @@
   "version" : "4.24.0-SNAPSHOT",
   "serviceVersion" : "1.24.0",
   "uiSupported" : false
+}, {
+  "service" : 
"org.apache.camel.test.infra.google.storage.services.GoogleStorageInfraService",
+  "description" : "Local Google Cloud Storage service with Floci GCP",
+  "implementation" : 
"org.apache.camel.test.infra.google.storage.services.GoogleStorageLocalContainerInfraService",
+  "alias" : [ "google" ],
+  "aliasImplementation" : [ "storage" ],
+  "groupId" : "org.apache.camel",
+  "artifactId" : "camel-test-infra-google-storage",
+  "version" : "4.24.0-SNAPSHOT",
+  "serviceVersion" : "0.12.0",
+  "uiSupported" : false
 }, {
   "service" : 
"org.apache.camel.test.infra.rabbitmq.services.RabbitMQInfraService",
   "description" : "RabbitMQ is an open source message and streaming broker",
diff --git a/components/camel-google/camel-google-storage/pom.xml 
b/components/camel-google/camel-google-storage/pom.xml
index 5d6a835e0764..3042da2df562 100644
--- a/components/camel-google/camel-google-storage/pom.xml
+++ b/components/camel-google/camel-google-storage/pom.xml
@@ -34,6 +34,10 @@
 
     <properties>
         <camel.surefire.forkTimeout>300</camel.surefire.forkTimeout>
+
+        <!-- Floci GCP is not available for these -->
+        <skipITs.ppc64le>true</skipITs.ppc64le>
+        <skipITs.s390x>true</skipITs.s390x>
     </properties>
 
     <dependencies>
@@ -74,6 +78,14 @@
             <scope>test</scope>
             <classifier>tests</classifier>
         </dependency>
+
+        <!-- test infra -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test-infra-google-storage</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>org.assertj</groupId>
             <artifactId>assertj-core</artifactId>
diff --git 
a/components/camel-google/camel-google-storage/src/test/java/org/apache/camel/component/google/storage/integration/ComplexIT.java
 
b/components/camel-google/camel-google-storage/src/test/java/org/apache/camel/component/google/storage/integration/ComplexIT.java
index 7c4d2df67ff8..d5a34f9e6bb5 100644
--- 
a/components/camel-google/camel-google-storage/src/test/java/org/apache/camel/component/google/storage/integration/ComplexIT.java
+++ 
b/components/camel-google/camel-google-storage/src/test/java/org/apache/camel/component/google/storage/integration/ComplexIT.java
@@ -17,24 +17,37 @@
 package org.apache.camel.component.google.storage.integration;
 
 import java.io.ByteArrayInputStream;
+import java.net.URI;
+import java.security.KeyPairGenerator;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
+import com.google.auth.oauth2.ServiceAccountCredentials;
 import com.google.cloud.storage.Blob;
+import com.google.cloud.storage.Storage;
+import com.google.cloud.storage.StorageOptions;
 import org.apache.camel.EndpointInject;
-import org.apache.camel.ProducerTemplate;
+import org.apache.camel.Exchange;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.google.storage.GoogleCloudStorageConstants;
 import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spi.Registry;
+import 
org.apache.camel.test.infra.google.storage.services.GoogleStorageLocalContainerInfraService;
+import 
org.apache.camel.test.infra.google.storage.services.GoogleStorageService;
+import 
org.apache.camel.test.infra.google.storage.services.GoogleStorageServiceFactory;
 import org.apache.camel.test.junit6.CamelTestSupport;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
-@EnabledIfEnvironmentVariable(named = "GOOGLE_APPLICATION_CREDENTIALS", 
matches = ".*",
-                              disabledReason = "Application credentials were 
not provided")
-public class ComplexIT extends CamelTestSupport {
+/**
+ * Runs against the Cloud Storage service of Floci GCP, or with {@code 
-Dgoogle.instance.type=remote} against the one of
+ * the project of the application default credentials, such as the key of the 
{@code GOOGLE_APPLICATION_CREDENTIALS}
+ * environment variable.
+ */
+class ComplexIT extends CamelTestSupport {
 
-    @EndpointInject
-    private ProducerTemplate template;
+    @RegisterExtension
+    static GoogleStorageService service = 
GoogleStorageServiceFactory.createService();
 
     @EndpointInject("mock:bucket1")
     private MockEndpoint mockBucket1;
@@ -45,14 +58,40 @@ public class ComplexIT extends CamelTestSupport {
     @EndpointInject("mock:processed")
     private MockEndpoint mockProcessed;
 
+    @Override
+    protected void bindToRegistry(Registry registry) throws Exception {
+        if (service instanceof GoogleStorageLocalContainerInfraService) {
+            // the endpoints take the client of the registry; against Google 
Cloud, they build their own
+            registry.bind("storageClient", createLocalStorageClient());
+        }
+    }
+
+    // Floci GCP gives an access token to a service account of any key, at the 
token address of the key: unlike no
+    // credentials, the ones of a key made for the test can sign the download 
links
+    private static Storage createLocalStorageClient() throws Exception {
+        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
+        generator.initialize(2048);
+        ServiceAccountCredentials credentials = 
ServiceAccountCredentials.newBuilder()
+                .setClientEmail("camel@" + service.projectId() + 
".iam.gserviceaccount.com")
+                .setPrivateKeyId("camel")
+                .setPrivateKey(generator.generateKeyPair().getPrivate())
+                .setProjectId(service.projectId())
+                .setTokenServerUri(URI.create(service.endpoint() + "/token"))
+                .build();
+        return StorageOptions.newBuilder()
+                .setHost(service.endpoint())
+                .setProjectId(service.projectId())
+                .setCredentials(credentials)
+                .build()
+                .getService();
+    }
+
     @Override
     protected RouteBuilder createRouteBuilder() {
         return new RouteBuilder() {
             @Override
             public void configure() {
                 final int numberOfObjects = 3;
-                //final String serviceAccountKeyFile = "somefile.json";
-                final String serviceAccountKeyFile = 
System.getenv("GOOGLE_APPLICATION_CREDENTIALS");
                 final String bucket1 = "camel_test_bucket1";
                 final String bucket2 = "camel_test_bucket2";
                 final String bucket3 = "camel_test_processed_bucket";
@@ -60,20 +99,19 @@ public class ComplexIT extends CamelTestSupport {
 
                 //upload 3 file into bucket1
                 byte[] payload = "Camel rocks!".getBytes();
-                ByteArrayInputStream bais = new ByteArrayInputStream(payload);
-                from("timer:timer1?repeatCount=" + numberOfObjects)
+                from("timer:timer1?includeMetadata=true&repeatCount=" + 
numberOfObjects)
                         .process(exchange -> {
-                            String filename = "file_" + ((int) (Math.random() 
* 10000)) + ".txt";
+                            String filename = "file_" + 
exchange.getProperty(Exchange.TIMER_COUNTER) + ".txt";
                             
exchange.getIn().setHeader(GoogleCloudStorageConstants.OBJECT_NAME, filename);
-                            exchange.getIn().setBody(bais);
+                            exchange.getIn().setBody(new 
ByteArrayInputStream(payload));
                         })
-                        .to("google-storage://" + bucket1 + 
"?serviceAccountKey=file:" + serviceAccountKeyFile)
+                        .to("google-storage://" + bucket1)
                         .log("upload file 
object:${header.CamelGoogleCloudStorageObjectName}, body:${body}")
                         .to("mock:bucket1");
 
                 //poll from bucket1, moving processed into bucket_processed 
and deleting original
-                from("google-storage://" + bucket1 + 
"?serviceAccountKey=file:" + serviceAccountKeyFile
-                     + "&moveAfterRead=true"
+                from("google-storage://" + bucket1
+                     + "?moveAfterRead=true"
                      + "&destinationBucket=" + bucket3
                      + "&autoCreateBucket=true"
                      + "&deleteAfterRead=true"
@@ -84,26 +122,26 @@ public class ComplexIT extends CamelTestSupport {
 
                 //upload these files to bucket2
                 from("direct:processed")
-                        .to("google-storage://" + bucket2 + 
"?serviceAccountKey=file:" + serviceAccountKeyFile)
+                        .to("google-storage://" + bucket2)
                         .log("uploaded file 
object:${header.CamelGoogleCloudStorageObjectName}, body:${body}")
                         .process(exchange -> {
                             
exchange.getIn().setHeader(GoogleCloudStorageConstants.DOWNLOAD_LINK_EXPIRATION_TIME,
 86400000L); //1 day
                         })
-                        .to("google-storage://" + bucket2 + 
"?serviceAccountKey=file:" + serviceAccountKeyFile
-                            + "&operation=createDownloadLink")
+                        .to("google-storage://" + bucket2
+                            + "?operation=createDownloadLink")
                         .log("URL for 
${header.CamelGoogleCloudStorageBucketName}/${header.CamelGoogleCloudStorageObjectName}
 =${body}")
                         .to("mock:bucket2");
 
                 //list all buckets
                 from("timer:timer1?repeatCount=1&fixedRate=true&period=10000")
-                        .to("google-storage://" + bucket2 + 
"?serviceAccountKey=file:" + serviceAccountKeyFile
-                            + "&operation=listBuckets")
+                        .to("google-storage://" + bucket2
+                            + "?operation=listBuckets")
                         .log("list buckets:${body}");
 
                 //list all object of the bucket2 and send result to 
direct:moreinfo and direct:copy
                 from("timer:timer1?repeatCount=1&fixedRate=true&period=10000")
-                        .to("google-storage://" + bucket2 + 
"?serviceAccountKey=file:" + serviceAccountKeyFile
-                            + "&operation=listObjects")
+                        .to("google-storage://" + bucket2
+                            + "?operation=listObjects")
                         .log("list " + bucket2 + " objects body:${body}")
                         .split(bodyAs(List.class))
                         .log("splitted: ${body}")
@@ -115,8 +153,8 @@ public class ComplexIT extends CamelTestSupport {
                             String fileName = blob.getName();
                             
exchange.getIn().setHeader(GoogleCloudStorageConstants.OBJECT_NAME, fileName);
                         })
-                        .to("google-storage://" + bucket2 + 
"?serviceAccountKey=file:" + serviceAccountKeyFile
-                            + "&operation=getObject")
+                        .to("google-storage://" + bucket2
+                            + "?operation=getObject")
                         .log("get object 
bucket:${header.CamelGoogleCloudStorageBucketName} 
object:${header.CamelGoogleCloudStorageObjectName}, body:${body}");
 
                 //copy object
@@ -129,8 +167,8 @@ public class ComplexIT extends CamelTestSupport {
                             
exchange.getIn().setHeader(GoogleCloudStorageConstants.DESTINATION_BUCKET_NAME, 
bucket4);
                             
exchange.getIn().setHeader(GoogleCloudStorageConstants.DESTINATION_OBJECT_NAME, 
copyFileName);
                         })
-                        .to("google-storage://" + bucket2 + 
"?serviceAccountKey=file:" + serviceAccountKeyFile
-                            + "&operation=copyObject")
+                        .to("google-storage://" + bucket2
+                            + "?operation=copyObject")
                         .log("${body}");
 
             }
@@ -138,13 +176,12 @@ public class ComplexIT extends CamelTestSupport {
     }
 
     @Test
-    public void sendIn() throws Exception {
+    void sendIn() throws Exception {
         mockBucket1.expectedMessageCount(3);
         mockBucket2.expectedMessageCount(3);
         mockProcessed.expectedMessageCount(3);
 
-        Thread.sleep(10000);
-        MockEndpoint.assertIsSatisfied(context);
+        MockEndpoint.assertIsSatisfied(context, 30, TimeUnit.SECONDS);
     }
 
 }
diff --git a/test-infra/camel-test-infra-all/pom.xml 
b/test-infra/camel-test-infra-all/pom.xml
index bea09ffe17a5..dfac989b11c5 100644
--- a/test-infra/camel-test-infra-all/pom.xml
+++ b/test-infra/camel-test-infra-all/pom.xml
@@ -141,6 +141,11 @@
             <artifactId>camel-test-infra-google-pubsub</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test-infra-google-storage</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-test-infra-infinispan</artifactId>
@@ -514,6 +519,12 @@
                                         
<artifactId>camel-test-infra-google-pubsub</artifactId>
                                     </dependency>
                                 </fileSet>
+                                <fileSet>
+                                    <dependency>
+                                        <groupId>org.apache.camel</groupId>
+                                        
<artifactId>camel-test-infra-google-storage</artifactId>
+                                    </dependency>
+                                </fileSet>
                                 <fileSet>
                                     <dependency>
                                         <groupId>org.apache.camel</groupId>
diff --git 
a/test-infra/camel-test-infra-all/src/generated/resources/META-INF/metadata.json
 
b/test-infra/camel-test-infra-all/src/generated/resources/META-INF/metadata.json
index 51503f728729..f53dfdae7abb 100644
--- 
a/test-infra/camel-test-infra-all/src/generated/resources/META-INF/metadata.json
+++ 
b/test-infra/camel-test-infra-all/src/generated/resources/META-INF/metadata.json
@@ -174,6 +174,17 @@
   "version" : "4.24.0-SNAPSHOT",
   "serviceVersion" : "1.24.0",
   "uiSupported" : false
+}, {
+  "service" : 
"org.apache.camel.test.infra.google.storage.services.GoogleStorageInfraService",
+  "description" : "Local Google Cloud Storage service with Floci GCP",
+  "implementation" : 
"org.apache.camel.test.infra.google.storage.services.GoogleStorageLocalContainerInfraService",
+  "alias" : [ "google" ],
+  "aliasImplementation" : [ "storage" ],
+  "groupId" : "org.apache.camel",
+  "artifactId" : "camel-test-infra-google-storage",
+  "version" : "4.24.0-SNAPSHOT",
+  "serviceVersion" : "0.12.0",
+  "uiSupported" : false
 }, {
   "service" : 
"org.apache.camel.test.infra.rabbitmq.services.RabbitMQInfraService",
   "description" : "RabbitMQ is an open source message and streaming broker",
diff --git a/test-infra/camel-test-infra-google-common/pom.xml 
b/test-infra/camel-test-infra-google-common/pom.xml
new file mode 100644
index 000000000000..8ca74ade6088
--- /dev/null
+++ b/test-infra/camel-test-infra-google-common/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You 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.
+
+-->
+<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";>
+    <parent>
+        <artifactId>camel-test-infra-parent</artifactId>
+        <groupId>org.apache.camel</groupId>
+        <relativePath>../camel-test-infra-parent/pom.xml</relativePath>
+        <version>4.24.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <name>Camel :: Test Infra :: Google Common</name>
+    <artifactId>camel-test-infra-google-common</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test-infra-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git 
a/test-infra/camel-test-infra-google-common/src/main/java/org/apache/camel/test/infra/google/common/GoogleProperties.java
 
b/test-infra/camel-test-infra-google-common/src/main/java/org/apache/camel/test/infra/google/common/GoogleProperties.java
new file mode 100644
index 000000000000..3a21641a8ec5
--- /dev/null
+++ 
b/test-infra/camel-test-infra-google-common/src/main/java/org/apache/camel/test/infra/google/common/GoogleProperties.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.test.infra.google.common;
+
+public final class GoogleProperties {
+    /**
+     * The image of Floci GCP, which runs the local Google Cloud services
+     */
+    public static final String GOOGLE_CONTAINER = "google.container";
+
+    private GoogleProperties() {
+
+    }
+}
diff --git 
a/test-infra/camel-test-infra-google-common/src/main/java/org/apache/camel/test/infra/google/common/services/FlociGcpContainer.java
 
b/test-infra/camel-test-infra-google-common/src/main/java/org/apache/camel/test/infra/google/common/services/FlociGcpContainer.java
new file mode 100644
index 000000000000..37926550c39b
--- /dev/null
+++ 
b/test-infra/camel-test-infra-google-common/src/main/java/org/apache/camel/test/infra/google/common/services/FlociGcpContainer.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.test.infra.google.common.services;
+
+import java.time.Duration;
+
+import org.apache.camel.test.infra.common.services.ContainerEnvironmentUtil;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.wait.strategy.Wait;
+
+/**
+ * A container running Floci GCP (https://github.com/floci-io/floci-gcp), a 
local Google Cloud emulator. It serves the
+ * gRPC and the REST APIs of the Google Cloud services on one port, and 
accepts any project id.
+ */
+public class FlociGcpContainer extends GenericContainer<FlociGcpContainer> {
+    public static final int SERVICE_PORT = 4588;
+
+    public FlociGcpContainer(String imageName, boolean fixedPort) {
+        super(imageName);
+
+        ContainerEnvironmentUtil.configurePort(this, fixedPort, SERVICE_PORT);
+
+        waitingFor(Wait.forHttp("/health")
+                .forPort(SERVICE_PORT)
+                .forStatusCode(200)
+                .withStartupTimeout(Duration.ofSeconds(120)));
+    }
+
+    /**
+     * The address of the emulator, for example {@code http://localhost:32768}
+     */
+    public String serviceAddress() {
+        return String.format("http://%s:%d";, getHost(), 
getMappedPort(SERVICE_PORT));
+    }
+}
diff --git 
a/test-infra/camel-test-infra-google-common/src/main/resources/META-INF/MANIFEST.MF
 
b/test-infra/camel-test-infra-google-common/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git 
a/test-infra/camel-test-infra-google-common/src/main/resources/org/apache/camel/test/infra/google/common/services/container.properties
 
b/test-infra/camel-test-infra-google-common/src/main/resources/org/apache/camel/test/infra/google/common/services/container.properties
new file mode 100644
index 000000000000..b39172195ef1
--- /dev/null
+++ 
b/test-infra/camel-test-infra-google-common/src/main/resources/org/apache/camel/test/infra/google/common/services/container.properties
@@ -0,0 +1,19 @@
+## ---------------------------------------------------------------------------
+## Licensed to the Apache Software Foundation (ASF) under one or more
+## contributor license agreements.  See the NOTICE file distributed with
+## this work for additional information regarding copyright ownership.
+## The ASF licenses this file to You 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.
+## ---------------------------------------------------------------------------
+# Floci GCP: the local Google Cloud services
+google.container=mirror.gcr.io/floci/floci-gcp:0.12.0
+google.container.version.exclude=latest,nightly,compat
diff --git a/test-infra/camel-test-infra-google-storage/pom.xml 
b/test-infra/camel-test-infra-google-storage/pom.xml
new file mode 100644
index 000000000000..23e7bd15258f
--- /dev/null
+++ b/test-infra/camel-test-infra-google-storage/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You 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.
+
+-->
+<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";>
+    <parent>
+        <artifactId>camel-test-infra-parent</artifactId>
+        <groupId>org.apache.camel</groupId>
+        <relativePath>../camel-test-infra-parent/pom.xml</relativePath>
+        <version>4.24.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <name>Camel :: Test Infra :: Google Cloud Storage</name>
+    <artifactId>camel-test-infra-google-storage</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test-infra-google-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git 
a/test-infra/camel-test-infra-google-storage/src/main/java/org/apache/camel/test/infra/google/storage/common/GoogleStorageProperties.java
 
b/test-infra/camel-test-infra-google-storage/src/main/java/org/apache/camel/test/infra/google/storage/common/GoogleStorageProperties.java
new file mode 100644
index 000000000000..4c515fdad65b
--- /dev/null
+++ 
b/test-infra/camel-test-infra-google-storage/src/main/java/org/apache/camel/test/infra/google/storage/common/GoogleStorageProperties.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.test.infra.google.storage.common;
+
+public final class GoogleStorageProperties {
+    public static final String PROJECT_ID = "google.storage.project.id";
+    public static final String ENDPOINT = "google.storage.endpoint";
+
+    private GoogleStorageProperties() {
+
+    }
+}
diff --git 
a/test-infra/camel-test-infra-google-storage/src/main/java/org/apache/camel/test/infra/google/storage/services/GoogleStorageInfraService.java
 
b/test-infra/camel-test-infra-google-storage/src/main/java/org/apache/camel/test/infra/google/storage/services/GoogleStorageInfraService.java
new file mode 100644
index 000000000000..3691ef94ded6
--- /dev/null
+++ 
b/test-infra/camel-test-infra-google-storage/src/main/java/org/apache/camel/test/infra/google/storage/services/GoogleStorageInfraService.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.test.infra.google.storage.services;
+
+import org.apache.camel.test.infra.common.services.InfrastructureService;
+
+/**
+ * A Cloud Storage service: the one of Floci GCP, or the one of a real Google 
Cloud project.
+ */
+public interface GoogleStorageInfraService extends InfrastructureService {
+
+    /**
+     * The id of the project
+     */
+    String projectId();
+
+    /**
+     * The address of the Cloud Storage API, for example {@code 
http://localhost:32768} for Floci GCP or
+     * {@code https://storage.googleapis.com} for Google Cloud
+     */
+    String endpoint();
+}
diff --git 
a/test-infra/camel-test-infra-google-storage/src/main/java/org/apache/camel/test/infra/google/storage/services/GoogleStorageLocalContainerInfraService.java
 
b/test-infra/camel-test-infra-google-storage/src/main/java/org/apache/camel/test/infra/google/storage/services/GoogleStorageLocalContainerInfraService.java
new file mode 100644
index 000000000000..69a638ffe1bb
--- /dev/null
+++ 
b/test-infra/camel-test-infra-google-storage/src/main/java/org/apache/camel/test/infra/google/storage/services/GoogleStorageLocalContainerInfraService.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.test.infra.google.storage.services;
+
+import org.apache.camel.spi.annotations.InfraService;
+import org.apache.camel.test.infra.common.LocalPropertyResolver;
+import org.apache.camel.test.infra.common.services.ContainerEnvironmentUtil;
+import org.apache.camel.test.infra.common.services.ContainerService;
+import org.apache.camel.test.infra.google.common.GoogleProperties;
+import org.apache.camel.test.infra.google.common.services.FlociGcpContainer;
+import 
org.apache.camel.test.infra.google.storage.common.GoogleStorageProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A local Cloud Storage service on Floci GCP. Floci GCP accepts any 
credentials, and gives an access token to a service
+ * account of any key at {@code <endpoint>/token}.
+ */
+@InfraService(service = GoogleStorageInfraService.class,
+              description = "Local Google Cloud Storage service with Floci 
GCP",
+              serviceAlias = "google", serviceImplementationAlias = "storage")
+public class GoogleStorageLocalContainerInfraService
+        implements GoogleStorageInfraService, 
ContainerService<FlociGcpContainer> {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(GoogleStorageLocalContainerInfraService.class);
+    private static final String DEFAULT_PROJECT_ID = "test-project";
+
+    private final FlociGcpContainer container;
+
+    public GoogleStorageLocalContainerInfraService() {
+        this(LocalPropertyResolver.getProperty(FlociGcpContainer.class, 
GoogleProperties.GOOGLE_CONTAINER));
+    }
+
+    public GoogleStorageLocalContainerInfraService(String imageName) {
+        container = initContainer(imageName);
+        String name = ContainerEnvironmentUtil.containerName(this.getClass());
+        if (name != null) {
+            container.withCreateContainerCmdModifier(cmd -> 
cmd.withName(name));
+        }
+    }
+
+    public GoogleStorageLocalContainerInfraService(FlociGcpContainer 
container) {
+        this.container = container;
+    }
+
+    protected FlociGcpContainer initContainer(String imageName) {
+        return new FlociGcpContainer(imageName, 
ContainerEnvironmentUtil.isFixedPort(this.getClass()));
+    }
+
+    @Override
+    public void registerProperties() {
+        System.setProperty(GoogleStorageProperties.PROJECT_ID, projectId());
+        System.setProperty(GoogleStorageProperties.ENDPOINT, endpoint());
+    }
+
+    @Override
+    public void initialize() {
+        container.start();
+
+        LOG.info("Floci GCP running at address {}", 
container.serviceAddress());
+
+        registerProperties();
+    }
+
+    @Override
+    public void shutdown() {
+        container.stop();
+    }
+
+    @Override
+    public FlociGcpContainer getContainer() {
+        return container;
+    }
+
+    /**
+     * The id of the project, {@code test-project} unless the {@code 
google.storage.project.id} system property gives
+     * another one: Floci GCP accepts any
+     */
+    @Override
+    public String projectId() {
+        return System.getProperty(GoogleStorageProperties.PROJECT_ID, 
DEFAULT_PROJECT_ID);
+    }
+
+    @Override
+    public String endpoint() {
+        return container.serviceAddress();
+    }
+}
diff --git 
a/test-infra/camel-test-infra-google-storage/src/main/java/org/apache/camel/test/infra/google/storage/services/GoogleStorageRemoteInfraService.java
 
b/test-infra/camel-test-infra-google-storage/src/main/java/org/apache/camel/test/infra/google/storage/services/GoogleStorageRemoteInfraService.java
new file mode 100644
index 000000000000..14fbf99c8a31
--- /dev/null
+++ 
b/test-infra/camel-test-infra-google-storage/src/main/java/org/apache/camel/test/infra/google/storage/services/GoogleStorageRemoteInfraService.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.test.infra.google.storage.services;
+
+import 
org.apache.camel.test.infra.google.storage.common.GoogleStorageProperties;
+
+/**
+ * The Cloud Storage service of a real Google Cloud project, which the clients 
reach with the application default
+ * credentials, such as the key of the {@code GOOGLE_APPLICATION_CREDENTIALS} 
environment variable.
+ */
+public class GoogleStorageRemoteInfraService implements 
GoogleStorageInfraService {
+    private static final String DEFAULT_ENDPOINT = 
"https://storage.googleapis.com";;
+
+    @Override
+    public void registerProperties() {
+        // NO-OP
+    }
+
+    @Override
+    public void initialize() {
+        registerProperties();
+    }
+
+    @Override
+    public void shutdown() {
+        // NO-OP
+    }
+
+    /**
+     * The id of the project of the {@code google.storage.project.id} system 
property, if any: the clients otherwise
+     * take the one of the application default credentials
+     */
+    @Override
+    public String projectId() {
+        return System.getProperty(GoogleStorageProperties.PROJECT_ID);
+    }
+
+    @Override
+    public String endpoint() {
+        return System.getProperty(GoogleStorageProperties.ENDPOINT, 
DEFAULT_ENDPOINT);
+    }
+}
diff --git 
a/test-infra/camel-test-infra-google-storage/src/main/java/org/apache/camel/test/infra/google/storage/services/GoogleStorageService.java
 
b/test-infra/camel-test-infra-google-storage/src/main/java/org/apache/camel/test/infra/google/storage/services/GoogleStorageService.java
new file mode 100644
index 000000000000..c330661c8f59
--- /dev/null
+++ 
b/test-infra/camel-test-infra-google-storage/src/main/java/org/apache/camel/test/infra/google/storage/services/GoogleStorageService.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.test.infra.google.storage.services;
+
+import org.apache.camel.test.infra.common.services.ContainerTestService;
+import org.apache.camel.test.infra.common.services.TestService;
+
+/**
+ * Test infra service for Google Cloud Storage
+ */
+public interface GoogleStorageService extends GoogleStorageInfraService, 
TestService, ContainerTestService {
+}
diff --git 
a/test-infra/camel-test-infra-google-storage/src/main/java/org/apache/camel/test/infra/google/storage/services/GoogleStorageServiceFactory.java
 
b/test-infra/camel-test-infra-google-storage/src/main/java/org/apache/camel/test/infra/google/storage/services/GoogleStorageServiceFactory.java
new file mode 100644
index 000000000000..0ab5dd4661b0
--- /dev/null
+++ 
b/test-infra/camel-test-infra-google-storage/src/main/java/org/apache/camel/test/infra/google/storage/services/GoogleStorageServiceFactory.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.test.infra.google.storage.services;
+
+import org.apache.camel.test.infra.common.services.SimpleTestServiceBuilder;
+import org.apache.camel.test.infra.common.services.SingletonService;
+
+/**
+ * Creates the Cloud Storage service of Floci GCP, or with {@code 
-Dgoogle.instance.type=remote} the one of a real
+ * Google Cloud project.
+ */
+public final class GoogleStorageServiceFactory {
+
+    private static class SingletonGoogleStorageService extends 
SingletonService<GoogleStorageService>
+            implements GoogleStorageService {
+        public SingletonGoogleStorageService(GoogleStorageService service, 
String name) {
+            super(service, name);
+        }
+
+        @Override
+        public String projectId() {
+            return getService().projectId();
+        }
+
+        @Override
+        public String endpoint() {
+            return getService().endpoint();
+        }
+    }
+
+    private GoogleStorageServiceFactory() {
+
+    }
+
+    public static SimpleTestServiceBuilder<GoogleStorageService> builder() {
+        return new SimpleTestServiceBuilder<>("google");
+    }
+
+    public static GoogleStorageService createService() {
+        return builder()
+                .addLocalMapping(GoogleStorageLocalContainerService::new)
+                .addRemoteMapping(GoogleStorageRemoteService::new)
+                .build();
+    }
+
+    public static GoogleStorageService createSingletonService() {
+        return SingletonServiceHolder.INSTANCE;
+    }
+
+    private static class SingletonServiceHolder {
+        static final GoogleStorageService INSTANCE;
+        static {
+            SimpleTestServiceBuilder<GoogleStorageService> instance = 
builder();
+            // a name of its own: the singleton of another Google service of 
the same JVM must not stand for this one
+            instance.addLocalMapping(
+                    () -> new SingletonGoogleStorageService(new 
GoogleStorageLocalContainerService(), "google-storage"))
+                    .addRemoteMapping(GoogleStorageRemoteService::new);
+            INSTANCE = instance.build();
+        }
+    }
+
+    static class GoogleStorageLocalContainerService extends 
GoogleStorageLocalContainerInfraService
+            implements GoogleStorageService {
+    }
+
+    static class GoogleStorageRemoteService extends 
GoogleStorageRemoteInfraService implements GoogleStorageService {
+    }
+}
diff --git 
a/test-infra/camel-test-infra-google-storage/src/main/resources/META-INF/MANIFEST.MF
 
b/test-infra/camel-test-infra-google-storage/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/test-infra/pom.xml b/test-infra/pom.xml
index e8da1e527977..020f4d5b8562 100644
--- a/test-infra/pom.xml
+++ b/test-infra/pom.xml
@@ -67,7 +67,9 @@
         <module>camel-test-infra-arangodb</module>
         <module>camel-test-infra-apicurio-registry</module>
         <module>camel-test-infra-consul</module>
+        <module>camel-test-infra-google-common</module>
         <module>camel-test-infra-google-pubsub</module>
+        <module>camel-test-infra-google-storage</module>
         <module>camel-test-infra-infinispan</module>
         <module>camel-test-infra-microprofile-lra</module>
         <module>camel-test-infra-minio</module>

Reply via email to