Initial Commit
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
|
||||
describe("network-plugin-partition dep-graph", () => {
|
||||
it("loads index.js (acyclic static imports)", async () => {
|
||||
const mod = await import("../src/index.js");
|
||||
expect(mod.PartitionDetector).toBeDefined();
|
||||
expect(mod.QuorumResolver).toBeDefined();
|
||||
expect(mod.MergeProtocol).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,57 @@
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
import {
|
||||
MergeProtocol,
|
||||
PartitionDetector,
|
||||
QuorumResolver,
|
||||
type Reconciler,
|
||||
} from "../../src/index.js";
|
||||
|
||||
describe("partition end-to-end", () => {
|
||||
it("detects split-brain, resolves quorum, and runs the merge", async () => {
|
||||
const aliceDetector = new PartitionDetector({
|
||||
meshId: "m",
|
||||
localPeerId: "alice",
|
||||
quorumRatio: 0.5,
|
||||
});
|
||||
aliceDetector.recordEpoch("bob", 1);
|
||||
|
||||
const charlieDetector = new PartitionDetector({
|
||||
meshId: "m",
|
||||
localPeerId: "charlie",
|
||||
quorumRatio: 0.5,
|
||||
});
|
||||
charlieDetector.recordEpoch("dave", 1);
|
||||
|
||||
const aliceView = aliceDetector.getPartitionView();
|
||||
const charlieView = charlieDetector.getPartitionView();
|
||||
expect(aliceView.partitionId).not.toBe(charlieView.partitionId);
|
||||
|
||||
const resolver = new QuorumResolver({ strategy: "size" });
|
||||
const winner = resolver.resolve([
|
||||
{ ...aliceView, reachablePeers: ["alice", "bob", "x"] },
|
||||
{ ...charlieView, reachablePeers: ["charlie"] },
|
||||
]);
|
||||
expect(winner?.reachablePeers.length).toBe(3);
|
||||
|
||||
const reconciled: string[] = [];
|
||||
const reg: Reconciler<unknown> = {
|
||||
name: "registry",
|
||||
reconcile: (auth, div) => {
|
||||
reconciled.push(`${String(auth)}+${String(div)}`);
|
||||
return auth;
|
||||
},
|
||||
};
|
||||
const merge = new MergeProtocol({ reconcilers: [reg] });
|
||||
await merge.merge(
|
||||
aliceView,
|
||||
charlieView,
|
||||
new Map([
|
||||
[
|
||||
"registry",
|
||||
{ authoritative: "auth-state", divergent: "div-state" },
|
||||
],
|
||||
])
|
||||
);
|
||||
expect(reconciled).toEqual(["auth-state+div-state"]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
// Ensure `globalThis.crypto` is available in bare-Node vitest runs.
|
||||
import { webcrypto } from "node:crypto";
|
||||
|
||||
type WritableGlobal = { crypto?: Crypto };
|
||||
const g = globalThis as WritableGlobal;
|
||||
if (g.crypto === undefined) {
|
||||
g.crypto = webcrypto as unknown as Crypto;
|
||||
}
|
||||
Reference in New Issue
Block a user