/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. *--------------------------------------------------------------------------------------------*/ package com.github.copilot.sdk; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import com.github.copilot.sdk.json.CopilotClientOptions; /** * E2E test context that manages the test environment including the CapiProxy, * working directories, and CLI path. * *
* This provides a complete test environment similar to the Node.js, .NET, Go, * and Python SDK test harnesses. It manages: *
** Usage example: *
* *
* {@code
* try (E2ETestContext ctx = E2ETestContext.create()) {
* ctx.configureForTest("tools", "my_test_name");
*
* try (CopilotClient client = ctx.createClient()) {
* CopilotSession session = client.createSession().get();
* // ... run test ...
* }
* }
* }
*
*/
public class E2ETestContext implements AutoCloseable {
private static final Pattern SNAKE_CASE = Pattern.compile("[^a-zA-Z0-9]");
private final String cliPath;
private final Path homeDir;
private final Path workDir;
private final String proxyUrl;
private final CapiProxy proxy;
private final Path repoRoot;
private E2ETestContext(String cliPath, Path homeDir, Path workDir, String proxyUrl, CapiProxy proxy,
Path repoRoot) {
this.cliPath = cliPath;
this.homeDir = homeDir;
this.workDir = workDir;
this.proxyUrl = proxyUrl;
this.proxy = proxy;
this.repoRoot = repoRoot;
}
/**
* Creates a new E2E test context.
*
* @return the test context
* @throws IOException
* if setup fails
* @throws InterruptedException
* if setup is interrupted
*/
public static E2ETestContext create() throws IOException, InterruptedException {
Path repoRoot = findRepoRoot();
String cliPath = getCliPath(repoRoot);
Path tempDir = Paths.get(System.getProperty("java.io.tmpdir"));
Path homeDir = Files.createTempDirectory(tempDir, "copilot-test-config-");
Path workDir = Files.createTempDirectory(tempDir, "copilot-test-work-");
CapiProxy proxy = new CapiProxy();
String proxyUrl = proxy.start();
return new E2ETestContext(cliPath, homeDir, workDir, proxyUrl, proxy, repoRoot);
}
/**
* Gets the Copilot CLI path.
*/
public String getCliPath() {
return cliPath;
}
/**
* Gets the temporary home directory for test isolation.
*/
public Path getHomeDir() {
return homeDir;
}
/**
* Gets the temporary working directory for tests.
*/
public Path getWorkDir() {
return workDir;
}
/**
* Gets the proxy URL.
*/
public String getProxyUrl() {
return proxyUrl;
}
/**
* Configures the proxy for a specific test.
*
* @param testFile
* the test category folder (e.g., "tools", "session", "permissions")
* @param testName
* the test method name (will be converted to snake_case)
* @throws IOException
* if configuration fails
* @throws InterruptedException
* if configuration is interrupted
*/
public void configureForTest(String testFile, String testName) throws IOException, InterruptedException {
// Convert test method names to lowercase snake_case for snapshot filenames
// to avoid case collisions on case-insensitive filesystems (macOS/Windows)
String sanitizedName = SNAKE_CASE.matcher(testName).replaceAll("_").toLowerCase();
String snapshotPath = repoRoot.resolve("test").resolve("snapshots").resolve(testFile)
.resolve(sanitizedName + ".yaml").toString();
proxy.configure(snapshotPath, workDir.toString());
}
/**
* Gets the captured HTTP exchanges from the proxy.
*
* @return list of exchange maps
* @throws IOException
* if the request fails
* @throws InterruptedException
* if the request is interrupted
*/
public List