Skip to content

Commit 4c6c2ec

Browse files
Copilotedburns
andauthored
Update Javadoc in TimeoutEdgeCaseTest and SchedulerShutdownRaceTest to use contract/regression language
Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/82d9999d-8d2f-4ccc-b0a9-0dfe932f8f78 Co-authored-by: edburns <75821+edburns@users.noreply.github.com>
1 parent 446fe74 commit 4c6c2ec

File tree

2 files changed

+21
-24
lines changed

2 files changed

+21
-24
lines changed

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,16 @@
1919
import com.github.copilot.sdk.json.MessageOptions;
2020

2121
/**
22-
* Reproduces the race between {@code sendAndWait()} and {@code close()}.
22+
* Regression coverage for the race between {@code sendAndWait()} and
23+
* {@code close()}.
2324
* <p>
2425
* If {@code close()} shuts down the timeout scheduler after
2526
* {@code ensureNotTerminated()} passes but before
2627
* {@code timeoutScheduler.schedule()} executes, the schedule call throws
27-
* {@link RejectedExecutionException}. Without a fix the exception propagates
28-
* uncaught, leaking the event subscription and leaving the returned future
29-
* incomplete.
28+
* {@link RejectedExecutionException}. This test asserts that
29+
* {@code sendAndWait()} handles this race by returning a future that completes
30+
* exceptionally (rather than propagating the exception to the caller or leaving
31+
* the returned future incomplete).
3032
*/
3133
public class SchedulerShutdownRaceTest {
3234

@@ -50,8 +52,7 @@ void sendAndWaitShouldReturnFailedFutureWhenSchedulerIsShutDown() throws Excepti
5052
var scheduler = (ScheduledExecutorService) schedulerField.get(session);
5153
scheduler.shutdownNow();
5254

53-
// With the fix: sendAndWait returns a future that completes exceptionally.
54-
// Without the fix: sendAndWait throws RejectedExecutionException directly.
55+
// sendAndWait must return a failed future rather than throwing directly.
5556
CompletableFuture<?> result = session.sendAndWait(new MessageOptions().setPrompt("test"), 5000);
5657

5758
assertNotNull(result, "sendAndWait should return a future, not throw");

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

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,16 @@
1919
import com.github.copilot.sdk.json.MessageOptions;
2020

2121
/**
22-
* Tests for timeout edge cases in {@link CopilotSession#sendAndWait}.
22+
* Regression tests for timeout edge cases in
23+
* {@link CopilotSession#sendAndWait}.
2324
* <p>
24-
* These tests prove two defects in the current per-call
25+
* These tests assert two behavioral contracts of the shared
2526
* {@code ScheduledExecutorService} approach:
2627
* <ol>
27-
* <li>A timeout fires after {@code close()}, leaking a {@code TimeoutException}
28-
* onto the returned future.</li>
29-
* <li>Each {@code sendAndWait} call spawns a new OS thread (~1 MB stack),
30-
* instead of reusing a shared scheduler thread.</li>
28+
* <li>A pending timeout must NOT fire after {@code close()} and must NOT
29+
* complete the returned future with a {@code TimeoutException}.</li>
30+
* <li>Multiple {@code sendAndWait} calls must reuse a single shared scheduler
31+
* thread rather than spawning a new OS thread per call.</li>
3132
* </ol>
3233
*/
3334
public class TimeoutEdgeCaseTest {
@@ -62,13 +63,10 @@ public int read() throws IOException {
6263
* After {@code close()}, the future returned by {@code sendAndWait} must NOT be
6364
* completed by a stale timeout.
6465
* <p>
65-
* Current buggy behavior: the per-call scheduler is not cancelled by
66-
* {@code close()}, so its 2-second timeout fires during the 5-second
67-
* {@code session.destroy} RPC wait, completing the future with
68-
* {@code TimeoutException}.
69-
* <p>
70-
* Expected behavior after fix: {@code close()} cancels pending timeouts before
71-
* the blocking RPC call, so the future remains incomplete.
66+
* Contract: {@code close()} shuts down the timeout scheduler before the
67+
* blocking {@code session.destroy} RPC call, so any pending timeout task is
68+
* cancelled and the future remains incomplete (not exceptionally completed with
69+
* {@code TimeoutException}).
7270
*/
7371
@Test
7472
void testTimeoutDoesNotFireAfterSessionClose() throws Exception {
@@ -94,13 +92,11 @@ void testTimeoutDoesNotFireAfterSessionClose() throws Exception {
9492
}
9593

9694
/**
97-
* A shared scheduler should reuse a single thread across multiple
95+
* A shared scheduler must reuse a single thread across multiple
9896
* {@code sendAndWait} calls, rather than spawning a new OS thread per call.
9997
* <p>
100-
* Current buggy behavior: two calls create two {@code sendAndWait-timeout}
101-
* threads.
102-
* <p>
103-
* Expected behavior after fix: two calls still use only one scheduler thread.
98+
* Contract: after two consecutive {@code sendAndWait} calls the number of live
99+
* {@code sendAndWait-timeout} threads must not increase after the second call.
104100
*/
105101
@Test
106102
void testSendAndWaitReusesTimeoutThread() throws Exception {

0 commit comments

Comments
 (0)