Skip to content

Commit f27eb12

Browse files
committed
Enhance E2E test context with snapshot validation and logging for expected prompts
1 parent 31963a9 commit f27eb12

1 file changed

Lines changed: 72 additions & 3 deletions

File tree

src/test/java/com/github/copilot/sdk/E2ETestContext.java

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@
1010
import java.nio.file.Files;
1111
import java.nio.file.Path;
1212
import java.nio.file.Paths;
13+
import java.util.ArrayList;
1314
import java.util.HashMap;
1415
import java.util.List;
1516
import java.util.Map;
17+
import java.util.logging.Logger;
18+
import java.util.regex.Matcher;
1619
import java.util.regex.Pattern;
1720

1821
import com.github.copilot.sdk.json.CopilotClientOptions;
@@ -50,14 +53,18 @@
5053
*/
5154
public class E2ETestContext implements AutoCloseable {
5255

56+
private static final Logger LOG = Logger.getLogger(E2ETestContext.class.getName());
5357
private static final Pattern SNAKE_CASE = Pattern.compile("[^a-zA-Z0-9]");
58+
private static final Pattern USER_CONTENT_PATTERN = Pattern
59+
.compile("^\\s+-\\s+role:\\s+user\\s*$\\s+content:\\s*(.+?)$", Pattern.MULTILINE);
5460

5561
private final String cliPath;
5662
private final Path homeDir;
5763
private final Path workDir;
5864
private String proxyUrl;
5965
private final CapiProxy proxy;
6066
private final Path repoRoot;
67+
private Path currentSnapshotFile;
6168

6269
private E2ETestContext(String cliPath, Path homeDir, Path workDir, String proxyUrl, CapiProxy proxy,
6370
Path repoRoot) {
@@ -139,9 +146,71 @@ public void configureForTest(String testFile, String testName) throws IOExceptio
139146
// Convert test method names to lowercase snake_case for snapshot filenames
140147
// to avoid case collisions on case-insensitive filesystems (macOS/Windows)
141148
String sanitizedName = SNAKE_CASE.matcher(testName).replaceAll("_").toLowerCase();
142-
String snapshotPath = repoRoot.resolve("test").resolve("snapshots").resolve(testFile)
143-
.resolve(sanitizedName + ".yaml").toString();
144-
proxy.configure(snapshotPath, workDir.toString());
149+
Path snapshotFile = repoRoot.resolve("test").resolve("snapshots").resolve(testFile)
150+
.resolve(sanitizedName + ".yaml");
151+
152+
// Validate snapshot exists - fail fast with a clear message
153+
if (!Files.exists(snapshotFile)) {
154+
Path snapshotsDir = repoRoot.resolve("test").resolve("snapshots").resolve(testFile);
155+
String availableSnapshots = "";
156+
if (Files.exists(snapshotsDir)) {
157+
try (var files = Files.list(snapshotsDir)) {
158+
availableSnapshots = files.filter(p -> p.toString().endsWith(".yaml"))
159+
.map(p -> p.getFileName().toString().replace(".yaml", "")).sorted()
160+
.reduce((a, b) -> a + ", " + b).orElse("<none>");
161+
}
162+
}
163+
throw new IOException(String.format(
164+
"Snapshot file not found: %s%n" + "Category: %s, Test: %s (sanitized: %s)%n"
165+
+ "Available snapshots in '%s/': %s%n"
166+
+ "Ensure the snapshot exists and the test name matches exactly.",
167+
snapshotFile, testFile, testName, sanitizedName, testFile, availableSnapshots));
168+
}
169+
170+
this.currentSnapshotFile = snapshotFile;
171+
proxy.configure(snapshotFile.toString(), workDir.toString());
172+
173+
// Log expected prompts to help debug prompt mismatch issues
174+
List<String> expectedPrompts = getExpectedUserPrompts();
175+
if (!expectedPrompts.isEmpty()) {
176+
LOG.info(() -> String.format("Configured snapshot '%s/%s' expects prompts: %s", testFile, sanitizedName,
177+
expectedPrompts));
178+
}
179+
}
180+
181+
/**
182+
* Gets the expected user prompts from the current snapshot file.
183+
* <p>
184+
* This is useful for debugging when tests fail with "No cached response found"
185+
* errors from CapiProxy. The prompts in your test must match these exactly.
186+
* </p>
187+
*
188+
* @return list of expected user prompt strings, or empty list if none found
189+
*/
190+
public List<String> getExpectedUserPrompts() {
191+
if (currentSnapshotFile == null || !Files.exists(currentSnapshotFile)) {
192+
return List.of();
193+
}
194+
try {
195+
String content = Files.readString(currentSnapshotFile);
196+
List<String> prompts = new ArrayList<>();
197+
Matcher matcher = USER_CONTENT_PATTERN.matcher(content);
198+
while (matcher.find()) {
199+
String prompt = matcher.group(1).trim();
200+
// Remove quotes if present
201+
if ((prompt.startsWith("\"") && prompt.endsWith("\""))
202+
|| (prompt.startsWith("'") && prompt.endsWith("'"))) {
203+
prompt = prompt.substring(1, prompt.length() - 1);
204+
}
205+
if (!prompts.contains(prompt)) {
206+
prompts.add(prompt);
207+
}
208+
}
209+
return prompts;
210+
} catch (IOException e) {
211+
LOG.warning("Failed to read snapshot file: " + e.getMessage());
212+
return List.of();
213+
}
145214
}
146215

147216
/**

0 commit comments

Comments
 (0)