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-performance-tests.git

commit 81b7209bd78302eaf909fb2de2e1054855d2fe82
Author: Claus Ibsen <[email protected]>
AuthorDate: Sun Oct 18 15:22:38 2026 +0200

    ai-benchmark: contracts/rest-code-first in the new set, and probe regexes 
match the whole body
    
    rest-code-first: GET /orders/{id} with a 404, POST /orders bound to a Java 
record (restart to compile it) with a
    400, and the generated API description at /openapi (restart, as 
camel-openapi-java comes from
    camel.jbang.dependencies). Checked with HTTP probes. The final reference is 
the example's route file
    (apache/camel-jbang-examples#118). Reference pass 3/3 twice.
    
    A probe kept the first 600 characters of the answer and matched its regex 
on them; the /orders/{id} path of the
    generated API description comes later. The regex is now matched on the 
whole body; the result still keeps the start.
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
    Claude-Session: https://claude.ai/code/session_01STT6whBgK1AqsSsUKrnE8m
---
 ai-benchmark/agent_mcp_stepwise.py                 | 14 ++++---
 ai-benchmark/gen_stepwise.py                       | 45 ++++++++++++++++++++++
 .../seed/contracts-rest-code-first/orders.json     |  5 +++
 3 files changed, 59 insertions(+), 5 deletions(-)

diff --git a/ai-benchmark/agent_mcp_stepwise.py 
b/ai-benchmark/agent_mcp_stepwise.py
index c4858f0..c4875e1 100755
--- a/ai-benchmark/agent_mcp_stepwise.py
+++ b/ai-benchmark/agent_mcp_stepwise.py
@@ -305,22 +305,26 @@ def probe(pr):
     server may still be settling after the reload, so the request is retried a 
few times until the expected status."""
     method = pr.get("method", "GET"); url = pr["url"]; want = 
int(pr.get("expect_status", 200))
     out = {"url": url, "method": method, "ok": False, "status": None, "body": 
""}
+    full = ""
     for _ in range(6):
         try:
             data = pr["body"].encode() if pr.get("body") is not None else None
             req = urllib.request.Request(url, data=data, method=method, 
headers=pr.get("headers") or {})
             with urllib.request.urlopen(req, timeout=8) as r:
-                out["status"], out["body"] = r.status, 
r.read().decode(errors="replace")[:600]
+                out["status"], full = r.status, 
r.read().decode(errors="replace")
         except urllib.error.HTTPError as e:
-            out["status"], out["body"] = e.code, 
e.read().decode(errors="replace")[:600]
+            out["status"], full = e.code, e.read().decode(errors="replace")
         except Exception as e:
-            out["status"], out["body"] = None, str(e)[:200]
+            out["status"], full = None, str(e)[:200]
+        # the result keeps the start of the body; the regex is matched on all 
of it (the /orders/{id} path of a
+        # generated API description comes after the first 600 characters, 
rcref Oct 18)
+        out["body"] = full[:600]
         # the status alone is not enough: right after a reload the previous 
route may still answer 200 with its own
         # body, and that is not the answer the step asks for -- retry until 
the body matches too
-        if out["status"] == want and body_matches(pr.get("body_regex"), 
out["body"]):
+        if out["status"] == want and body_matches(pr.get("body_regex"), full):
             break
         time.sleep(2)
-    out["ok"] = out["status"] == want and body_matches(pr.get("body_regex"), 
out["body"])
+    out["ok"] = out["status"] == want and body_matches(pr.get("body_regex"), 
full)
     return out
 
 
diff --git a/ai-benchmark/gen_stepwise.py b/ai-benchmark/gen_stepwise.py
index 7b29409..93f3cd6 100644
--- a/ai-benchmark/gen_stepwise.py
+++ b/ai-benchmark/gen_stepwise.py
@@ -998,6 +998,51 @@ EXAMPLES.append({
     ]})
 
 
+# ---------------------------------------------------------------- 
contracts/rest-code-first (REST DSL code first, json binding, probes)
+# The answers are Java objects written by the json binding; error answers are 
JSON text (skipBindingOnErrorCode). Step 2
+# adds a Java record (a restart compiles it); step 3 needs camel-openapi-java, 
which camel run does not add by itself
+# for a code-first apiContextPath (the dependency applies on the restart).
+RC = "rest-code-first.camel.yaml"
+RC_LIST = '- route:\n    id: list-orders\n    from:\n      uri: direct\n      
parameters:\n        name: list-orders\n      steps:\n        - setBody:\n      
      expression:\n              constant:\n                expression: 
"resource:file:orders.json"\n        - unmarshal:\n            json:\n          
    library: Jackson\n'
+RC_GET = '- route:\n    id: get-order\n    from:\n      uri: direct\n      
parameters:\n        name: get-order\n      steps:\n        - setBody:\n        
    expression:\n              constant:\n                expression: 
"resource:file:orders.json"\n        - unmarshal:\n            json:\n          
    library: Jackson\n        - setBody:\n            expression:\n             
 groovy:\n                expression: "body.find { it.orderId == headers.id 
}"\n        - filter:\n         [...]
+RC_CREATE = '- route:\n    id: create-order\n    from:\n      uri: direct\n    
  parameters:\n        name: create-order\n      steps:\n        - choice:\n    
        when:\n              - expression:\n                  simple:\n         
           expression: "${body.lines} == null || ${body.lines.isEmpty()}"\n     
           steps:\n                  - setHeader:\n                      name: 
CamelHttpResponseCode\n                      expression:\n                      
  constant:\n  [...]
+RC_ORDER_JAVA = '/*\n * Licensed to the Apache Software Foundation (ASF) under 
one or more\n * contributor license agreements.  See the NOTICE file 
distributed with\n * this work for additional information regarding copyright 
ownership.\n * The ASF licenses this file to You under the Apache License, 
Version 2.0\n * (the "License"); you may not use this file except in compliance 
with\n * the License.  You may obtain a copy of the License at\n *\n *      
http://www.apache.org/licenses/LICE [...]
+def rc_conf(api):
+    return "- restConfiguration:\n    bindingMode: json\n" + ("    
apiContextPath: openapi\n" if api else "")
+def rc_rest(get_id, post):
+    s = ("- rest:\n    path: /orders\n    get:\n      - id: listOrders\n       
 description: All orders\n"
+         "        to:\n          uri: direct:list-orders\n")
+    if get_id:
+        s += ("      - id: getOrder\n        path: \"/{id}\"\n        
description: One order, by its id\n"
+              "        to:\n          uri: direct:get-order\n")
+    if post:
+        s += ("    post:\n      - id: createOrder\n        description: 
Creates an order\n        type: camel.example.Order\n"
+              "        to:\n          uri: direct:create-order\n")
+    return s
+def rc_state(get_id, post, api):
+    parts = [rc_conf(api), rc_rest(get_id, post), RC_LIST] + ([RC_GET] if 
get_id else []) + ([RC_CREATE] if post else [])
+    return "\n".join(parts)
+RC_NEW = ('{"orderId": "ORD-1004", "customer": "C-482", "country": "DK", 
"status": "paid", '
+          '"lines": [{"sku": "CAMEL-MUG", "qty": 1, "price": 9.5}]}')
+RC_EMPTY = '{"orderId": "ORD-1005", "customer": "C-482", "country": "DK", 
"status": "paid", "lines": []}'
+EXAMPLES.append({
+    "name": "contracts-rest-code-first", "route_file": RC, "props_file": 
"application.properties", "wait_seconds": 8,
+    "seed": "contracts-rest-code-first", "steps_dir": NEW,
+    "initial": {RC: rc_state(False, False, False), "application.properties": 
PORT_PROPS},
+    "steps": [
+        {"request": "Add GET /orders/{id} to the REST API: answer the order 
with that id from orders.json, or 404 with {\"error\": \"unknown order 
<id>\"}.",
+         "check": {"file_regex": "\\{id\\}", "probes": 
[GET("/orders/ORD-1002", 200, "\"customer\":\"C-207\""), 
GET("/orders/ORD-9999", 404, "unknown order ORD-9999")]},
+         "reference": {RC: rc_state(True, False, False)}},
+        {"request": "Add POST /orders that binds the JSON of a new order with 
the json binding to a Java record camel.example.Order (orderId, customer, 
country, status and lines; each line has sku, qty and price). Answer 400 with 
{\"error\": \"an order needs at least one line\"} when the order has no lines; 
otherwise log \"Order ${body.orderId} created with ${body.lines.size()} 
line(s)\" and answer 201 with the order. A new Java class needs a restart of 
the integration to be compiled; it [...]
+         "check": {"files": {"Order.java": "record Order"}, "probes": 
[POST("/orders", RC_NEW, 201, "\"orderId\":\"ORD-1004\""), POST("/orders", 
RC_EMPTY, 400, "at least one line")],
+                   "log_regex": "Order ORD-1004 created with 1 line\\(s\\)"},
+         "reference": {RC: rc_state(True, True, False), "Order.java": 
RC_ORDER_JAVA}, "restart": True},
+        {"request": "Serve the API description that Camel generates from the 
REST operations at /openapi. The integration is restarted after your change.",
+         "check": {"probes": [GET("/openapi", 200, "\"/orders/\\{id\\}\"")]},
+         "reference": {RC: rc_state(True, True, True), 
"application.properties": PORT_PROPS + 
"camel.jbang.dependencies=camel:openapi-java\n"}, "restart": True},
+    ]})
+
+
 def write_project(ex):
     d = os.path.join(PROJECTS, ex["name"])
     shutil.rmtree(d, ignore_errors=True)
diff --git a/ai-benchmark/seed/contracts-rest-code-first/orders.json 
b/ai-benchmark/seed/contracts-rest-code-first/orders.json
new file mode 100644
index 0000000..ceea517
--- /dev/null
+++ b/ai-benchmark/seed/contracts-rest-code-first/orders.json
@@ -0,0 +1,5 @@
+[
+  {"orderId": "ORD-1001", "customer": "C-482", "country": "DK", "status": 
"paid", "lines": [{"sku": "CAMEL-TSHIRT", "qty": 2, "price": 19.95}, {"sku": 
"CAMEL-MUG", "qty": 1, "price": 9.5}]},
+  {"orderId": "ORD-1002", "customer": "C-207", "country": "DE", "status": 
"paid", "lines": [{"sku": "CAMEL-MUG", "qty": 3, "price": 9.5}]},
+  {"orderId": "ORD-1003", "customer": "C-134", "country": "US", "status": 
"pending", "lines": [{"sku": "CAMEL-TSHIRT", "qty": 1, "price": 19.95}, {"sku": 
"CAMEL-CAP", "qty": 1, "price": 14.0}, {"sku": "CAMEL-MUG", "qty": 2, "price": 
9.5}]}
+]

Reply via email to