Skip to content

Commit bc88de4

Browse files
committed
Add tests for new features: AskUserTest, HooksTest, and auth options tests
- Add AskUserTest for user input handler functionality (disabled pending harness update) - Add HooksTest for pre/post tool-use hooks (disabled pending harness update) - Add auth options tests to CopilotClientTest: - testGithubTokenOptionAccepted - testUseLoggedInUserDefaultsToNull - testExplicitUseLoggedInUserFalse - testExplicitUseLoggedInUserTrueWithGithubToken - testGithubTokenWithCliUrlThrows - testUseLoggedInUserWithCliUrlThrows Note: AskUserTest and HooksTest are disabled because they require test harness updates with support for the new RPC methods (ask_user, hooks). These tests will be enabled once the harness is updated (see upstream PR #269).
1 parent e85055a commit bc88de4

3 files changed

Lines changed: 402 additions & 0 deletions

File tree

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
*--------------------------------------------------------------------------------------------*/
4+
5+
package com.github.copilot.sdk;
6+
7+
import static org.junit.jupiter.api.Assertions.*;
8+
9+
import java.util.ArrayList;
10+
import java.util.List;
11+
import java.util.concurrent.CompletableFuture;
12+
import java.util.concurrent.TimeUnit;
13+
14+
import org.junit.jupiter.api.AfterAll;
15+
import org.junit.jupiter.api.BeforeAll;
16+
import org.junit.jupiter.api.Disabled;
17+
import org.junit.jupiter.api.Test;
18+
19+
import com.github.copilot.sdk.json.MessageOptions;
20+
import com.github.copilot.sdk.json.SessionConfig;
21+
import com.github.copilot.sdk.json.UserInputRequest;
22+
import com.github.copilot.sdk.json.UserInputResponse;
23+
24+
/**
25+
* Tests for user input handler (ask_user) functionality.
26+
*
27+
* <p>
28+
* These tests use the shared CapiProxy infrastructure for deterministic API
29+
* response replay. Snapshots are stored in test/snapshots/ask-user/.
30+
* </p>
31+
*
32+
* <p>
33+
* <b>Note:</b> These tests require the latest test harness with ask_user
34+
* support.
35+
* </p>
36+
*/
37+
@Disabled("Requires test harness update with ask_user support - see upstream PR #269")
38+
public class AskUserTest {
39+
40+
private static E2ETestContext ctx;
41+
42+
@BeforeAll
43+
static void setup() throws Exception {
44+
ctx = E2ETestContext.create();
45+
}
46+
47+
@AfterAll
48+
static void teardown() throws Exception {
49+
if (ctx != null) {
50+
ctx.close();
51+
}
52+
}
53+
54+
@Test
55+
void testUserInputHandlerInvokedWhenModelUsesAskUserTool() throws Exception {
56+
ctx.configureForTest("ask-user", "should_invoke_user_input_handler_when_model_uses_ask_user_tool");
57+
58+
List<UserInputRequest> userInputRequests = new ArrayList<>();
59+
final String[] sessionIdHolder = new String[1];
60+
61+
SessionConfig config = new SessionConfig().setOnUserInputRequest((request, invocation) -> {
62+
userInputRequests.add(request);
63+
assertEquals(sessionIdHolder[0], invocation.getSessionId());
64+
65+
// Return the first choice if available, otherwise a freeform answer
66+
String answer = (request.getChoices() != null && !request.getChoices().isEmpty())
67+
? request.getChoices().get(0)
68+
: "freeform answer";
69+
boolean wasFreeform = request.getChoices() == null || request.getChoices().isEmpty();
70+
71+
return CompletableFuture
72+
.completedFuture(new UserInputResponse().setAnswer(answer).setWasFreeform(wasFreeform));
73+
});
74+
75+
try (CopilotClient client = ctx.createClient()) {
76+
CopilotSession session = client.createSession(config).get();
77+
sessionIdHolder[0] = session.getSessionId();
78+
79+
session.sendAndWait(new MessageOptions().setPrompt(
80+
"Ask me to choose between 'Option A' and 'Option B' using the ask_user tool. Wait for my response before continuing."))
81+
.get(60, TimeUnit.SECONDS);
82+
83+
// Should have received at least one user input request
84+
assertFalse(userInputRequests.isEmpty(), "Should have received user input requests");
85+
86+
// The request should have a question
87+
assertTrue(userInputRequests.stream().anyMatch(r -> r.getQuestion() != null && !r.getQuestion().isEmpty()),
88+
"User input request should have a question");
89+
}
90+
}
91+
92+
@Test
93+
void testUserInputRequestWithChoices() throws Exception {
94+
ctx.configureForTest("ask-user", "should_receive_choices_in_user_input_request");
95+
96+
List<UserInputRequest> userInputRequests = new ArrayList<>();
97+
98+
SessionConfig config = new SessionConfig().setOnUserInputRequest((request, invocation) -> {
99+
userInputRequests.add(request);
100+
101+
// Pick the first choice
102+
String answer = (request.getChoices() != null && !request.getChoices().isEmpty())
103+
? request.getChoices().get(0)
104+
: "default";
105+
106+
return CompletableFuture.completedFuture(new UserInputResponse().setAnswer(answer).setWasFreeform(false));
107+
});
108+
109+
try (CopilotClient client = ctx.createClient()) {
110+
CopilotSession session = client.createSession(config).get();
111+
112+
session.sendAndWait(new MessageOptions().setPrompt(
113+
"Use the ask_user tool to ask me to pick between exactly two options: 'Red' and 'Blue'. These should be provided as choices. Wait for my answer."))
114+
.get(60, TimeUnit.SECONDS);
115+
116+
// Should have received a request
117+
assertFalse(userInputRequests.isEmpty(), "Should have received user input requests");
118+
119+
// At least one request should have choices
120+
assertTrue(userInputRequests.stream().anyMatch(r -> r.getChoices() != null && !r.getChoices().isEmpty()),
121+
"At least one request should have choices");
122+
}
123+
}
124+
125+
@Test
126+
void testFreeformUserInputResponse() throws Exception {
127+
ctx.configureForTest("ask-user", "should_handle_freeform_user_input_response");
128+
129+
List<UserInputRequest> userInputRequests = new ArrayList<>();
130+
String freeformAnswer = "This is my custom freeform answer that was not in the choices";
131+
132+
SessionConfig config = new SessionConfig().setOnUserInputRequest((request, invocation) -> {
133+
userInputRequests.add(request);
134+
135+
// Return a freeform answer (not from choices)
136+
return CompletableFuture
137+
.completedFuture(new UserInputResponse().setAnswer(freeformAnswer).setWasFreeform(true));
138+
});
139+
140+
try (CopilotClient client = ctx.createClient()) {
141+
CopilotSession session = client.createSession(config).get();
142+
143+
var response = session.sendAndWait(new MessageOptions().setPrompt(
144+
"Ask me a question using ask_user and then include my answer in your response. The question should be 'What is your favorite color?'"))
145+
.get(60, TimeUnit.SECONDS);
146+
147+
// Should have received a request
148+
assertFalse(userInputRequests.isEmpty(), "Should have received user input requests");
149+
150+
// The model's response should be defined
151+
assertNotNull(response, "Response should not be null");
152+
}
153+
}
154+
}

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

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,50 @@ void testForceStopWithoutCleanup() throws Exception {
163163
assertEquals(ConnectionState.DISCONNECTED, client.getState());
164164
}
165165
}
166+
167+
@Test
168+
void testGithubTokenOptionAccepted() {
169+
CopilotClientOptions options = new CopilotClientOptions().setCliPath("/path/to/cli")
170+
.setGithubToken("gho_test_token");
171+
172+
assertEquals("gho_test_token", options.getGithubToken());
173+
}
174+
175+
@Test
176+
void testUseLoggedInUserDefaultsToNull() {
177+
CopilotClientOptions options = new CopilotClientOptions().setCliPath("/path/to/cli");
178+
179+
assertNull(options.getUseLoggedInUser());
180+
}
181+
182+
@Test
183+
void testExplicitUseLoggedInUserFalse() {
184+
CopilotClientOptions options = new CopilotClientOptions().setCliPath("/path/to/cli").setUseLoggedInUser(false);
185+
186+
assertEquals(false, options.getUseLoggedInUser());
187+
}
188+
189+
@Test
190+
void testExplicitUseLoggedInUserTrueWithGithubToken() {
191+
CopilotClientOptions options = new CopilotClientOptions().setCliPath("/path/to/cli")
192+
.setGithubToken("gho_test_token").setUseLoggedInUser(true);
193+
194+
assertEquals(true, options.getUseLoggedInUser());
195+
}
196+
197+
@Test
198+
void testGithubTokenWithCliUrlThrows() {
199+
CopilotClientOptions options = new CopilotClientOptions().setCliUrl("localhost:8080")
200+
.setGithubToken("gho_test_token").setUseStdio(false);
201+
202+
assertThrows(IllegalArgumentException.class, () -> new CopilotClient(options));
203+
}
204+
205+
@Test
206+
void testUseLoggedInUserWithCliUrlThrows() {
207+
CopilotClientOptions options = new CopilotClientOptions().setCliUrl("localhost:8080").setUseLoggedInUser(false)
208+
.setUseStdio(false);
209+
210+
assertThrows(IllegalArgumentException.class, () -> new CopilotClient(options));
211+
}
166212
}

0 commit comments

Comments
 (0)