snapshot of https://github.com/ueberdosis/hocuspocus.git @ cf3cfa355b4d3bb61c6b6c80071f71783e32470e (2026-09-15)
Some checks failed
build / lint (22) (push) Failing after 17s
build / test (22) (push) Failing after 8s
build / lint (23) (push) Failing after 2s
build / build (22) (push) Has been skipped
build / build (23) (push) Has been skipped
build / test (23) (push) Failing after 4s
docsearch / docsearch (push) Failing after 1s
Some checks failed
build / lint (22) (push) Failing after 17s
build / test (22) (push) Failing after 8s
build / lint (23) (push) Failing after 2s
build / build (22) (push) Has been skipped
build / build (23) (push) Has been skipped
build / test (23) (push) Failing after 4s
docsearch / docsearch (push) Failing after 1s
This commit is contained in:
74
tests/extension-redis/openDirectConnection.ts
Normal file
74
tests/extension-redis/openDirectConnection.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { Redis } from "@hocuspocus/extension-redis";
|
||||
import test from "ava";
|
||||
import { newHocuspocus, redisConnectionSettings, sleep } from "../utils/index.ts";
|
||||
|
||||
const newRedisServer = (t: any, prefix: string, identifier: string, options = {}) =>
|
||||
newHocuspocus(t, {
|
||||
extensions: [
|
||||
new Redis({
|
||||
...redisConnectionSettings,
|
||||
identifier: `${identifier}${crypto.randomUUID()}`,
|
||||
prefix,
|
||||
// Keep teardown quick — these delays are unrelated to load-time sync.
|
||||
disconnectDelay: 100,
|
||||
...options,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
test("direct connection on a second instance sees edits that only live in another instance's memory", async (t) => {
|
||||
const prefix = `extension-redis/openDirectConnection-${crypto.randomUUID()}`;
|
||||
|
||||
const serverA = await newRedisServer(t, prefix, "serverA");
|
||||
const serverB = await newRedisServer(t, prefix, "serverB");
|
||||
|
||||
// Open + modify the document on server A and keep the connection open so the
|
||||
// document stays in memory on A and is never persisted to storage. The only
|
||||
// way server B can learn about this edit is via the Redis sync handshake.
|
||||
const directA = await serverA.openDirectConnection("sync-on-open");
|
||||
await directA.transact((doc) => {
|
||||
doc.getMap("config").set("foo", "bar");
|
||||
});
|
||||
|
||||
// Open a direct connection on server B and read immediately. Without an
|
||||
// inbound-sync wait in afterLoadDocument, B only has the (empty) state it
|
||||
// loaded from storage, so this read sees `undefined`.
|
||||
const directB = await serverB.openDirectConnection("sync-on-open");
|
||||
|
||||
let seenValue: unknown;
|
||||
await directB.transact((doc) => {
|
||||
seenValue = doc.getMap("config").get("foo");
|
||||
});
|
||||
|
||||
t.is(seenValue, "bar");
|
||||
|
||||
await directB.disconnect();
|
||||
await directA.disconnect();
|
||||
});
|
||||
|
||||
test("openDirectConnection on a single instance does not stall waiting for absent peers", async (t) => {
|
||||
const prefix = `extension-redis/openDirectConnection-solo-${crypto.randomUUID()}`;
|
||||
|
||||
// A generous sync timeout: if presence detection is broken and we wait for
|
||||
// peers that don't exist, this load would take ~5s instead of being instant.
|
||||
const server = await newRedisServer(t, prefix, "solo", {
|
||||
awaitInitialSyncTimeout: 5000,
|
||||
});
|
||||
|
||||
const start = Date.now();
|
||||
const direct = await server.openDirectConnection("solo-doc");
|
||||
const elapsed = Date.now() - start;
|
||||
|
||||
t.true(
|
||||
elapsed < 2000,
|
||||
`openDirectConnection should not block on absent peers (took ${elapsed}ms)`,
|
||||
);
|
||||
|
||||
await direct.transact((doc) => {
|
||||
doc.getMap("config").set("foo", "bar");
|
||||
});
|
||||
t.is(direct.document?.getMap("config").get("foo"), "bar");
|
||||
|
||||
await direct.disconnect();
|
||||
await sleep(50);
|
||||
});
|
||||
Reference in New Issue
Block a user