Skip to content

Commit 6669eee

Browse files
authored
fix: preserve batch session state for recordings (#244)
1 parent 4496561 commit 6669eee

4 files changed

Lines changed: 95 additions & 2 deletions

File tree

src/daemon/__tests__/request-router-lock-policy.test.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,46 @@ test('direct daemon requests apply strip lock policy for existing sessions befor
154154
assert.equal(action?.flags.target, undefined);
155155
assert.equal(action?.flags.device, 'iPhone 16');
156156
});
157+
158+
test('batch preserves tenant-scoped session names across nested requests', async () => {
159+
const sessionStore = makeStore();
160+
sessionStore.set('tenant-a:default', makeIosSession('tenant-a:default'));
161+
const leaseRegistry = new LeaseRegistry();
162+
const lease = leaseRegistry.allocateLease({
163+
tenantId: 'tenant-a',
164+
runId: 'run-1',
165+
});
166+
let dispatchCalls = 0;
167+
168+
const handler = createRequestHandler({
169+
logPath: path.join(os.tmpdir(), 'daemon.log'),
170+
token: 'test-token',
171+
sessionStore,
172+
leaseRegistry,
173+
trackDownloadableArtifact: () => 'artifact-id',
174+
dispatchCommand: async () => {
175+
dispatchCalls += 1;
176+
return {};
177+
},
178+
});
179+
180+
const response = await handler({
181+
token: 'test-token',
182+
session: 'default',
183+
command: 'batch',
184+
positionals: [],
185+
flags: {
186+
batchSteps: [{ command: 'home' }],
187+
},
188+
meta: {
189+
tenantId: 'tenant-a',
190+
runId: 'run-1',
191+
leaseId: lease.leaseId,
192+
sessionIsolation: 'tenant',
193+
},
194+
});
195+
196+
assert.equal(response.ok, true);
197+
assert.equal(dispatchCalls, 1);
198+
assert.equal(sessionStore.get('tenant-a:default')?.actions.at(-1)?.command, 'home');
199+
});

src/daemon/handlers/__tests__/session.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,41 @@ test('batch step forwards typed runtime payload', async () => {
270270
]);
271271
});
272272

273+
test('batch step pins nested requests to the resolved session', async () => {
274+
const sessionStore = makeSessionStore();
275+
const seenSessions: Array<{ session: string; flagSession: string | undefined }> = [];
276+
277+
const response = await handleSessionCommands({
278+
req: {
279+
token: 't',
280+
session: 'default',
281+
command: 'batch',
282+
positionals: [],
283+
flags: {
284+
batchSteps: [{ command: 'wait', positionals: ['100'] }],
285+
},
286+
},
287+
sessionName: 'resolved-session',
288+
logPath: path.join(os.tmpdir(), 'daemon.log'),
289+
sessionStore,
290+
invoke: async (stepReq) => {
291+
seenSessions.push({
292+
session: stepReq.session,
293+
flagSession: stepReq.flags?.session,
294+
});
295+
return { ok: true, data: {} };
296+
},
297+
});
298+
299+
assert.equal(response?.ok, true);
300+
assert.deepEqual(seenSessions, [
301+
{
302+
session: 'resolved-session',
303+
flagSession: 'resolved-session',
304+
},
305+
]);
306+
});
307+
273308
test('runtime set/show/clear manages session-scoped runtime hints before open', async () => {
274309
const sessionStore = makeSessionStore();
275310
const baseRequest = {

src/daemon/handlers/session-batch.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,16 @@ async function runBatchStep(
113113
}
114114
> {
115115
const stepStartedAt = Date.now();
116+
const stepFlags = buildBatchStepFlags(req.flags, step.flags);
117+
if (stepFlags.session === undefined) {
118+
stepFlags.session = sessionName;
119+
}
116120
const response = await invoke({
117121
token: req.token,
118122
session: sessionName,
119123
command: step.command,
120124
positionals: step.positionals,
121-
flags: buildBatchStepFlags(req.flags, step.flags),
125+
flags: stepFlags,
122126
runtime: step.runtime as DaemonRequest['runtime'],
123127
meta: req.meta,
124128
});

src/daemon/request-router.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,20 @@ function scopeRequestSession(req: DaemonRequest): DaemonRequest {
8686
'session isolation mode tenant requires --tenant (or meta.tenantId).',
8787
);
8888
}
89+
const requestedSession = req.session || 'default';
90+
if (requestedSession.startsWith(`${tenant}:`)) {
91+
return {
92+
...req,
93+
meta: {
94+
...req.meta,
95+
tenantId: tenant,
96+
sessionIsolation: isolation,
97+
},
98+
};
99+
}
89100
return {
90101
...req,
91-
session: `${tenant}:${req.session || 'default'}`,
102+
session: `${tenant}:${requestedSession}`,
92103
meta: {
93104
...req.meta,
94105
tenantId: tenant,

0 commit comments

Comments
 (0)