@clickup/ent-framework
Version:
A PostgreSQL graph-database-alike library with microsharding and row-level security
105 lines (90 loc) • 3.07 kB
text/typescript
import { MASTER, STALE_REPLICA } from "../../abstract/Shard";
import {
recreateTestTables,
TEST_CONFIG,
TEST_ISLANDS,
testCluster,
} from "../../pg/__tests__/test-utils";
import { PgSchema } from "../../pg/PgSchema";
import { ID } from "../../types";
import { BaseEnt } from "../BaseEnt";
import { True } from "../predicates/True";
import { AllowIf } from "../rules/AllowIf";
import { Require } from "../rules/Require";
import { GLOBAL_SHARD } from "../ShardAffinity";
import { createVC } from "./test-utils";
jest.useFakeTimers({ advanceTimers: true });
const vc = createVC("no-cache");
const entTestPersonSchema = new PgSchema(
'ent.timeline"person',
{
id: { type: ID, autoInsert: "id_gen()" },
name: { type: String },
},
[],
);
class EntTestPerson extends BaseEnt(testCluster, entTestPersonSchema) {
static readonly CREATE = [
`CREATE TABLE %T(
id bigint NOT NULL,
name text NOT NULL
)`,
];
static override configure() {
return new this.Configuration({
shardAffinity: GLOBAL_SHARD,
privacyInferPrincipal: null,
privacyLoad: [new AllowIf(new True())],
privacyInsert: [new Require(new True())],
});
}
}
beforeEach(async () => {
testCluster.options.islands = TEST_ISLANDS;
testCluster.options.shardsDiscoverIntervalMs = 1000000;
await testCluster.rediscover();
await recreateTestTables([EntTestPerson]);
});
test("replication lag tracking is simulated through timestamp", async () => {
testCluster.options.islands = [
{
no: 0,
nodes: [
{ ...TEST_CONFIG, role: "master" },
{ ...TEST_CONFIG, role: "replica" },
],
},
];
await testCluster.rediscover();
const master = await testCluster.shardByNo(0).client(MASTER);
const masterQuerySpy = jest.spyOn(master, "query");
const replica = await testCluster.shardByNo(0).client(STALE_REPLICA);
const replicaQuerySpy = jest.spyOn(replica, "query");
const id1 = await EntTestPerson.insert(vc, { name: "a" });
expect(masterQuerySpy).toBeCalledTimes(1);
expect(masterQuerySpy.mock.calls[0][0].annotations[0].whyClient).toBe(
"master-bc-is-write",
);
await EntTestPerson.loadX(vc, id1);
expect(replicaQuerySpy).toBeCalledTimes(0);
expect(masterQuerySpy).toBeCalledTimes(2);
expect(masterQuerySpy.mock.calls[1][0].annotations[0].whyClient).toBe(
"master-bc-replica-not-caught-up",
);
await jest.advanceTimersByTimeAsync(11000);
await EntTestPerson.loadX(vc, id1);
expect(replicaQuerySpy).toBeCalledTimes(1);
await jest.advanceTimersByTimeAsync(30000);
jest.clearAllMocks();
const id2 = await EntTestPerson.insert(vc, { name: "b" });
expect(masterQuerySpy).toBeCalledTimes(1);
expect(masterQuerySpy.mock.calls[0][0].annotations[0].whyClient).toBe(
"master-bc-is-write",
);
await EntTestPerson.loadX(vc, id2);
expect(replicaQuerySpy).toBeCalledTimes(0);
expect(masterQuerySpy).toBeCalledTimes(2);
expect(masterQuerySpy.mock.calls[1][0].annotations[0].whyClient).toBe(
"master-bc-replica-not-caught-up",
);
});