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


##########
components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/FunctionGraphUtils.java:
##########
@@ -34,7 +35,17 @@ private 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();

Review Comment:
   ⚠️ **Silent null body silently dropped into the exchange** — 
`extractJsonFieldAsString` now returns `null` when `response.getResult()` is 
`null` or has no `body` field. The caller at `FunctionGraphProducer.java:109` 
does `exchange.getMessage().setBody(responseBody)` without any null check, so a 
function that returns no body silently produces a `null` exchange body. Pre-PR 
this crashed with NPE (visible); post-PR it silently clears the body, and any 
downstream processor that expects a non-null body fails with a cryptic error 
far from this call site.
   
   At minimum, log a warning when the result is null:
   ```java
           JsonObject root = gson.fromJson(jsonString, JsonObject.class);
           if (root == null) {
               LOG.warn("extractJsonFieldAsString: input JSON is null or 
unparseable; returning null");
               return null;
           }
           JsonElement field = root.get(fieldName);
           if (field == null || field.isJsonNull()) {
               LOG.warn("extractJsonFieldAsString: field '{}' absent or null in 
response; returning null", fieldName);
               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();
   ```
   Or — better — check for null in `FunctionGraphProducer` and throw a 
meaningful exception rather than silently passing null downstream.



##########
components/camel-huawei/camel-huaweicloud-functiongraph/src/test/java/org/apache/camel/FunctionGraphUtilsTest.java:
##########
@@ -0,0 +1,78 @@
+/*
+ * 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.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class FunctionGraphUtilsTest extends CamelTestSupport {
+
+    // --- extractJsonFieldAsString: 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 ---
+
+    @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() {

Review Comment:
   **Missing test: `extractJsonFieldAsString(null, "body")` should return 
null** — the PR adds a `root == null` guard, but there's no test that exercises 
it. A function that returns no result (`response.getResult()` == null) would 
hit this path in production. Add:
   ```java
       @Test
       public void extractNullJsonReturnsNull() {
           assertNull(FunctionGraphUtils.extractJsonFieldAsString(null, 
"body"));
       }
   ```



##########
components/camel-huawei/camel-huaweicloud-functiongraph/src/test/java/org/apache/camel/FunctionGraphUtilsTest.java:
##########
@@ -0,0 +1,78 @@
+/*
+ * 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.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class FunctionGraphUtilsTest extends CamelTestSupport {
+
+    // --- extractJsonFieldAsString: must not assume 'body' is a JSON object 
(HTTP-triggered functions

Review Comment:
   **`CamelTestSupport` not needed for 4 of 5 tests** — 
`extractObjectBodyReturnsItsJson`, `extractStringBodyReturnsTheRawString`, 
`extractNumericBodyReturnsItsValue`, and `extractAbsentFieldReturnsNull` only 
call a static utility method; they don't touch the Camel context at all. 
Extending `CamelTestSupport` starts and stops a full Camel context for every 
test, adding significant overhead for nothing. Split into two classes: a plain 
JUnit 5 class (no superclass) for the static-method tests, and keep 
`CamelTestSupport` only for `urnKeepsRegionWhenEndpointIsAlsoConfigured`.



##########
components/camel-huawei/camel-huaweicloud-functiongraph/src/test/java/org/apache/camel/FunctionGraphUtilsTest.java:
##########
@@ -0,0 +1,78 @@
+/*
+ * 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.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class FunctionGraphUtilsTest extends CamelTestSupport {
+
+    // --- extractJsonFieldAsString: 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 ---
+
+    @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"));
+    }
+
+    // --- ClientConfigurations must keep the region for the invoke URN even 
when 'endpoint' is also set ---
+
+    @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);
+    }
+}

Review Comment:
   **Missing negative test: endpoint-only (no region) should fail fast** — the 
constructor refactor introduces a gap where providing `endpoint` but no 
`region` silently succeeds (no throw), yet `composeUrn` will produce 
`urn:fss:null:…`. Add a test that asserts this configuration throws 
`IllegalArgumentException`:
   ```java
       @Test
       public void endpointWithoutRegionThrows() {
           FunctionGraphEndpoint ep = context.getEndpoint(
               
"hwcloud-functiongraph:invokeFunction?endpoint=https://function.example.com";
               + "&projectId=proj-1&functionName=fn&functionPackage=pkg"
               + "&accessKey=ak&secretKey=sk&ignoreSslVerification=true",
               FunctionGraphEndpoint.class);
           assertThrows(IllegalArgumentException.class, () -> new 
ClientConfigurations(ep),
               "region is required even when endpoint is set");
       }
   ```
   (This test will currently **fail**, exposing the real remaining bug in the 
constructor logic.)



-- 
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