|
|
@@ -1,6 +1,16 @@
|
|
|
-import { beforeEach, describe, expect, mock, test } from 'bun:test';
|
|
|
+import { afterEach, beforeEach, describe, expect, mock, test } from 'bun:test';
|
|
|
import { MultiplexerSessionManager } from './session-manager';
|
|
|
|
|
|
+const originalFetch = globalThis.fetch;
|
|
|
+let mockSessionStatuses: Record<string, { type: string }> = {};
|
|
|
+const mockFetch = mock(
|
|
|
+ async () =>
|
|
|
+ new Response(JSON.stringify(mockSessionStatuses), {
|
|
|
+ headers: { 'content-type': 'application/json' },
|
|
|
+ status: 200,
|
|
|
+ }),
|
|
|
+);
|
|
|
+
|
|
|
// Define the mock multiplexer
|
|
|
const mockMultiplexer = {
|
|
|
type: 'tmux' as const,
|
|
|
@@ -25,6 +35,7 @@ mock.module('../multiplexer', () => ({
|
|
|
function createMockContext(overrides?: {
|
|
|
sessionStatusResult?: { data?: Record<string, { type: string }> };
|
|
|
directory?: string;
|
|
|
+ serverUrl?: string;
|
|
|
}) {
|
|
|
const defaultPort = process.env.OPENCODE_PORT ?? '4096';
|
|
|
return {
|
|
|
@@ -36,10 +47,16 @@ function createMockContext(overrides?: {
|
|
|
},
|
|
|
},
|
|
|
directory: overrides?.directory ?? '/test/directory',
|
|
|
- serverUrl: new URL(`http://localhost:${defaultPort}`),
|
|
|
+ serverUrl: new URL(
|
|
|
+ overrides?.serverUrl ?? `http://localhost:${defaultPort}`,
|
|
|
+ ),
|
|
|
} as any;
|
|
|
}
|
|
|
|
|
|
+function setMockSessionStatuses(statuses: Record<string, { type: string }>) {
|
|
|
+ mockSessionStatuses = statuses;
|
|
|
+}
|
|
|
+
|
|
|
const defaultMultiplexerConfig = {
|
|
|
type: 'tmux' as const,
|
|
|
layout: 'main-vertical' as const,
|
|
|
@@ -58,6 +75,9 @@ function createDeferred<T>() {
|
|
|
|
|
|
describe('MultiplexerSessionManager', () => {
|
|
|
beforeEach(() => {
|
|
|
+ mockSessionStatuses = {};
|
|
|
+ mockFetch.mockClear();
|
|
|
+ globalThis.fetch = mockFetch as typeof fetch;
|
|
|
mockMultiplexer.spawnPane.mockReset();
|
|
|
mockMultiplexer.spawnPane.mockResolvedValue({
|
|
|
success: true,
|
|
|
@@ -69,6 +89,10 @@ describe('MultiplexerSessionManager', () => {
|
|
|
mockMultiplexer.isInsideSession.mockReturnValue(true);
|
|
|
});
|
|
|
|
|
|
+ afterEach(() => {
|
|
|
+ globalThis.fetch = originalFetch;
|
|
|
+ });
|
|
|
+
|
|
|
describe('constructor', () => {
|
|
|
test('initializes with config', () => {
|
|
|
const ctx = createMockContext();
|
|
|
@@ -227,10 +251,7 @@ describe('MultiplexerSessionManager', () => {
|
|
|
properties: { info: { id: 'c1', parentID: 'p1' } },
|
|
|
});
|
|
|
|
|
|
- // Mock status
|
|
|
- ctx.client.session.status.mockResolvedValue({
|
|
|
- data: { c1: { type: 'idle' } },
|
|
|
- });
|
|
|
+ setMockSessionStatuses({ c1: { type: 'idle' } });
|
|
|
|
|
|
await (manager as any).pollSessions();
|
|
|
|
|
|
@@ -249,9 +270,36 @@ describe('MultiplexerSessionManager', () => {
|
|
|
properties: { info: { id: 'c1', parentID: 'p1' } },
|
|
|
});
|
|
|
|
|
|
- ctx.client.session.status.mockResolvedValue({ data: {} });
|
|
|
+ setMockSessionStatuses({});
|
|
|
+ await (manager as any).pollSessions();
|
|
|
+
|
|
|
+ expect(mockMultiplexer.closePane).not.toHaveBeenCalled();
|
|
|
+ });
|
|
|
+
|
|
|
+ test('polls the actual serverUrl instead of the plugin SDK default URL', async () => {
|
|
|
+ const ctx = createMockContext({
|
|
|
+ serverUrl: 'http://127.0.0.1:63871/',
|
|
|
+ sessionStatusResult: { data: {} },
|
|
|
+ });
|
|
|
+ const manager = new MultiplexerSessionManager(
|
|
|
+ ctx,
|
|
|
+ defaultMultiplexerConfig,
|
|
|
+ );
|
|
|
+
|
|
|
+ await manager.onSessionCreated({
|
|
|
+ type: 'session.created',
|
|
|
+ properties: { info: { id: 'child-live', parentID: 'parent-live' } },
|
|
|
+ });
|
|
|
+
|
|
|
+ setMockSessionStatuses({ 'child-live': { type: 'busy' } });
|
|
|
+
|
|
|
await (manager as any).pollSessions();
|
|
|
|
|
|
+ expect(ctx.client.session.status).not.toHaveBeenCalled();
|
|
|
+ expect(mockFetch).toHaveBeenCalledWith(
|
|
|
+ new URL('http://127.0.0.1:63871/session/status'),
|
|
|
+ expect.any(Object),
|
|
|
+ );
|
|
|
expect(mockMultiplexer.closePane).not.toHaveBeenCalled();
|
|
|
});
|
|
|
|
|
|
@@ -284,9 +332,7 @@ describe('MultiplexerSessionManager', () => {
|
|
|
},
|
|
|
});
|
|
|
|
|
|
- ctx.client.session.status.mockResolvedValue({
|
|
|
- data: { 'child-789': { type: 'idle' } },
|
|
|
- });
|
|
|
+ setMockSessionStatuses({ 'child-789': { type: 'idle' } });
|
|
|
await (manager as any).pollSessions();
|
|
|
|
|
|
await manager.onSessionStatus({
|