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

oscerd 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 0a5082e633a4 CAMEL-26615: camel-azure-storage-datalake - run the 
integration tests on Floci AZ (#29229)
0a5082e633a4 is described below

commit 0a5082e633a4b50dbca3f700da7e9e69aeed40da
Author: Andrea Cosentino <[email protected]>
AuthorDate: Thu Nov 5 13:56:53 2026 +0100

    CAMEL-26615: camel-azure-storage-datalake - run the integration tests on 
Floci AZ (#29229)
    
    The Data Lake integration tests ran only against a real storage account:
    Azurite has no DFS API, so camel-test-infra-azure-storage-datalake had no
    local service.
    
    Add a Floci AZ container (mirror.gcr.io/floci/floci-az, the Azure emulator
    of the Floci family the AWS test-infra uses) and a FlociAzInfraService base
    to camel-test-infra-azure-common, and a local storage-datalake service on 
it.
    Floci AZ answers the DFS API only for the host 
<account>.dfs.core.windows.net
    with no account in the path, so the test-infra client sends its requests
    that way. The four integration tests run against it by default, and against
    a real account when accountName and accountKey are given; they are skipped
    on ppc64le and s390x. The remote endpoint no longer has the account key in
    its path.
    
    DataLakeProducerIT no longer expects file systems before it creates one,
    and DataLakeConsumerIT.testPollingToFile no longer deletes the file the
    consumer may already have downloaded.
    
    Blob and Queue stay on Azurite (CAMEL-26613): their image moves to the
    azure.storage.blob.container and azure.storage.queue.container keys, so the
    test-infra metadata matches them by their implementation alias, while
    azure.container holds the Floci AZ image.
    
    Signed-off-by: Andrea Cosentino <[email protected]>
    Co-authored-by: Claude Opus 5.5 <[email protected]>
---
 .../apache/camel/catalog/test-infra/metadata.json  | 11 +++
 .../camel-azure-storage-datalake/pom.xml           |  6 ++
 .../azure/storage/datalake/integration/Base.java   |  6 +-
 .../datalake/integration/DataLakeConsumerIT.java   |  5 --
 .../integration/DataLakeFileOperationIT.java       |  2 -
 .../integration/DataLakeFileSystemOperationIT.java |  2 -
 .../datalake/integration/DataLakeProducerIT.java   |  4 --
 .../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc    |  8 +++
 .../src/generated/resources/META-INF/metadata.json | 11 +++
 .../test/infra/azure/common/AzureProperties.java   | 12 ++++
 .../common/services/AzureStorageInfraService.java  |  3 +-
 .../azure/common/services/FlociAzContainer.java    | 84 ++++++++++++++++++++++
 ...eInfraService.java => FlociAzInfraService.java} | 64 ++++++++++++-----
 .../azure/common/services/container.properties     | 10 ++-
 ...AzureStorageBlobLocalContainerInfraService.java |  6 ++
 .../clients/AzureStorageDataLakeClientUtils.java   | 56 +++++++++++++--
 ...eStorageDataLakeLocalContainerInfraService.java | 33 +++++++++
 .../AzureStorageDataLakeServiceFactory.java        |  9 ++-
 ...zureStorageQueueLocalContainerInfraService.java |  6 ++
 19 files changed, 298 insertions(+), 40 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 59238f890ae9..aced56b21e4f 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
@@ -394,6 +394,17 @@
   "version" : "4.24.0-SNAPSHOT",
   "serviceVersion" : "5.0.1",
   "uiSupported" : false
+}, {
+  "service" : 
"org.apache.camel.test.infra.azure.common.services.AzureInfraService",
+  "description" : "Local Azure Data Lake Storage Gen2 service with Floci AZ",
+  "implementation" : 
"org.apache.camel.test.infra.azure.storage.datalake.services.AzureStorageDataLakeLocalContainerInfraService",
+  "alias" : [ "azure" ],
+  "aliasImplementation" : [ "storage-datalake" ],
+  "groupId" : "org.apache.camel",
+  "artifactId" : "camel-test-infra-azure-storage-datalake",
+  "version" : "4.24.0-SNAPSHOT",
+  "serviceVersion" : "0.16.0",
+  "uiSupported" : false
 }, {
   "service" : 
"org.apache.camel.test.infra.artemis.services.ArtemisInfraService",
   "description" : "Apache Artemis is an open source message broker",
diff --git a/components/camel-azure/camel-azure-storage-datalake/pom.xml 
b/components/camel-azure/camel-azure-storage-datalake/pom.xml
index 603c8cceaddd..2bfe6744997a 100644
--- a/components/camel-azure/camel-azure-storage-datalake/pom.xml
+++ b/components/camel-azure/camel-azure-storage-datalake/pom.xml
@@ -32,6 +32,12 @@
     <name>Camel :: Azure :: Storage Datalake</name>
     <description>Camel Azure Datalake Component</description>
 
+    <properties>
+        <!-- Floci AZ is not available on these platforms -->
+        <skipITs.ppc64le>true</skipITs.ppc64le>
+        <skipITs.s390x>true</skipITs.s390x>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>org.apache.camel</groupId>
diff --git 
a/components/camel-azure/camel-azure-storage-datalake/src/test/java/org/apache/camel/component/azure/storage/datalake/integration/Base.java
 
b/components/camel-azure/camel-azure-storage-datalake/src/test/java/org/apache/camel/component/azure/storage/datalake/integration/Base.java
index 0c1865ebbe34..0f5d14962460 100644
--- 
a/components/camel-azure/camel-azure-storage-datalake/src/test/java/org/apache/camel/component/azure/storage/datalake/integration/Base.java
+++ 
b/components/camel-azure/camel-azure-storage-datalake/src/test/java/org/apache/camel/component/azure/storage/datalake/integration/Base.java
@@ -37,7 +37,6 @@ import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.TestInstance;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-//@EnabledIfSystemProperty(named = "azure.instance.type", matches = "remote")
 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
 public class Base extends CamelTestSupport {
 
@@ -59,6 +58,10 @@ public class Base extends CamelTestSupport {
         return context;
     }
 
+    /*
+     * The tests run against a local Floci AZ container, unless the 
accountName and accountKey properties are set: then
+     * they run against that storage account.
+     */
     static void initCredentials() {
         String accountName = System.getProperty("accountName");
         String accessKey = System.getProperty("accountKey");
@@ -66,6 +69,7 @@ public class Base extends CamelTestSupport {
         if (StringUtils.isNotEmpty(accountName) && 
StringUtils.isNotEmpty(accessKey)) {
             System.setProperty(AzureConfigs.ACCOUNT_NAME, accountName);
             System.setProperty(AzureConfigs.ACCOUNT_KEY, accessKey);
+            System.setProperty("azure.instance.type", "remote");
         }
     }
 
diff --git 
a/components/camel-azure/camel-azure-storage-datalake/src/test/java/org/apache/camel/component/azure/storage/datalake/integration/DataLakeConsumerIT.java
 
b/components/camel-azure/camel-azure-storage-datalake/src/test/java/org/apache/camel/component/azure/storage/datalake/integration/DataLakeConsumerIT.java
index a80530a65091..6a7a2c035370 100644
--- 
a/components/camel-azure/camel-azure-storage-datalake/src/test/java/org/apache/camel/component/azure/storage/datalake/integration/DataLakeConsumerIT.java
+++ 
b/components/camel-azure/camel-azure-storage-datalake/src/test/java/org/apache/camel/component/azure/storage/datalake/integration/DataLakeConsumerIT.java
@@ -21,7 +21,6 @@ import java.io.File;
 import java.io.InputStream;
 import java.io.UncheckedIOException;
 import java.nio.charset.Charset;
-import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.List;
@@ -42,14 +41,12 @@ import org.apache.commons.lang3.RandomStringUtils;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
 import org.junit.jupiter.api.io.TempDir;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-@EnabledIfSystemProperty(named = "azure.instance.type", matches = "remote")
 public class DataLakeConsumerIT extends Base {
 
     @TempDir
@@ -118,8 +115,6 @@ public class DataLakeConsumerIT extends Base {
 
     @Test
     void testPollingToFile() throws Exception {
-        Files.deleteIfExists(new File(testDir + "/" + fileName).toPath());
-
         final MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
         mockEndpoint.expectedMessageCount(1);
         mockEndpoint.assertIsSatisfied();
diff --git 
a/components/camel-azure/camel-azure-storage-datalake/src/test/java/org/apache/camel/component/azure/storage/datalake/integration/DataLakeFileOperationIT.java
 
b/components/camel-azure/camel-azure-storage-datalake/src/test/java/org/apache/camel/component/azure/storage/datalake/integration/DataLakeFileOperationIT.java
index 941fe0b3b4a7..e6635c6d14ef 100644
--- 
a/components/camel-azure/camel-azure-storage-datalake/src/test/java/org/apache/camel/component/azure/storage/datalake/integration/DataLakeFileOperationIT.java
+++ 
b/components/camel-azure/camel-azure-storage-datalake/src/test/java/org/apache/camel/component/azure/storage/datalake/integration/DataLakeFileOperationIT.java
@@ -40,12 +40,10 @@ import org.apache.commons.lang3.RandomStringUtils;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
 import org.junit.jupiter.api.io.TempDir;
 
 import static org.junit.jupiter.api.Assertions.*;
 
-@EnabledIfSystemProperty(named = "azure.instance.type", matches = "remote")
 public class DataLakeFileOperationIT extends Base {
     private DataLakeFileSystemClientWrapper fileSystemClientWrapper;
     private String randomFileName;
diff --git 
a/components/camel-azure/camel-azure-storage-datalake/src/test/java/org/apache/camel/component/azure/storage/datalake/integration/DataLakeFileSystemOperationIT.java
 
b/components/camel-azure/camel-azure-storage-datalake/src/test/java/org/apache/camel/component/azure/storage/datalake/integration/DataLakeFileSystemOperationIT.java
index 3eacc8f86506..ee528f68dd95 100644
--- 
a/components/camel-azure/camel-azure-storage-datalake/src/test/java/org/apache/camel/component/azure/storage/datalake/integration/DataLakeFileSystemOperationIT.java
+++ 
b/components/camel-azure/camel-azure-storage-datalake/src/test/java/org/apache/camel/component/azure/storage/datalake/integration/DataLakeFileSystemOperationIT.java
@@ -28,11 +28,9 @@ import org.awaitility.Awaitility;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
 
 import static org.junit.jupiter.api.Assertions.*;
 
-@EnabledIfSystemProperty(named = "azure.instance.type", matches = "remote")
 public class DataLakeFileSystemOperationIT extends Base {
 
     private DataLakeServiceClientWrapper serviceClientWrapper;
diff --git 
a/components/camel-azure/camel-azure-storage-datalake/src/test/java/org/apache/camel/component/azure/storage/datalake/integration/DataLakeProducerIT.java
 
b/components/camel-azure/camel-azure-storage-datalake/src/test/java/org/apache/camel/component/azure/storage/datalake/integration/DataLakeProducerIT.java
index 21f40d4624e8..cc5c3de4ff16 100644
--- 
a/components/camel-azure/camel-azure-storage-datalake/src/test/java/org/apache/camel/component/azure/storage/datalake/integration/DataLakeProducerIT.java
+++ 
b/components/camel-azure/camel-azure-storage-datalake/src/test/java/org/apache/camel/component/azure/storage/datalake/integration/DataLakeProducerIT.java
@@ -28,11 +28,9 @@ import org.apache.commons.lang3.RandomStringUtils;
 import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-@EnabledIfSystemProperty(named = "azure.instance.type", matches = "remote")
 public class DataLakeProducerIT extends Base {
 
     private String fileName;
@@ -55,7 +53,6 @@ public class DataLakeProducerIT extends Base {
                     null,
                     List.class);
 
-            
Assertions.assertThat(filesystems.stream().map(FileSystemItem::getName)).isNotEmpty();
             
Assertions.assertThat(filesystems.stream().map(FileSystemItem::getName)).doesNotContain(fileSystemName);
         }
 
@@ -100,7 +97,6 @@ public class DataLakeProducerIT extends Base {
                     null,
                     List.class);
 
-            
Assertions.assertThat(filesystems.stream().map(FileSystemItem::getName)).isNotEmpty();
             
Assertions.assertThat(filesystems.stream().map(FileSystemItem::getName)).doesNotContain(fileSystemName);
         }
 
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index 7f2031673993..ded84bf0357b 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -1356,6 +1356,14 @@ the initial state (`camel.health.initial-state`, DOWN by 
default) while the firs
 the change feed processor cannot start, with the failure of the last attempt; 
before, it was UP. To leave
 the check out, as before, set 
`camel.health.exclude-pattern=consumer:<routeId>`.
 
+=== camel-test-infra-azure - the azure.container property holds the Floci AZ 
image
+
+The Azure test-infra runs its new local Data Lake Storage Gen2 service (`camel 
infra run azure storage-datalake`) on
+https://github.com/floci-io/floci-az[Floci AZ], and the `azure.container` 
property of `camel-test-infra-azure-common`
+now holds the Floci AZ image. The Blob and Queue services still run on 
Azurite, whose image is now set with the
+`azure.storage.blob.container` and `azure.storage.queue.container` properties: 
to run them on another Azurite image,
+set these instead of `azure.container`.
+
 === camel-vertx-websocket - consumers on the same host and port must use the 
same SSLContextParameters
 
 All `vertx-websocket` consumers on the same host and port are served by one 
HTTP server, which is created from the
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 59238f890ae9..aced56b21e4f 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
@@ -394,6 +394,17 @@
   "version" : "4.24.0-SNAPSHOT",
   "serviceVersion" : "5.0.1",
   "uiSupported" : false
+}, {
+  "service" : 
"org.apache.camel.test.infra.azure.common.services.AzureInfraService",
+  "description" : "Local Azure Data Lake Storage Gen2 service with Floci AZ",
+  "implementation" : 
"org.apache.camel.test.infra.azure.storage.datalake.services.AzureStorageDataLakeLocalContainerInfraService",
+  "alias" : [ "azure" ],
+  "aliasImplementation" : [ "storage-datalake" ],
+  "groupId" : "org.apache.camel",
+  "artifactId" : "camel-test-infra-azure-storage-datalake",
+  "version" : "4.24.0-SNAPSHOT",
+  "serviceVersion" : "0.16.0",
+  "uiSupported" : false
 }, {
   "service" : 
"org.apache.camel.test.infra.artemis.services.ArtemisInfraService",
   "description" : "Apache Artemis is an open source message broker",
diff --git 
a/test-infra/camel-test-infra-azure-common/src/main/java/org/apache/camel/test/infra/azure/common/AzureProperties.java
 
b/test-infra/camel-test-infra-azure-common/src/main/java/org/apache/camel/test/infra/azure/common/AzureProperties.java
index 15120c7aa348..74f40e210c7b 100644
--- 
a/test-infra/camel-test-infra-azure-common/src/main/java/org/apache/camel/test/infra/azure/common/AzureProperties.java
+++ 
b/test-infra/camel-test-infra-azure-common/src/main/java/org/apache/camel/test/infra/azure/common/AzureProperties.java
@@ -18,7 +18,19 @@
 package org.apache.camel.test.infra.azure.common;
 
 public final class AzureProperties {
+    /**
+     * The Floci AZ image of the local Azure services
+     */
     public static final String AZURE_CONTAINER = "azure.container";
+    /**
+     * The Azurite image of the local Blob service. Blob and Queue keep a key 
each, so the version of the test-infra
+     * metadata is matched by their implementation alias and not by the shared 
{@code azure} alias of Floci AZ.
+     */
+    public static final String AZURE_STORAGE_BLOB_CONTAINER = 
"azure.storage.blob.container";
+    /**
+     * The Azurite image of the local Queue service
+     */
+    public static final String AZURE_STORAGE_QUEUE_CONTAINER = 
"azure.storage.queue.container";
 
     private AzureProperties() {
 
diff --git 
a/test-infra/camel-test-infra-azure-common/src/main/java/org/apache/camel/test/infra/azure/common/services/AzureStorageInfraService.java
 
b/test-infra/camel-test-infra-azure-common/src/main/java/org/apache/camel/test/infra/azure/common/services/AzureStorageInfraService.java
index 25a95ca2a291..90572da26321 100644
--- 
a/test-infra/camel-test-infra-azure-common/src/main/java/org/apache/camel/test/infra/azure/common/services/AzureStorageInfraService.java
+++ 
b/test-infra/camel-test-infra-azure-common/src/main/java/org/apache/camel/test/infra/azure/common/services/AzureStorageInfraService.java
@@ -30,7 +30,8 @@ public abstract class AzureStorageInfraService implements 
AzureInfraService, Con
     private final AzuriteContainer container;
 
     protected AzureStorageInfraService() {
-        this(LocalPropertyResolver.getProperty(AzureStorageInfraService.class, 
AzureProperties.AZURE_CONTAINER));
+        this(LocalPropertyResolver.getProperty(AzureStorageInfraService.class,
+                AzureProperties.AZURE_STORAGE_BLOB_CONTAINER));
     }
 
     protected AzureStorageInfraService(String imageName) {
diff --git 
a/test-infra/camel-test-infra-azure-common/src/main/java/org/apache/camel/test/infra/azure/common/services/FlociAzContainer.java
 
b/test-infra/camel-test-infra-azure-common/src/main/java/org/apache/camel/test/infra/azure/common/services/FlociAzContainer.java
new file mode 100644
index 000000000000..5ce38aca62d2
--- /dev/null
+++ 
b/test-infra/camel-test-infra-azure-common/src/main/java/org/apache/camel/test/infra/azure/common/services/FlociAzContainer.java
@@ -0,0 +1,84 @@
+/*
+ * 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.azure.common.services;
+
+import java.time.Duration;
+
+import org.apache.camel.test.infra.azure.common.AzureCredentialsHolder;
+import org.apache.camel.test.infra.azure.common.AzureProperties;
+import org.apache.camel.test.infra.common.LocalPropertyResolver;
+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 AZ (https://github.com/floci-io/floci-az), a 
local Azure emulator. It serves every Azure
+ * service on one port, and tells them apart by the first segment of the path: 
{@code /devstoreaccount1} for Blob and
+ * Data Lake, {@code /devstoreaccount1-queue} for Queue, {@code 
/devstoreaccount1-keyvault} for Key Vault, and so on.
+ */
+public class FlociAzContainer extends GenericContainer<FlociAzContainer> {
+    public static final int SERVICE_PORT = 4577;
+    public static final String DEFAULT_ACCOUNT_NAME = "devstoreaccount1";
+    // the well-known development storage key, which Floci AZ accepts as 
Azurite does
+    public static final String DEFAULT_ACCOUNT_KEY
+            = 
"Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
+
+    public FlociAzContainer() {
+        this(LocalPropertyResolver.getProperty(FlociAzContainer.class, 
AzureProperties.AZURE_CONTAINER), false);
+    }
+
+    public FlociAzContainer(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)));
+    }
+
+    public AzureCredentialsHolder azureCredentials() {
+        return new AzureCredentialsHolder() {
+            @Override
+            public String accountName() {
+                return DEFAULT_ACCOUNT_NAME;
+            }
+
+            @Override
+            public String accountKey() {
+                return DEFAULT_ACCOUNT_KEY;
+            }
+        };
+    }
+
+    /**
+     * The address of the emulator, for example {@code http://localhost:32768}
+     */
+    public String serviceAddress() {
+        return String.format("http://%s:%d";, getHost(), 
getMappedPort(SERVICE_PORT));
+    }
+
+    /**
+     * The endpoint of the storage account, used by the Blob and Data Lake 
clients, for example
+     * {@code http://localhost:32768/devstoreaccount1}
+     */
+    public String accountEndpoint() {
+        return serviceAddress() + "/" + DEFAULT_ACCOUNT_NAME;
+    }
+}
diff --git 
a/test-infra/camel-test-infra-azure-common/src/main/java/org/apache/camel/test/infra/azure/common/services/AzureStorageInfraService.java
 
b/test-infra/camel-test-infra-azure-common/src/main/java/org/apache/camel/test/infra/azure/common/services/FlociAzInfraService.java
similarity index 50%
copy from 
test-infra/camel-test-infra-azure-common/src/main/java/org/apache/camel/test/infra/azure/common/services/AzureStorageInfraService.java
copy to 
test-infra/camel-test-infra-azure-common/src/main/java/org/apache/camel/test/infra/azure/common/services/FlociAzInfraService.java
index 25a95ca2a291..f4b77ec2b389 100644
--- 
a/test-infra/camel-test-infra-azure-common/src/main/java/org/apache/camel/test/infra/azure/common/services/AzureStorageInfraService.java
+++ 
b/test-infra/camel-test-infra-azure-common/src/main/java/org/apache/camel/test/infra/azure/common/services/FlociAzInfraService.java
@@ -18,6 +18,7 @@
 package org.apache.camel.test.infra.azure.common.services;
 
 import org.apache.camel.test.infra.azure.common.AzureConfigs;
+import org.apache.camel.test.infra.azure.common.AzureCredentialsHolder;
 import org.apache.camel.test.infra.azure.common.AzureProperties;
 import org.apache.camel.test.infra.common.LocalPropertyResolver;
 import org.apache.camel.test.infra.common.services.ContainerEnvironmentUtil;
@@ -25,15 +26,19 @@ import 
org.apache.camel.test.infra.common.services.ContainerService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public abstract class AzureStorageInfraService implements AzureInfraService, 
ContainerService<AzuriteContainer> {
-    private static final Logger LOG = 
LoggerFactory.getLogger(AzureStorageInfraService.class);
-    private final AzuriteContainer container;
+/**
+ * Base class of the local Azure services that run on Floci AZ.
+ */
+public abstract class FlociAzInfraService implements AzureInfraService, 
ContainerService<FlociAzContainer> {
+    private static final Logger LOG = 
LoggerFactory.getLogger(FlociAzInfraService.class);
+
+    private final FlociAzContainer container;
 
-    protected AzureStorageInfraService() {
-        this(LocalPropertyResolver.getProperty(AzureStorageInfraService.class, 
AzureProperties.AZURE_CONTAINER));
+    protected FlociAzInfraService() {
+        this(LocalPropertyResolver.getProperty(FlociAzContainer.class, 
AzureProperties.AZURE_CONTAINER));
     }
 
-    protected AzureStorageInfraService(String imageName) {
+    protected FlociAzInfraService(String imageName) {
         this.container = initContainer(imageName);
         String name = ContainerEnvironmentUtil.containerName(this.getClass());
         if (name != null) {
@@ -41,32 +46,32 @@ public abstract class AzureStorageInfraService implements 
AzureInfraService, Con
         }
     }
 
-    protected AzureStorageInfraService(AzuriteContainer container) {
+    protected FlociAzInfraService(FlociAzContainer container) {
         this.container = container;
     }
 
-    protected AzuriteContainer initContainer(String imageName) {
-        return new AzuriteContainer(imageName, 
ContainerEnvironmentUtil.isFixedPort(this.getClass().getSuperclass()));
+    protected FlociAzContainer initContainer(String imageName) {
+        return new FlociAzContainer(imageName, 
ContainerEnvironmentUtil.isFixedPort(this.getClass()));
     }
 
-    public AzuriteContainer getContainer() {
+    @Override
+    public FlociAzContainer getContainer() {
         return container;
     }
 
+    @Override
     public void registerProperties() {
-        System.setProperty(AzureConfigs.ACCOUNT_NAME, 
container.azureCredentials().accountName());
-        System.setProperty(AzureConfigs.ACCOUNT_KEY, 
container.azureCredentials().accountKey());
-        System.setProperty(AzureConfigs.HOST, container.getHost());
+        System.setProperty(AzureConfigs.ACCOUNT_NAME, accountName());
+        System.setProperty(AzureConfigs.ACCOUNT_KEY, accessKey());
+        System.setProperty(AzureConfigs.HOST, host());
+        System.setProperty(AzureConfigs.PORT, String.valueOf(port()));
     }
 
     @Override
     public void initialize() {
         container.start();
 
-        LOG.info("Azurite local blob service running at address {}:{}", 
container.getHost(),
-                container.getMappedPort(AzureServices.BLOB_SERVICE));
-        LOG.info("Azurite local queue service running at address {}:{}", 
container.getHost(),
-                container.getMappedPort(AzureServices.QUEUE_SERVICE));
+        LOG.info("Floci AZ running at address {}", container.serviceAddress());
 
         registerProperties();
     }
@@ -75,4 +80,29 @@ public abstract class AzureStorageInfraService implements 
AzureInfraService, Con
     public void shutdown() {
         container.stop();
     }
+
+    @Override
+    public AzureCredentialsHolder azureCredentials() {
+        return container.azureCredentials();
+    }
+
+    @Override
+    public String accountName() {
+        return container.azureCredentials().accountName();
+    }
+
+    @Override
+    public String accessKey() {
+        return container.azureCredentials().accountKey();
+    }
+
+    @Override
+    public String host() {
+        return container.getHost();
+    }
+
+    @Override
+    public int port() {
+        return container.getMappedPort(FlociAzContainer.SERVICE_PORT);
+    }
 }
diff --git 
a/test-infra/camel-test-infra-azure-common/src/main/resources/org/apache/camel/test/infra/azure/common/services/container.properties
 
b/test-infra/camel-test-infra-azure-common/src/main/resources/org/apache/camel/test/infra/azure/common/services/container.properties
index 78ac5ce78a34..3089b7a8a244 100644
--- 
a/test-infra/camel-test-infra-azure-common/src/main/resources/org/apache/camel/test/infra/azure/common/services/container.properties
+++ 
b/test-infra/camel-test-infra-azure-common/src/main/resources/org/apache/camel/test/infra/azure/common/services/container.properties
@@ -14,5 +14,11 @@
 ## See the License for the specific language governing permissions and
 ## limitations under the License.
 ## ---------------------------------------------------------------------------
-azure.container=mcr.microsoft.com/azure-storage/azurite:3.37.0
-azure.container.version.exclude=table-alpha,amd64,arm64,preview,latest
+# Floci AZ: the local Azure services
+azure.container=mirror.gcr.io/floci/floci-az:0.16.0
+azure.container.version.exclude=latest,nightly,compat
+# Azurite: the local Blob and Queue services, until Floci AZ covers what their 
tests use
+azure.storage.blob.container=mcr.microsoft.com/azure-storage/azurite:3.37.0
+azure.storage.blob.container.version.exclude=table-alpha,amd64,arm64,preview,latest
+azure.storage.queue.container=mcr.microsoft.com/azure-storage/azurite:3.37.0
+azure.storage.queue.container.version.exclude=table-alpha,amd64,arm64,preview,latest
diff --git 
a/test-infra/camel-test-infra-azure-storage-blob/src/main/java/org/apache/camel/test/infra/azure/storage/blob/services/AzureStorageBlobLocalContainerInfraService.java
 
b/test-infra/camel-test-infra-azure-storage-blob/src/main/java/org/apache/camel/test/infra/azure/storage/blob/services/AzureStorageBlobLocalContainerInfraService.java
index 93b4827271ad..2ff578602fe5 100644
--- 
a/test-infra/camel-test-infra-azure-storage-blob/src/main/java/org/apache/camel/test/infra/azure/storage/blob/services/AzureStorageBlobLocalContainerInfraService.java
+++ 
b/test-infra/camel-test-infra-azure-storage-blob/src/main/java/org/apache/camel/test/infra/azure/storage/blob/services/AzureStorageBlobLocalContainerInfraService.java
@@ -20,15 +20,21 @@ package 
org.apache.camel.test.infra.azure.storage.blob.services;
 import org.apache.camel.spi.annotations.InfraService;
 import org.apache.camel.test.infra.azure.common.AzureConfigs;
 import org.apache.camel.test.infra.azure.common.AzureCredentialsHolder;
+import org.apache.camel.test.infra.azure.common.AzureProperties;
 import org.apache.camel.test.infra.azure.common.services.AzureInfraService;
 import org.apache.camel.test.infra.azure.common.services.AzureServices;
 import 
org.apache.camel.test.infra.azure.common.services.AzureStorageInfraService;
+import org.apache.camel.test.infra.common.LocalPropertyResolver;
 
 @InfraService(service = AzureInfraService.class,
               description = "Local Azure services with Azurite",
               serviceAlias = "azure", serviceImplementationAlias = 
"storage-blob")
 public class AzureStorageBlobLocalContainerInfraService extends 
AzureStorageInfraService {
 
+    public AzureStorageBlobLocalContainerInfraService() {
+        
super(LocalPropertyResolver.getProperty(AzureStorageInfraService.class, 
AzureProperties.AZURE_STORAGE_BLOB_CONTAINER));
+    }
+
     @Override
     public void registerProperties() {
         super.registerProperties();
diff --git 
a/test-infra/camel-test-infra-azure-storage-datalake/src/main/java/org/apache/camel/test/infra/azure/storage/datalake/clients/AzureStorageDataLakeClientUtils.java
 
b/test-infra/camel-test-infra-azure-storage-datalake/src/main/java/org/apache/camel/test/infra/azure/storage/datalake/clients/AzureStorageDataLakeClientUtils.java
index fd9a6ccf7dd7..93797ec9ff0a 100644
--- 
a/test-infra/camel-test-infra-azure-storage-datalake/src/main/java/org/apache/camel/test/infra/azure/storage/datalake/clients/AzureStorageDataLakeClientUtils.java
+++ 
b/test-infra/camel-test-infra-azure-storage-datalake/src/main/java/org/apache/camel/test/infra/azure/storage/datalake/clients/AzureStorageDataLakeClientUtils.java
@@ -17,10 +17,19 @@
 
 package org.apache.camel.test.infra.azure.storage.datalake.clients;
 
+import java.net.URL;
+
+import com.azure.core.http.HttpHeaderName;
+import com.azure.core.http.HttpPipelineCallContext;
+import com.azure.core.http.HttpPipelineNextPolicy;
+import com.azure.core.http.HttpRequest;
+import com.azure.core.http.HttpResponse;
+import com.azure.core.http.policy.HttpPipelinePolicy;
 import com.azure.storage.common.StorageSharedKeyCredential;
 import com.azure.storage.file.datalake.DataLakeServiceClient;
 import com.azure.storage.file.datalake.DataLakeServiceClientBuilder;
 import org.apache.camel.test.infra.azure.common.AzureConfigs;
+import reactor.core.publisher.Mono;
 
 public final class AzureStorageDataLakeClientUtils {
 
@@ -35,11 +44,48 @@ public final class AzureStorageDataLakeClientUtils {
         String accountKey = System.getProperty(AzureConfigs.ACCOUNT_KEY);
         StorageSharedKeyCredential credential = new 
StorageSharedKeyCredential(accountName, accountKey);
 
-        String endpoint = String.format("https://%s.dfs.core.windows.net/%s";, 
accountName, accountKey);
+        DataLakeServiceClientBuilder builder = new 
DataLakeServiceClientBuilder()
+                .credential(credential);
+
+        if (instanceType == null || 
instanceType.equals("local-azure-container")) {
+            builder.endpoint(String.format("http://%s:%s/%s";, 
System.getProperty(AzureConfigs.HOST),
+                    System.getProperty(AzureConfigs.PORT), accountName))
+                    .addPolicy(new DfsHostPolicy(accountName));
+        } else {
+            builder.endpoint(String.format("https://%s.dfs.core.windows.net";, 
accountName));
+        }
+
+        return builder.buildClient();
+    }
+
+    /**
+     * Floci AZ serves the Data Lake Storage Gen2 (DFS) API of an account only 
to the requests for the host
+     * {@code <account>.dfs.core.windows.net}, with no account in the path. 
The client is built for the address of the
+     * container, and this policy sends its requests to that host.
+     */
+    private static final class DfsHostPolicy implements HttpPipelinePolicy {
+        private final String accountName;
+
+        private DfsHostPolicy(String accountName) {
+            this.accountName = accountName;
+        }
+
+        @Override
+        public Mono<HttpResponse> process(HttpPipelineCallContext context, 
HttpPipelineNextPolicy next) {
+            HttpRequest request = context.getHttpRequest();
+
+            URL url = request.getUrl();
+            String accountPath = "/" + accountName;
+            String path = url.getPath();
+            if (path.equals(accountPath) || path.startsWith(accountPath + 
"/")) {
+                String rest = path.substring(accountPath.length());
+                String query = url.getQuery();
+                request.setUrl(url.getProtocol() + "://" + url.getAuthority() 
+ (rest.isEmpty() ? "/" : rest)
+                               + (query != null ? "?" + query : ""));
+            }
+            request.setHeader(HttpHeaderName.HOST, accountName + 
".dfs.core.windows.net");
 
-        return new DataLakeServiceClientBuilder()
-                .endpoint(endpoint)
-                .credential(credential)
-                .buildClient();
+            return next.process();
+        }
     }
 }
diff --git 
a/test-infra/camel-test-infra-azure-storage-datalake/src/main/java/org/apache/camel/test/infra/azure/storage/datalake/services/AzureStorageDataLakeLocalContainerInfraService.java
 
b/test-infra/camel-test-infra-azure-storage-datalake/src/main/java/org/apache/camel/test/infra/azure/storage/datalake/services/AzureStorageDataLakeLocalContainerInfraService.java
new file mode 100644
index 000000000000..5856d1b84b67
--- /dev/null
+++ 
b/test-infra/camel-test-infra-azure-storage-datalake/src/main/java/org/apache/camel/test/infra/azure/storage/datalake/services/AzureStorageDataLakeLocalContainerInfraService.java
@@ -0,0 +1,33 @@
+/*
+ * 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.azure.storage.datalake.services;
+
+import org.apache.camel.spi.annotations.InfraService;
+import org.apache.camel.test.infra.azure.common.services.AzureInfraService;
+import org.apache.camel.test.infra.azure.common.services.FlociAzInfraService;
+
+/**
+ * A local Data Lake Storage Gen2 service: Floci AZ serves the DFS API of the 
storage account on its Blob backend. It
+ * answers the DFS API only to the requests for the host {@code 
<account>.dfs.core.windows.net}, with no account in the
+ * path: {@code AzureStorageDataLakeClientUtils} builds a client that sends 
its requests that way.
+ */
+@InfraService(service = AzureInfraService.class,
+              description = "Local Azure Data Lake Storage Gen2 service with 
Floci AZ",
+              serviceAlias = "azure", serviceImplementationAlias = 
"storage-datalake")
+public class AzureStorageDataLakeLocalContainerInfraService extends 
FlociAzInfraService {
+}
diff --git 
a/test-infra/camel-test-infra-azure-storage-datalake/src/main/java/org/apache/camel/test/infra/azure/storage/datalake/services/AzureStorageDataLakeServiceFactory.java
 
b/test-infra/camel-test-infra-azure-storage-datalake/src/main/java/org/apache/camel/test/infra/azure/storage/datalake/services/AzureStorageDataLakeServiceFactory.java
index 95449de430d1..037d570f76d8 100644
--- 
a/test-infra/camel-test-infra-azure-storage-datalake/src/main/java/org/apache/camel/test/infra/azure/storage/datalake/services/AzureStorageDataLakeServiceFactory.java
+++ 
b/test-infra/camel-test-infra-azure-storage-datalake/src/main/java/org/apache/camel/test/infra/azure/storage/datalake/services/AzureStorageDataLakeServiceFactory.java
@@ -66,6 +66,7 @@ public final class AzureStorageDataLakeServiceFactory {
 
     public static AzureService createService() {
         return builder()
+                
.addLocalMapping(AzureStorageDataLakeLocalContainerService::new)
                 .addRemoteMapping(AzureStorageDataLakeRemoteService::new)
                 .build();
     }
@@ -78,11 +79,17 @@ public final class AzureStorageDataLakeServiceFactory {
         static final AzureService INSTANCE;
         static {
             SimpleTestServiceBuilder<AzureService> instance = builder();
-            instance.addRemoteMapping(AzureStorageDataLakeRemoteService::new);
+            instance.addLocalMapping(
+                    () -> new SingletonAzureStorageDataLakeService(new 
AzureStorageDataLakeLocalContainerService(), "azure"))
+                    .addRemoteMapping(AzureStorageDataLakeRemoteService::new);
             INSTANCE = instance.build();
         }
     }
 
+    static class AzureStorageDataLakeLocalContainerService extends 
AzureStorageDataLakeLocalContainerInfraService
+            implements AzureService {
+    }
+
     static class AzureStorageDataLakeRemoteService extends 
AzureStorageDataLakeRemoteInfraService implements AzureService {
     }
 }
diff --git 
a/test-infra/camel-test-infra-azure-storage-queue/src/main/java/org/apache/camel/test/infra/azure/storage/queue/services/AzureStorageQueueLocalContainerInfraService.java
 
b/test-infra/camel-test-infra-azure-storage-queue/src/main/java/org/apache/camel/test/infra/azure/storage/queue/services/AzureStorageQueueLocalContainerInfraService.java
index 60801978fd18..d20d64059934 100644
--- 
a/test-infra/camel-test-infra-azure-storage-queue/src/main/java/org/apache/camel/test/infra/azure/storage/queue/services/AzureStorageQueueLocalContainerInfraService.java
+++ 
b/test-infra/camel-test-infra-azure-storage-queue/src/main/java/org/apache/camel/test/infra/azure/storage/queue/services/AzureStorageQueueLocalContainerInfraService.java
@@ -20,15 +20,21 @@ package 
org.apache.camel.test.infra.azure.storage.queue.services;
 import org.apache.camel.spi.annotations.InfraService;
 import org.apache.camel.test.infra.azure.common.AzureConfigs;
 import org.apache.camel.test.infra.azure.common.AzureCredentialsHolder;
+import org.apache.camel.test.infra.azure.common.AzureProperties;
 import org.apache.camel.test.infra.azure.common.services.AzureInfraService;
 import org.apache.camel.test.infra.azure.common.services.AzureServices;
 import 
org.apache.camel.test.infra.azure.common.services.AzureStorageInfraService;
+import org.apache.camel.test.infra.common.LocalPropertyResolver;
 
 @InfraService(service = AzureInfraService.class,
               description = "Local Azure services with Azurite",
               serviceAlias = "azure", serviceImplementationAlias = 
"storage-queue")
 public class AzureStorageQueueLocalContainerInfraService extends 
AzureStorageInfraService {
 
+    public AzureStorageQueueLocalContainerInfraService() {
+        
super(LocalPropertyResolver.getProperty(AzureStorageInfraService.class, 
AzureProperties.AZURE_STORAGE_QUEUE_CONTAINER));
+    }
+
     @Override
     public void registerProperties() {
         super.registerProperties();

Reply via email to