mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
288 lines
9.3 KiB
JavaScript
288 lines
9.3 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {
|
|
nativeIntegrationFixture,
|
|
assertSuccessfulZoom,
|
|
turnOfEventLoop,
|
|
} from '../testSupport/geminiIntegrationFixture.mjs';
|
|
|
|
const options = { concurrency: false, timeout: 5000 };
|
|
const resultFor = (h, id) =>
|
|
h.events.filter(
|
|
(event) => event.type === 'action-result' && event.callId === id,
|
|
);
|
|
const callFor = (h, id) =>
|
|
h.events.filter(
|
|
(event) => event.type === 'action-call' && event.callId === id,
|
|
);
|
|
|
|
test(
|
|
'native tool reaches actual common session and camera runner without a caption',
|
|
options,
|
|
async (t) => {
|
|
const h = nativeIntegrationFixture(t);
|
|
const ws = await h.start();
|
|
h.activity(ws); // Native activity is input framing, not transcript admission.
|
|
await h.tool('ordinary', ws);
|
|
assertSuccessfulZoom(h, ws, 'ordinary', 1000);
|
|
assert.equal(h.runnerCalls.length, 1);
|
|
assert.equal(h.runnerCalls[0].options.callId, 'ordinary');
|
|
assert.equal(h.runnerCalls[0].options.signal.aborted, false);
|
|
assert.equal(h.runnerCalls[0].options.isCurrent(), true);
|
|
h.complete(ws);
|
|
assert.equal(h.controller.narration.state().tools, 0);
|
|
assert.equal(h.controller.narration.state().pendingTimers, 0);
|
|
},
|
|
);
|
|
|
|
for (const cancellation of ['stop', 'native interruption']) {
|
|
test(
|
|
`${cancellation} discards a stale completed action result; successor changes camera once`,
|
|
options,
|
|
async (t) => {
|
|
const h = nativeIntegrationFixture(t);
|
|
const oldSocket = await h.start();
|
|
h.activity(oldSocket);
|
|
const gate = h.holdResult('old');
|
|
const oldDispatch = h.tool('old', oldSocket);
|
|
const committedResult = await gate.ready;
|
|
assert.equal(committedResult.ok, true);
|
|
assert.equal(
|
|
h.state.height,
|
|
750,
|
|
'the legitimate first action committed before cancellation',
|
|
);
|
|
assert.equal(callFor(h, 'old').length, 1);
|
|
assert.deepEqual(resultFor(h, 'old'), []);
|
|
assert.deepEqual(h.outputs(oldSocket), []);
|
|
|
|
if (cancellation === 'stop') h.session.stop();
|
|
else
|
|
oldSocket.message({
|
|
serverContent: { interrupted: true, turnComplete: true },
|
|
});
|
|
assert.equal(h.runnerCalls[0].options.signal.aborted, true);
|
|
assert.equal(h.runnerCalls[0].options.isCurrent(), false);
|
|
await oldDispatch; // Cancellation must settle before the held result returns.
|
|
gate.release();
|
|
await turnOfEventLoop();
|
|
assert.equal(
|
|
h.state.height,
|
|
750,
|
|
'settling a cancelled result adds no camera mutation',
|
|
);
|
|
assert.equal(h.state.zooms.length, 1);
|
|
assert.deepEqual(resultFor(h, 'old'), []);
|
|
assert.deepEqual(h.outputs(oldSocket), []);
|
|
if (cancellation === 'native interruption')
|
|
assert.ok(h.events.some((event) => event.type === 'interruption'));
|
|
|
|
const successorSocket =
|
|
cancellation === 'stop' ? await h.start() : oldSocket;
|
|
h.activity(successorSocket);
|
|
await h.tool('successor', successorSocket);
|
|
assertSuccessfulZoom(h, successorSocket, 'successor', 750);
|
|
assert.equal(h.state.zooms.length, 2);
|
|
assert.equal(h.runnerCalls.length, 2);
|
|
assert.equal(
|
|
h.outputs(successorSocket).some((output) => output.id === 'old'),
|
|
false,
|
|
);
|
|
h.complete(successorSocket);
|
|
},
|
|
);
|
|
}
|
|
|
|
for (const phase of ['common connecting', 'adapter connecting']) {
|
|
test(
|
|
`Stop from ${phase} observer prevents acquisition and permits fresh Start`,
|
|
options,
|
|
async (t) => {
|
|
const h = nativeIntegrationFixture(t);
|
|
let stopped = false;
|
|
const remove = h.session.subscribe((event) => {
|
|
const matchingDetail =
|
|
phase === 'common connecting'
|
|
? event.detail === undefined
|
|
: typeof event.detail === 'string' && event.detail.length > 0;
|
|
if (
|
|
!stopped &&
|
|
event.type === 'state' &&
|
|
event.state === 'connecting' &&
|
|
matchingDetail
|
|
) {
|
|
stopped = true;
|
|
h.session.stop();
|
|
}
|
|
});
|
|
await h.session.start();
|
|
remove();
|
|
assert.equal(
|
|
stopped,
|
|
true,
|
|
'the chosen production observer boundary was exercised',
|
|
);
|
|
assert.deepEqual(h.acquisitions, {
|
|
microphone: 0,
|
|
audio: 0,
|
|
token: 0,
|
|
socket: 0,
|
|
});
|
|
assert.equal(h.session.state, 'idle');
|
|
assert.equal(h.controller.narration.state().tools, 0);
|
|
assert.equal(h.controller.narration.state().pendingTimers, 0);
|
|
assert.equal(h.clock.timers.size, 0);
|
|
const ws = await h.start();
|
|
h.activity(ws);
|
|
await h.tool('fresh-after-start-cancel', ws);
|
|
assertSuccessfulZoom(h, ws, 'fresh-after-start-cancel', 1000);
|
|
h.complete(ws);
|
|
},
|
|
);
|
|
}
|
|
|
|
test(
|
|
'Stop from common action-call observer prevents runner and leaves no unhandled rejection',
|
|
options,
|
|
async (t) => {
|
|
const h = nativeIntegrationFixture(t);
|
|
const ws = await h.start();
|
|
const remove = h.session.subscribe((event) => {
|
|
if (event.type === 'action-call' && event.callId === 'cancel-at-call')
|
|
h.session.stop();
|
|
});
|
|
h.activity(ws);
|
|
await h.tool('cancel-at-call', ws);
|
|
// Do not install a swallowing process rejection listener. node:test records
|
|
// an unhandled rejection as a failure; these checkpoints let it surface here.
|
|
await turnOfEventLoop();
|
|
await turnOfEventLoop();
|
|
remove();
|
|
assert.equal(callFor(h, 'cancel-at-call').length, 1);
|
|
assert.deepEqual(resultFor(h, 'cancel-at-call'), []);
|
|
assert.equal(h.runnerCalls.length, 0);
|
|
assert.equal(h.state.height, 1000);
|
|
assert.deepEqual(h.outputs(ws), []);
|
|
assert.equal(h.controller.narration.state().tools, 0);
|
|
assert.equal(h.controller.narration.state().pendingTimers, 0);
|
|
assert.equal(h.clock.timers.size, 0);
|
|
const successor = await h.start();
|
|
h.activity(successor);
|
|
await h.tool('after-call-cancel', successor);
|
|
assertSuccessfulZoom(h, successor, 'after-call-cancel', 1000);
|
|
h.complete(successor);
|
|
},
|
|
);
|
|
|
|
test(
|
|
'Stop from executing observer cannot recreate narration or dispatch the runner',
|
|
options,
|
|
async (t) => {
|
|
const h = nativeIntegrationFixture(t);
|
|
const ws = await h.start();
|
|
let stopped = false;
|
|
const remove = h.session.subscribe((event) => {
|
|
if (!stopped && event.type === 'state' && event.state === 'executing') {
|
|
stopped = true;
|
|
h.session.stop();
|
|
}
|
|
});
|
|
h.activity(ws);
|
|
await h.tool('cancel-at-executing', ws);
|
|
remove();
|
|
assert.equal(stopped, true);
|
|
assert.equal(h.runnerCalls.length, 0);
|
|
assert.deepEqual(callFor(h, 'cancel-at-executing'), []);
|
|
assert.deepEqual(resultFor(h, 'cancel-at-executing'), []);
|
|
assert.equal(h.state.height, 1000);
|
|
assert.deepEqual(h.outputs(ws), []);
|
|
assert.equal(h.controller.narration.state().tools, 0);
|
|
assert.equal(h.controller.narration.state().pendingTimers, 0);
|
|
assert.equal(h.clock.timers.size, 0);
|
|
assert.equal(ws.closed, true);
|
|
assert.ok(h.audios.every((audio) => audio.closed));
|
|
assert.ok(h.tracks.every((track) => track.readyState === 'ended'));
|
|
const before = {
|
|
events: h.events.length,
|
|
wire: ws.sent.length,
|
|
earcon: h.state.earconStarts,
|
|
};
|
|
h.clock.advance(60_000);
|
|
assert.deepEqual(
|
|
{
|
|
events: h.events.length,
|
|
wire: ws.sent.length,
|
|
earcon: h.state.earconStarts,
|
|
},
|
|
before,
|
|
);
|
|
const successor = await h.start();
|
|
h.activity(successor);
|
|
await h.tool('after-executing-cancel', successor);
|
|
assertSuccessfulZoom(h, successor, 'after-executing-cancel', 1000);
|
|
h.complete(successor);
|
|
},
|
|
);
|
|
|
|
test(
|
|
'native idle observer restart remains connecting and public Stop cancels its pending permission',
|
|
options,
|
|
async (t) => {
|
|
const h = nativeIntegrationFixture(t);
|
|
await h.start();
|
|
let grant;
|
|
const permission = new Promise((resolve) => {
|
|
grant = resolve;
|
|
});
|
|
h.controller.getUserMedia = () => permission;
|
|
const states = [];
|
|
let restarted = false;
|
|
let startup;
|
|
const remove = h.session.subscribe((event) => {
|
|
if (event.type === 'state') states.push(event.state);
|
|
if (!restarted && event.type === 'state' && event.state === 'idle') {
|
|
restarted = true;
|
|
startup = h.session.start();
|
|
}
|
|
});
|
|
h.session.stop();
|
|
remove();
|
|
assert.equal(restarted, true);
|
|
assert.equal(states.filter((state) => state === 'idle').length, 1);
|
|
assert.equal(h.session.state, 'connecting');
|
|
assert.equal(h.controller.status, 'connecting');
|
|
assert.equal(
|
|
h.session.isActive(),
|
|
true,
|
|
'the common button/facade must offer Stop',
|
|
);
|
|
h.session.stop();
|
|
assert.equal(h.session.state, 'idle');
|
|
assert.equal(h.controller.status, 'idle');
|
|
const lateTrack = {
|
|
readyState: 'live',
|
|
stopCalls: 0,
|
|
stop() {
|
|
this.stopCalls++;
|
|
this.readyState = 'ended';
|
|
},
|
|
};
|
|
h.tracks.push(lateTrack);
|
|
grant({ getTracks: () => [lateTrack], getAudioTracks: () => [lateTrack] });
|
|
await startup;
|
|
await turnOfEventLoop();
|
|
assert.equal(lateTrack.stopCalls, 1);
|
|
assert.equal(
|
|
h.requests.length,
|
|
1,
|
|
'cancelled restart must not mint another token',
|
|
);
|
|
assert.equal(
|
|
h.sockets.length,
|
|
1,
|
|
'cancelled restart must not open another socket',
|
|
);
|
|
assert.equal(h.session.state, 'idle');
|
|
},
|
|
);
|