test: cover server restart session recovery
This commit is contained in:
@@ -193,6 +193,103 @@ describe("YNX-1105e: Server state recovery", () => {
|
||||
await secondRuntime.stop();
|
||||
});
|
||||
|
||||
it("SR-02: restart drops in-memory active sessions and requires reconnect", async () => {
|
||||
const storePath = await createTempServerStorePath();
|
||||
const store = createYonexusServerStore(storePath);
|
||||
const now = 1_710_000_000;
|
||||
|
||||
const firstTransport = createMockTransport();
|
||||
const firstRuntime = createYonexusServerRuntime({
|
||||
config: {
|
||||
followerIdentifiers: ["client-a"],
|
||||
notifyBotToken: "stub-token",
|
||||
adminUserId: "admin-user",
|
||||
listenHost: "127.0.0.1",
|
||||
listenPort: 8787
|
||||
},
|
||||
store,
|
||||
transport: firstTransport.transport,
|
||||
now: () => now
|
||||
});
|
||||
|
||||
await firstRuntime.start();
|
||||
const record = firstRuntime.state.registry.clients.get("client-a");
|
||||
expect(record).toBeDefined();
|
||||
|
||||
record!.pairingStatus = "paired";
|
||||
record!.publicKey = "test-public-key";
|
||||
record!.secret = "test-secret";
|
||||
record!.status = "online";
|
||||
record!.lastAuthenticatedAt = now;
|
||||
record!.lastHeartbeatAt = now;
|
||||
record!.updatedAt = now;
|
||||
|
||||
firstRuntime.state.registry.sessions.set("client-a", {
|
||||
identifier: "client-a",
|
||||
socket: createMockSocket(),
|
||||
isAuthenticated: true,
|
||||
connectedAt: now,
|
||||
lastActivityAt: now,
|
||||
publicKey: "test-public-key"
|
||||
});
|
||||
|
||||
await firstRuntime.stop();
|
||||
|
||||
const secondTransport = createMockTransport();
|
||||
const secondRuntime = createYonexusServerRuntime({
|
||||
config: {
|
||||
followerIdentifiers: ["client-a"],
|
||||
notifyBotToken: "stub-token",
|
||||
adminUserId: "admin-user",
|
||||
listenHost: "127.0.0.1",
|
||||
listenPort: 8787
|
||||
},
|
||||
store,
|
||||
transport: secondTransport.transport,
|
||||
now: () => now + 5
|
||||
});
|
||||
|
||||
await secondRuntime.start();
|
||||
|
||||
const reloadedRecord = secondRuntime.state.registry.clients.get("client-a");
|
||||
expect(reloadedRecord).toMatchObject({
|
||||
identifier: "client-a",
|
||||
pairingStatus: "paired",
|
||||
secret: "test-secret",
|
||||
publicKey: "test-public-key",
|
||||
status: "online",
|
||||
lastAuthenticatedAt: now,
|
||||
lastHeartbeatAt: now
|
||||
});
|
||||
expect(secondRuntime.state.registry.sessions.size).toBe(0);
|
||||
|
||||
const reconnectConnection = createConnection();
|
||||
await secondRuntime.handleMessage(
|
||||
reconnectConnection,
|
||||
encodeBuiltin(
|
||||
buildHello(
|
||||
{
|
||||
identifier: "client-a",
|
||||
hasSecret: true,
|
||||
hasKeyPair: true,
|
||||
publicKey: "test-public-key",
|
||||
protocolVersion: YONEXUS_PROTOCOL_VERSION
|
||||
},
|
||||
{ requestId: "req-hello-reconnect", timestamp: now + 5 }
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
const helloAck = decodeBuiltin(secondTransport.sentToConnection[0].message);
|
||||
expect(helloAck.type).toBe("hello_ack");
|
||||
expect(helloAck.payload).toMatchObject({
|
||||
identifier: "client-a",
|
||||
nextAction: "auth_required"
|
||||
});
|
||||
|
||||
await secondRuntime.stop();
|
||||
});
|
||||
|
||||
it("SR-05: corrupted server store raises YonexusServerStoreCorruptionError", async () => {
|
||||
const storePath = await createTempServerStorePath();
|
||||
await writeFile(storePath, '{"version":1,"clients":"oops"}\n', "utf8");
|
||||
|
||||
Reference in New Issue
Block a user