gnodet-bot commented on code in PR #29249:
URL: https://github.com/apache/camel/pull/29249#discussion_r4492277631


##########
test-infra/camel-test-infra-azure-cosmosdb/src/main/java/org/apache/camel/test/infra/azure/cosmosdb/clients/AzureCosmosDbClientUtils.java:
##########
@@ -0,0 +1,151 @@
+/*
+ * 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.cosmosdb.clients;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+import com.azure.cosmos.CosmosAsyncClient;
+import com.azure.cosmos.CosmosClientBuilder;
+import 
org.apache.camel.test.infra.azure.cosmosdb.common.AzureCosmosDbProperties;
+
+public final class AzureCosmosDbClientUtils {
+    private static final String TRUST_STORE = "javax.net.ssl.trustStore";
+    private static final String TRUST_STORE_TYPE = 
"javax.net.ssl.trustStoreType";
+    private static final String TRUST_STORE_PASSWORD = 
"javax.net.ssl.trustStorePassword";
+    private static final String TRUST_STORE_PROVIDER = 
"javax.net.ssl.trustStoreProvider";
+
+    private AzureCosmosDbClientUtils() {
+
+    }
+
+    /**
+     * Builds a client of the account the tests run against: the local Floci 
AZ container, unless the
+     * {@link AzureCosmosDbProperties#INSTANCE_TYPE} system property is {@code 
remote}. Like the clients the
+     * azure-cosmosdb component builds by default, it returns the items it 
writes.
+     */
+    public static CosmosAsyncClient createAsyncClient() {
+        CosmosClientBuilder builder = new CosmosClientBuilder()
+                .endpoint(System.getProperty(AzureCosmosDbProperties.ENDPOINT))
+                .key(System.getProperty(AzureCosmosDbProperties.ACCESS_KEY))
+                .contentResponseOnWriteEnabled(true);
+
+        String instanceType = 
System.getProperty(AzureCosmosDbProperties.INSTANCE_TYPE);
+        if (instanceType == null || 
instanceType.equals("local-azure-container")) {
+            // Floci AZ emulates the gateway API only, and the client keeps to 
the endpoint whatever locations the
+            // emulator advertises
+            builder.gatewayMode()
+                    .endpointDiscoveryEnabled(false);
+
+            return buildTrusting(builder, 
System.getProperty(AzureCosmosDbProperties.CERTIFICATE_URL));
+        }
+
+        return builder.buildAsyncClient();
+    }
+
+    /*
+     * The Cosmos DB SDK has no option for the certificates a client trusts: a 
client trusts the default trust store of
+     * the JVM, which it loads when it is built. The default trust store holds 
the certificate of the emulator, next to the
+     * certificates the JVM trusts, only while the client is built: the client 
trusts the emulator, and the trust of the
+     * JVM is the same once the client is built.
+     */
+    private static synchronized CosmosAsyncClient 
buildTrusting(CosmosClientBuilder builder, String certificateUrl) {
+        Map<String, String> previous = new HashMap<>();
+        for (String name : new String[] { TRUST_STORE, TRUST_STORE_TYPE, 
TRUST_STORE_PASSWORD, TRUST_STORE_PROVIDER }) {
+            previous.put(name, System.getProperty(name));
+        }
+
+        Path trustStoreFile = null;
+        try {
+            String password = UUID.randomUUID().toString();
+            trustStoreFile = Files.createTempFile("floci-az-cosmos-trust", 
".p12");
+            try (OutputStream out = Files.newOutputStream(trustStoreFile)) {
+                trustStore(readCertificate(certificateUrl)).store(out, 
password.toCharArray());
+            }
+
+            System.setProperty(TRUST_STORE, trustStoreFile.toString());
+            System.setProperty(TRUST_STORE_TYPE, "PKCS12");
+            System.setProperty(TRUST_STORE_PASSWORD, password);
+            System.clearProperty(TRUST_STORE_PROVIDER);
+
+            return builder.buildAsyncClient();

Review Comment:
   ⚠️ The `finally` block below (lines 104–112) restores system properties and 
deletes the trust store file immediately after this call returns. This relies 
on the SDK loading its `SslContext` eagerly during `buildAsyncClient()` — a 
valid assumption today, but worth documenting explicitly. If a future SDK 
version defers TLS initialization, the trust store will already be deleted when 
it tries to load. Consider adding a note to the Javadoc above.



##########
components/camel-azure/camel-azure-cosmosdb/src/test/java/org/apache/camel/component/azure/cosmosdb/integration/operations/CosmosDbContainerOperationsIT.java:
##########
@@ -50,38 +49,31 @@
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-@EnabledIfSystemProperties({
-        @EnabledIfSystemProperty(named = "endpoint", matches = ".*",
-                                 disabledReason = "Make sure you supply 
CosmosDB endpoint, e.g: mvn clean install -Dendpoint="),
-        @EnabledIfSystemProperty(named = "accessKey", matches = ".*",
-                                 disabledReason = "Make sure you supply 
CosmosDB accessKey, e.g: mvn clean install -DaccessKey=")
-})
 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
 class CosmosDbContainerOperationsIT {
     private static final String DATABASE_NAME = 
RandomStringUtils.secure().nextAlphabetic(10).toLowerCase();
     private static final String LEASE_DATABASE_NAME = 
RandomStringUtils.secure().nextAlphabetic(10).toLowerCase();
 
+    @RegisterExtension
+    static AzureCosmosDbService service = CosmosDbTestUtils.createService();
+
     private CosmosAsyncClientWrapper clientWrapper;
     private CosmosDbContainerOperations containerOperations;
     private String containerId;
 
     @BeforeAll
-    void prepare() throws Exception {
-        final Properties properties = 
CosmosDbTestUtils.loadAzureAccessFromJvmEnv();
-
-        final CosmosAsyncClient client = new CosmosClientBuilder()
-                .contentResponseOnWriteEnabled(true)
-                .key(properties.getProperty("access_key"))
-                .endpoint(properties.getProperty("endpoint"))
-                .buildAsyncClient();
-
-        clientWrapper = new CosmosAsyncClientWrapper(client);
+    void prepare() {
+        clientWrapper = new 
CosmosAsyncClientWrapper(CosmosDbTestUtils.createAsyncClient());
     }
 
     @AfterAll
     void cleanup() {
         clientWrapper.getDatabase(DATABASE_NAME).delete().block();
-        clientWrapper.getDatabase(LEASE_DATABASE_NAME).delete().block();
+        // only testCaptureChangeFeed creates the lease database, and it does 
not always run
+        clientWrapper.readAllDatabases()
+                .filter(database -> 
LEASE_DATABASE_NAME.equals(database.getId()))
+                .flatMap(database -> 
clientWrapper.getDatabase(LEASE_DATABASE_NAME).delete())
+                .blockLast();
     }

Review Comment:
   ⚠️ The cleanup calls (`delete().block()` and `.blockLast()`) will throw if 
the container has stopped or a database doesn't exist, potentially masking the 
actual test failure. Wrap each in a `try/catch` for best-effort teardown 
(swallow, or at most log at WARN level).



##########
test-infra/camel-test-infra-azure-cosmosdb/src/main/java/org/apache/camel/test/infra/azure/cosmosdb/clients/AzureCosmosDbClientUtils.java:
##########
@@ -0,0 +1,151 @@
+/*
+ * 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.cosmosdb.clients;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+import com.azure.cosmos.CosmosAsyncClient;
+import com.azure.cosmos.CosmosClientBuilder;
+import 
org.apache.camel.test.infra.azure.cosmosdb.common.AzureCosmosDbProperties;
+
+public final class AzureCosmosDbClientUtils {
+    private static final String TRUST_STORE = "javax.net.ssl.trustStore";
+    private static final String TRUST_STORE_TYPE = 
"javax.net.ssl.trustStoreType";
+    private static final String TRUST_STORE_PASSWORD = 
"javax.net.ssl.trustStorePassword";
+    private static final String TRUST_STORE_PROVIDER = 
"javax.net.ssl.trustStoreProvider";
+
+    private AzureCosmosDbClientUtils() {
+
+    }
+
+    /**
+     * Builds a client of the account the tests run against: the local Floci 
AZ container, unless the
+     * {@link AzureCosmosDbProperties#INSTANCE_TYPE} system property is {@code 
remote}. Like the clients the
+     * azure-cosmosdb component builds by default, it returns the items it 
writes.
+     */
+    public static CosmosAsyncClient createAsyncClient() {
+        CosmosClientBuilder builder = new CosmosClientBuilder()
+                .endpoint(System.getProperty(AzureCosmosDbProperties.ENDPOINT))
+                .key(System.getProperty(AzureCosmosDbProperties.ACCESS_KEY))
+                .contentResponseOnWriteEnabled(true);
+
+        String instanceType = 
System.getProperty(AzureCosmosDbProperties.INSTANCE_TYPE);
+        if (instanceType == null || 
instanceType.equals("local-azure-container")) {
+            // Floci AZ emulates the gateway API only, and the client keeps to 
the endpoint whatever locations the
+            // emulator advertises
+            builder.gatewayMode()
+                    .endpointDiscoveryEnabled(false);
+
+            return buildTrusting(builder, 
System.getProperty(AzureCosmosDbProperties.CERTIFICATE_URL));

Review Comment:
   💡 `System.getProperty(AzureCosmosDbProperties.CERTIFICATE_URL)` can return 
`null` if the property is unset. Downstream, `URI.create(null)` throws 
`NullPointerException` with no useful context. Consider adding:
   ```java
   String certUrl = System.getProperty(AzureCosmosDbProperties.CERTIFICATE_URL);
   Objects.requireNonNull(certUrl, "System property " + 
AzureCosmosDbProperties.CERTIFICATE_URL + " must be set for Floci AZ emulator");
   return buildTrusting(builder, certUrl);
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to