fix(chat): recover session list from snapshots
This commit is contained in:
@@ -452,6 +452,134 @@ test('buildVisionPayload injects public standard image urls for page generation'
|
||||
assert.match(text, /不得改写图片里人物的年龄、性别、人数或主体关系/);
|
||||
});
|
||||
|
||||
test('GET /sessions serves snapshot summaries when every upstream is unavailable', async () => {
|
||||
let upstream;
|
||||
try {
|
||||
upstream = createServer((_req, res) => {
|
||||
res.writeHead(503, { 'Content-Type': 'text/plain' });
|
||||
res.end('temporarily unavailable');
|
||||
});
|
||||
const upstreamPort = await listen(upstream);
|
||||
const proxy = createTkmindProxy({
|
||||
apiTarget: `http://127.0.0.1:${upstreamPort}`,
|
||||
apiSecret: 'test-secret',
|
||||
userAuth: {
|
||||
async listOwnedSessionIds() {
|
||||
return new Set(['session-1']);
|
||||
},
|
||||
async getSessionOrigins() {
|
||||
return new Map([['session-1', 'h5']]);
|
||||
},
|
||||
},
|
||||
sessionSnapshotService: {
|
||||
isEnabled() {
|
||||
return true;
|
||||
},
|
||||
async get(sessionId) {
|
||||
assert.equal(sessionId, 'session-1');
|
||||
return {
|
||||
session: {
|
||||
id: sessionId,
|
||||
name: 'Recovered session',
|
||||
updated_at: '2026-07-27T00:00:00.000Z',
|
||||
},
|
||||
messages: [{ role: 'user', content: [{ type: 'text', text: 'hello' }] }],
|
||||
meta: {
|
||||
synced_msg_count: 1,
|
||||
source_updated_at: '2026-07-27T00:00:00.000Z',
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const req = {
|
||||
currentUser: { id: 'user-1', username: 'john' },
|
||||
query: {},
|
||||
};
|
||||
let payload;
|
||||
const headers = new Map();
|
||||
const res = {
|
||||
statusCode: 200,
|
||||
status(code) {
|
||||
this.statusCode = code;
|
||||
return this;
|
||||
},
|
||||
setHeader(name, value) {
|
||||
headers.set(name, value);
|
||||
},
|
||||
json(value) {
|
||||
payload = value;
|
||||
return this;
|
||||
},
|
||||
};
|
||||
|
||||
await proxy.handlers['GET /sessions'][1](req, res);
|
||||
|
||||
assert.equal(res.statusCode, 200);
|
||||
assert.equal(headers.get('X-TKMind-Degraded'), '1');
|
||||
assert.equal(payload.sessions.length, 1);
|
||||
assert.equal(payload.sessions[0].id, 'session-1');
|
||||
assert.equal(payload.sessions[0].name, 'Recovered session');
|
||||
assert.equal(payload.sessions[0].message_count, 1);
|
||||
} finally {
|
||||
await closeServer(upstream);
|
||||
}
|
||||
});
|
||||
|
||||
test('GET /sessions keeps the upstream error when no fallback session can be recovered', async () => {
|
||||
let upstream;
|
||||
try {
|
||||
upstream = createServer((_req, res) => {
|
||||
res.writeHead(503, { 'Content-Type': 'text/plain' });
|
||||
res.end('temporarily unavailable');
|
||||
});
|
||||
const upstreamPort = await listen(upstream);
|
||||
const proxy = createTkmindProxy({
|
||||
apiTarget: `http://127.0.0.1:${upstreamPort}`,
|
||||
apiSecret: 'test-secret',
|
||||
userAuth: {
|
||||
async listOwnedSessionIds() {
|
||||
return new Set(['session-1']);
|
||||
},
|
||||
},
|
||||
sessionSnapshotService: {
|
||||
isEnabled() {
|
||||
return true;
|
||||
},
|
||||
async get() {
|
||||
return null;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const req = {
|
||||
currentUser: { id: 'user-1', username: 'john' },
|
||||
query: {},
|
||||
};
|
||||
let payload;
|
||||
const res = {
|
||||
statusCode: 200,
|
||||
status(code) {
|
||||
this.statusCode = code;
|
||||
return this;
|
||||
},
|
||||
setHeader() {},
|
||||
json(value) {
|
||||
payload = value;
|
||||
return this;
|
||||
},
|
||||
};
|
||||
|
||||
await proxy.handlers['GET /sessions'][1](req, res);
|
||||
|
||||
assert.equal(res.statusCode, 502);
|
||||
assert.equal(payload.message, 'temporarily unavailable');
|
||||
} finally {
|
||||
await closeServer(upstream);
|
||||
}
|
||||
});
|
||||
|
||||
test('proxySessionEvents does not send JSON after SSE headers were sent', async () => {
|
||||
let upstream;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user