Skip to content

Commit c92c728

Browse files
markpollackclaude
andcommitted
feat: Phase 3b progress - 3 new integration tests completed
Added integration tests for: - agentic-patterns/orchestrator-workers (complex task breakdown pattern) - agentic-patterns/routing-workflow (support ticket routing pattern) - model-context-protocol/client-starter/starter-default-client (MCP tools query) All tests validated locally and passing: - orchestrator-workers: Shows task analysis and worker responses - routing-workflow: Demonstrates routing analysis for 3 ticket types - starter-default-client: Successfully queries Brave Search tools via MCP Phase 3b status: 3/21 remaining examples converted (14% complete) Total integration framework status: 15/33 examples (45% complete) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 892f324 commit c92c728

File tree

9 files changed

+620
-16
lines changed

9 files changed

+620
-16
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"timeoutSec": 300,
3+
"successRegex": [
4+
"=== ORCHESTRATOR OUTPUT ===",
5+
"ANALYSIS:",
6+
"TASKS:",
7+
"=== WORKER OUTPUT ==="
8+
],
9+
"requiredEnv": [
10+
"OPENAI_API_KEY"
11+
]
12+
}
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
///usr/bin/env jbang "$0" "$@" ; exit $?
2+
//DEPS org.zeroturnaround:zt-exec:1.12
3+
//DEPS com.fasterxml.jackson.core:jackson-databind:2.17.1
4+
//JAVA 17
5+
//FILES ExampleInfo.json
6+
7+
/*
8+
* Integration test launcher for orchestrator-workers
9+
* Generated by scaffold_integration_test.py on 2025-08-01 11:43:32
10+
*/
11+
12+
import com.fasterxml.jackson.databind.*;
13+
import org.zeroturnaround.exec.*;
14+
import java.nio.file.*;
15+
import java.util.concurrent.TimeUnit;
16+
import static java.lang.System.*;
17+
18+
record ExampleInfo(
19+
int timeoutSec,
20+
String[] successRegex,
21+
String[] requiredEnv,
22+
String[] setupCommands,
23+
String[] cleanupCommands
24+
) {}
25+
26+
public class RunOrchestratorWorkers {
27+
28+
public static void main(String... args) throws Exception {
29+
Path configPath = Path.of("integration-tests/ExampleInfo.json");
30+
ExampleInfo cfg = new ObjectMapper().readValue(configPath.toFile(), ExampleInfo.class);
31+
32+
// Verify required environment variables
33+
for (String envVar : cfg.requiredEnv()) {
34+
if (getenv(envVar) == null) {
35+
err.println("❌ Missing required environment variable: " + envVar);
36+
exit(1);
37+
}
38+
}
39+
40+
try {
41+
42+
// Build and run the main application
43+
out.println("🏗️ Building orchestrator-workers...");
44+
runCommand(new String[]{"./mvnw", "clean", "package", "-q", "-DskipTests"}, 300);
45+
46+
// Run setup commands AFTER build to avoid clean removing test files
47+
if (cfg.setupCommands() != null) {
48+
for (String setupCmd : cfg.setupCommands()) {
49+
out.println("🔧 Running setup: " + setupCmd);
50+
runCommand(setupCmd.split("\\s+"), 60); // 1 minute timeout for setup
51+
}
52+
}
53+
54+
out.println("🚀 Running orchestrator-workers...");
55+
// Create persistent log file for debugging
56+
Path logDir = Paths.get("../../integration-testing/logs/integration-tests");
57+
Files.createDirectories(logDir);
58+
Path logFile = logDir.resolve("orchestrator-workers-spring-boot-" + System.currentTimeMillis() + ".log");
59+
60+
ProcessResult result = new ProcessExecutor()
61+
.command("./mvnw", "spring-boot:run", "-q")
62+
.timeout(cfg.timeoutSec(), TimeUnit.SECONDS)
63+
.redirectOutput(Files.newOutputStream(logFile))
64+
.redirectErrorStream(true)
65+
.execute();
66+
67+
int exitCode = result.getExitValue();
68+
69+
// Verify output patterns
70+
String output = Files.readString(logFile);
71+
out.println("✅ Verifying output patterns...");
72+
73+
int failedPatterns = 0;
74+
for (String pattern : cfg.successRegex()) {
75+
if (output.matches("(?s).*" + pattern + ".*")) {
76+
out.println(" ✓ Found: " + pattern);
77+
} else {
78+
err.println(" ❌ Missing: " + pattern);
79+
failedPatterns++;
80+
}
81+
}
82+
83+
// Display captured application output for debugging
84+
out.println("\n📋 Captured Application Output:");
85+
out.println("=== ORCHESTRATOR OUTPUT ===");
86+
87+
// Extract orchestrator analysis section
88+
String[] lines = output.split("\n");
89+
boolean inOrchestratorOutput = false;
90+
boolean inWorkerOutput = false;
91+
92+
for (String line : lines) {
93+
if (line.contains("=== ORCHESTRATOR OUTPUT ===")) {
94+
inOrchestratorOutput = true;
95+
inWorkerOutput = false;
96+
continue;
97+
} else if (line.contains("=== WORKER OUTPUT ===")) {
98+
inOrchestratorOutput = false;
99+
inWorkerOutput = true;
100+
out.println("\n=== WORKER OUTPUT ===");
101+
continue;
102+
}
103+
104+
if (inOrchestratorOutput || inWorkerOutput) {
105+
out.println(line);
106+
}
107+
}
108+
109+
// Keep log file for debugging - DO NOT DELETE
110+
out.println("\n📁 Spring Boot log preserved: " + logFile.toAbsolutePath());
111+
112+
if (exitCode != 0) {
113+
err.println("❌ Application exited with code: " + exitCode);
114+
exit(exitCode);
115+
}
116+
117+
if (failedPatterns > 0) {
118+
err.println("❌ Failed pattern verification: " + failedPatterns + " patterns missing");
119+
exit(1);
120+
}
121+
122+
out.println("🎉 Integration test completed successfully!");
123+
124+
} finally {
125+
// Run cleanup commands if specified
126+
if (cfg.cleanupCommands() != null) {
127+
for (String cleanupCmd : cfg.cleanupCommands()) {
128+
out.println("🧹 Running cleanup: " + cleanupCmd);
129+
try {
130+
runCommand(cleanupCmd.split("\\s+"), 30);
131+
} catch (Exception e) {
132+
err.println("⚠️ Cleanup command failed (non-fatal): " + e.getMessage());
133+
}
134+
}
135+
}
136+
}
137+
}
138+
139+
private static void runCommand(String[] cmd, int timeoutSec) throws Exception {
140+
ProcessResult result = new ProcessExecutor()
141+
.command(cmd)
142+
.timeout(timeoutSec, TimeUnit.SECONDS)
143+
.redirectOutput(System.out)
144+
.redirectError(System.err)
145+
.execute();
146+
147+
int exit = result.getExitValue();
148+
if (exit != 0) {
149+
throw new RuntimeException("Command failed with exit code " + exit + ": " + String.join(" ", cmd));
150+
}
151+
}
152+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"timeoutSec": 300,
3+
"successRegex": [
4+
"Ticket 1",
5+
"Ticket 2",
6+
"Ticket 3",
7+
"Available routes:",
8+
"Routing Analysis:",
9+
"Selected route:",
10+
"Support Response:"
11+
],
12+
"requiredEnv": [
13+
"OPENAI_API_KEY"
14+
]
15+
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
///usr/bin/env jbang "$0" "$@" ; exit $?
2+
//DEPS org.zeroturnaround:zt-exec:1.12
3+
//DEPS com.fasterxml.jackson.core:jackson-databind:2.17.1
4+
//JAVA 17
5+
//FILES ExampleInfo.json
6+
7+
/*
8+
* Integration test launcher for routing-workflow
9+
* Generated by scaffold_integration_test.py on 2025-08-01 11:48:19
10+
*/
11+
12+
import com.fasterxml.jackson.databind.*;
13+
import org.zeroturnaround.exec.*;
14+
import java.nio.file.*;
15+
import java.util.concurrent.TimeUnit;
16+
import static java.lang.System.*;
17+
18+
record ExampleInfo(
19+
int timeoutSec,
20+
String[] successRegex,
21+
String[] requiredEnv,
22+
String[] setupCommands,
23+
String[] cleanupCommands
24+
) {}
25+
26+
public class RunRoutingWorkflow {
27+
28+
public static void main(String... args) throws Exception {
29+
Path configPath = Path.of("integration-tests/ExampleInfo.json");
30+
ExampleInfo cfg = new ObjectMapper().readValue(configPath.toFile(), ExampleInfo.class);
31+
32+
// Verify required environment variables
33+
for (String envVar : cfg.requiredEnv()) {
34+
if (getenv(envVar) == null) {
35+
err.println("❌ Missing required environment variable: " + envVar);
36+
exit(1);
37+
}
38+
}
39+
40+
try {
41+
42+
// Build and run the main application
43+
out.println("🏗️ Building routing-workflow...");
44+
runCommand(new String[]{"./mvnw", "clean", "package", "-q", "-DskipTests"}, 300);
45+
46+
// Run setup commands AFTER build to avoid clean removing test files
47+
if (cfg.setupCommands() != null) {
48+
for (String setupCmd : cfg.setupCommands()) {
49+
out.println("🔧 Running setup: " + setupCmd);
50+
runCommand(setupCmd.split("\\s+"), 60); // 1 minute timeout for setup
51+
}
52+
}
53+
54+
out.println("🚀 Running routing-workflow...");
55+
// Create persistent log file for debugging
56+
Path logDir = Paths.get("../../integration-testing/logs/integration-tests");
57+
Files.createDirectories(logDir);
58+
Path logFile = logDir.resolve("routing-workflow-spring-boot-" + System.currentTimeMillis() + ".log");
59+
60+
ProcessResult result = new ProcessExecutor()
61+
.command("./mvnw", "spring-boot:run", "-q")
62+
.timeout(cfg.timeoutSec(), TimeUnit.SECONDS)
63+
.redirectOutput(Files.newOutputStream(logFile))
64+
.redirectErrorStream(true)
65+
.execute();
66+
67+
int exitCode = result.getExitValue();
68+
69+
// Verify output patterns
70+
String output = Files.readString(logFile);
71+
out.println("✅ Verifying output patterns...");
72+
73+
int failedPatterns = 0;
74+
for (String pattern : cfg.successRegex()) {
75+
if (output.matches("(?s).*" + pattern + ".*")) {
76+
out.println(" ✓ Found: " + pattern);
77+
} else {
78+
err.println(" ❌ Missing: " + pattern);
79+
failedPatterns++;
80+
}
81+
}
82+
83+
// Display captured application output for debugging
84+
out.println("\n📋 Captured Application Output:");
85+
out.println("=== ROUTING WORKFLOW OUTPUT ===");
86+
87+
// Extract and display ticket processing sections
88+
String[] lines = output.split("\n");
89+
boolean inTicketSection = false;
90+
91+
for (String line : lines) {
92+
if (line.startsWith("Ticket ")) {
93+
inTicketSection = true;
94+
out.println("\n" + line);
95+
} else if (line.contains("Available routes:")) {
96+
out.println(line);
97+
} else if (line.contains("Routing Analysis:")) {
98+
out.println(line);
99+
} else if (line.contains("Selected route:")) {
100+
out.println(line);
101+
} else if (line.contains("Support Response:")) {
102+
out.println(line);
103+
} else if (inTicketSection && line.trim().isEmpty()) {
104+
inTicketSection = false;
105+
} else if (inTicketSection || line.contains("Subject:") || line.contains("Message:")) {
106+
out.println(line);
107+
}
108+
}
109+
110+
// Keep log file for debugging - DO NOT DELETE
111+
out.println("\n📁 Spring Boot log preserved: " + logFile.toAbsolutePath());
112+
113+
if (exitCode != 0) {
114+
err.println("❌ Application exited with code: " + exitCode);
115+
exit(exitCode);
116+
}
117+
118+
if (failedPatterns > 0) {
119+
err.println("❌ Failed pattern verification: " + failedPatterns + " patterns missing");
120+
exit(1);
121+
}
122+
123+
out.println("🎉 Integration test completed successfully!");
124+
125+
} finally {
126+
// Run cleanup commands if specified
127+
if (cfg.cleanupCommands() != null) {
128+
for (String cleanupCmd : cfg.cleanupCommands()) {
129+
out.println("🧹 Running cleanup: " + cleanupCmd);
130+
try {
131+
runCommand(cleanupCmd.split("\\s+"), 30);
132+
} catch (Exception e) {
133+
err.println("⚠️ Cleanup command failed (non-fatal): " + e.getMessage());
134+
}
135+
}
136+
}
137+
}
138+
}
139+
140+
private static void runCommand(String[] cmd, int timeoutSec) throws Exception {
141+
ProcessResult result = new ProcessExecutor()
142+
.command(cmd)
143+
.timeout(timeoutSec, TimeUnit.SECONDS)
144+
.redirectOutput(System.out)
145+
.redirectError(System.err)
146+
.execute();
147+
148+
int exit = result.getExitValue();
149+
if (exit != 0) {
150+
throw new RuntimeException("Command failed with exit code " + exit + ": " + String.join(" ", cmd));
151+
}
152+
}
153+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"timeoutSec": 300,
3+
"successRegex": [
4+
">>> QUESTION: What tools are available\\?",
5+
">>> ASSISTANT:",
6+
"Brave.*Search"
7+
],
8+
"requiredEnv": [
9+
"OPENAI_API_KEY"
10+
]
11+
}

0 commit comments

Comments
 (0)