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 b2dfac0906db CAMEL-24765: camel-huaweicloud-functiongraph - keep the
region in the invoke URN and read the response body robustly (#26496)
b2dfac0906db is described below
commit b2dfac0906dbb665c2365fa67a4eff8f81f492d5
Author: Andrea Cosentino <[email protected]>
AuthorDate: Thu Sep 17 09:54:47 2026 +0200
CAMEL-24765: camel-huaweicloud-functiongraph - keep the region in the
invoke URN and read the response body robustly (#26496)
Populate region independently of the endpoint/region client-init choice so
the invoke URN is never urn:fss:null; extract the response body robustly
(string/primitive/absent, not just objects); require proxyPort > 0.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
---
.../org/apache/camel/FunctionGraphEndpoint.java | 2 +-
.../java/org/apache/camel/FunctionGraphUtils.java | 13 ++++-
.../apache/camel/models/ClientConfigurations.java | 13 +++--
.../FunctionGraphClientConfigurationsTest.java | 51 ++++++++++++++++++
.../org/apache/camel/FunctionGraphUtilsTest.java | 61 ++++++++++++++++++++++
5 files changed, 133 insertions(+), 7 deletions(-)
diff --git
a/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/FunctionGraphEndpoint.java
b/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/FunctionGraphEndpoint.java
index 3f561840fec1..0992b4c9a41f 100644
---
a/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/FunctionGraphEndpoint.java
+++
b/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/FunctionGraphEndpoint.java
@@ -264,7 +264,7 @@ public class FunctionGraphEndpoint extends DefaultEndpoint {
HttpConfig httpConfig = HttpConfig.getDefaultHttpConfig();
httpConfig.withIgnoreSSLVerification(isIgnoreSslVerification());
if (ObjectHelper.isNotEmpty(getProxyHost())
- && ObjectHelper.isNotEmpty(getProxyPort())) {
+ && getProxyPort() > 0) {
httpConfig.withProxyHost(getProxyHost())
.withProxyPort(getProxyPort());
diff --git
a/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/FunctionGraphUtils.java
b/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/FunctionGraphUtils.java
index 1bad9f917dc0..b895a6b92e1f 100644
---
a/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/FunctionGraphUtils.java
+++
b/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/FunctionGraphUtils.java
@@ -17,6 +17,7 @@
package org.apache.camel;
import com.google.gson.Gson;
+import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.apache.camel.models.ClientConfigurations;
@@ -34,7 +35,17 @@ public final class FunctionGraphUtils {
*/
public static String extractJsonFieldAsString(String jsonString, String
fieldName) {
Gson gson = new Gson();
- return gson.fromJson(jsonString,
JsonObject.class).getAsJsonObject(fieldName).toString();
+ JsonObject root = gson.fromJson(jsonString, JsonObject.class);
+ if (root == null) {
+ return null;
+ }
+ JsonElement field = root.get(fieldName);
+ if (field == null || field.isJsonNull()) {
+ return null;
+ }
+ // a FunctionGraph 'body' is commonly a JSON-encoded string/primitive
(HTTP-triggered functions),
+ // not always an object; return the raw value for primitives and the
JSON text for objects/arrays
+ return field.isJsonPrimitive() ? field.getAsString() :
field.toString();
}
/**
diff --git
a/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/models/ClientConfigurations.java
b/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/models/ClientConfigurations.java
index b18f1e5aaf8f..43192c76c03e 100644
---
a/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/models/ClientConfigurations.java
+++
b/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/models/ClientConfigurations.java
@@ -40,20 +40,23 @@ public class ClientConfigurations {
public ClientConfigurations(FunctionGraphEndpoint endpoint) {
- // checking for required region
+ // checking for required region/endpoint (endpoint takes precedence
for client initialization)
if (ObjectHelper.isNotEmpty(endpoint.getEndpoint())) {
this.setEndpoint(endpoint.getEndpoint());
- } else if (ObjectHelper.isNotEmpty(endpoint.getRegion())) {
- this.setRegion(endpoint.getRegion());
- } else {
+ } else if (ObjectHelper.isEmpty(endpoint.getRegion())) {
if (LOG.isErrorEnabled()) {
LOG.error("No region/endpoint given. Cannot proceed with
FunctionGraph operations.");
}
throw new IllegalArgumentException("Region/endpoint not found");
}
+ // the invoke URN always needs the region, even when the client is
initialized from 'endpoint',
+ // so copy it independently instead of only in the region branch above
+ if (ObjectHelper.isNotEmpty(endpoint.getRegion())) {
+ this.setRegion(endpoint.getRegion());
+ }
// checking for optional proxy authentication
- if (ObjectHelper.isNotEmpty(endpoint.getProxyHost()) &&
ObjectHelper.isNotEmpty(endpoint.getProxyPort())) {
+ if (ObjectHelper.isNotEmpty(endpoint.getProxyHost()) &&
endpoint.getProxyPort() > 0) {
this.setProxyHost(endpoint.getProxyHost());
this.setProxyPort(endpoint.getProxyPort());
}
diff --git
a/components/camel-huawei/camel-huaweicloud-functiongraph/src/test/java/org/apache/camel/FunctionGraphClientConfigurationsTest.java
b/components/camel-huawei/camel-huaweicloud-functiongraph/src/test/java/org/apache/camel/FunctionGraphClientConfigurationsTest.java
new file mode 100644
index 000000000000..76469f969a3b
--- /dev/null
+++
b/components/camel-huawei/camel-huaweicloud-functiongraph/src/test/java/org/apache/camel/FunctionGraphClientConfigurationsTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import org.apache.camel.constants.FunctionGraphConstants;
+import org.apache.camel.models.ClientConfigurations;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Verifies that the invoke URN keeps the region even when the client is
initialized from the {@code endpoint}
+ * parameter. Uses {@link CamelTestSupport} because it resolves a real {@link
FunctionGraphEndpoint} from the context.
+ */
+public class FunctionGraphClientConfigurationsTest extends CamelTestSupport {
+
+ @Test
+ public void urnKeepsRegionWhenEndpointIsAlsoConfigured() {
+ FunctionGraphEndpoint endpoint = context.getEndpoint(
+
"hwcloud-functiongraph:invokeFunction?region=eu-west-101&endpoint=https://function.example.com"
+ +
"&projectId=proj-1&functionName=fn&functionPackage=pkg"
+ +
"&accessKey=ak&secretKey=sk&ignoreSslVerification=true",
+ FunctionGraphEndpoint.class);
+
+ ClientConfigurations clientConfigurations = new
ClientConfigurations(endpoint);
+
+ assertEquals("eu-west-101", clientConfigurations.getRegion(),
+ "region must be populated even when the client is initialized
from the endpoint");
+ // functionName/functionPackage are filled in by the producer at
invoke time; here we only assert the
+ // region segment is present (previously it was 'urn:fss:null:...'
whenever endpoint was configured)
+ String urn =
FunctionGraphUtils.composeUrn(FunctionGraphConstants.URN_FORMAT,
clientConfigurations);
+ assertTrue(urn.startsWith("urn:fss:eu-west-101:proj-1:function:"),
+ "the invoke URN must carry the region, was: " + urn);
+ }
+}
diff --git
a/components/camel-huawei/camel-huaweicloud-functiongraph/src/test/java/org/apache/camel/FunctionGraphUtilsTest.java
b/components/camel-huawei/camel-huaweicloud-functiongraph/src/test/java/org/apache/camel/FunctionGraphUtilsTest.java
new file mode 100644
index 000000000000..9245eb3b2777
--- /dev/null
+++
b/components/camel-huawei/camel-huaweicloud-functiongraph/src/test/java/org/apache/camel/FunctionGraphUtilsTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+/**
+ * Unit tests for the static {@link
FunctionGraphUtils#extractJsonFieldAsString} helper. It must not assume 'body'
is a
+ * JSON object (HTTP-triggered functions return it as a JSON-encoded
string/primitive) and must tolerate an absent/null
+ * field and a null/blank result.
+ */
+public class FunctionGraphUtilsTest {
+
+ @Test
+ public void extractObjectBodyReturnsItsJson() {
+ String result =
FunctionGraphUtils.extractJsonFieldAsString("{\"body\":{\"orderId\":1,\"ok\":true}}",
"body");
+ assertEquals("{\"orderId\":1,\"ok\":true}", result);
+ }
+
+ @Test
+ public void extractStringBodyReturnsTheRawString() {
+ // previously threw ClassCastException because getAsJsonObject was
forced on a string member
+ String result =
FunctionGraphUtils.extractJsonFieldAsString("{\"body\":\"hello world\"}",
"body");
+ assertEquals("hello world", result);
+ }
+
+ @Test
+ public void extractNumericBodyReturnsItsValue() {
+ String result =
FunctionGraphUtils.extractJsonFieldAsString("{\"body\":42}", "body");
+ assertEquals("42", result);
+ }
+
+ @Test
+ public void extractAbsentFieldReturnsNull() {
+ // previously threw NullPointerException
+
assertNull(FunctionGraphUtils.extractJsonFieldAsString("{\"statusCode\":200}",
"body"));
+ }
+
+ @Test
+ public void extractNullJsonReturnsNull() {
+ // a function that returns no result (response.getResult() == null)
hits the root == null guard
+ assertNull(FunctionGraphUtils.extractJsonFieldAsString(null, "body"));
+ }
+}