@effectstream/db 0.200.2 → 0.200.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -6
- package/test/start-pglite.test.ts +100 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effectstream/db",
|
|
3
|
-
"version": "0.200.
|
|
3
|
+
"version": "0.200.5",
|
|
4
4
|
"license": "(MIT OR Apache-2.0)",
|
|
5
5
|
"homepage": "https://effectstream.github.io/docs/",
|
|
6
6
|
"repository": {
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
"./version": "./migrations/system-version.ts"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@effectstream/coroutine": "0.200.
|
|
25
|
-
"@effectstream/log": "0.200.
|
|
26
|
-
"@effectstream/runtime": "0.200.
|
|
27
|
-
"@effectstream/sync": "0.200.
|
|
28
|
-
"@effectstream/utils": "0.200.
|
|
24
|
+
"@effectstream/coroutine": "0.200.5",
|
|
25
|
+
"@effectstream/log": "0.200.5",
|
|
26
|
+
"@effectstream/runtime": "0.200.5",
|
|
27
|
+
"@effectstream/sync": "0.200.5",
|
|
28
|
+
"@effectstream/utils": "0.200.5",
|
|
29
29
|
"@electric-sql/pglite": "^0.3.14",
|
|
30
30
|
"@pgtyped/runtime": "2.4.2",
|
|
31
31
|
"@pgtyped/parser": "2.4.2",
|
|
@@ -15,12 +15,25 @@ const connection = (handle: PgliteHandle) => ({
|
|
|
15
15
|
connectionTimeoutMillis: 500,
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
type PositiveClientFactory = (config: ReturnType<typeof connection>) => Client;
|
|
19
|
+
|
|
20
|
+
const createPositiveClient: PositiveClientFactory = (config) => new Client(config);
|
|
21
|
+
|
|
22
|
+
async function connect(
|
|
23
|
+
handle: PgliteHandle,
|
|
24
|
+
clientFactory: PositiveClientFactory = createPositiveClient,
|
|
25
|
+
): Promise<Client> {
|
|
26
|
+
await handle.db.waitReady;
|
|
27
|
+
const client = clientFactory(connection(handle));
|
|
20
28
|
await client.connect();
|
|
21
29
|
return client;
|
|
22
30
|
}
|
|
23
31
|
|
|
32
|
+
const controlledHandle = (waitReady: Promise<unknown>, port = 5432): PgliteHandle => ({
|
|
33
|
+
port,
|
|
34
|
+
db: { waitReady },
|
|
35
|
+
}) as unknown as PgliteHandle;
|
|
36
|
+
|
|
24
37
|
async function expectRefused(handle: PgliteHandle): Promise<void> {
|
|
25
38
|
const probe = new Client(connection(handle));
|
|
26
39
|
await expect(probe.connect()).rejects.toMatchObject({ code: "ECONNREFUSED" });
|
|
@@ -49,6 +62,91 @@ async function waitFor(
|
|
|
49
62
|
}
|
|
50
63
|
}
|
|
51
64
|
|
|
65
|
+
test("positive client waits for readiness before construction", async () => {
|
|
66
|
+
const order: string[] = [];
|
|
67
|
+
let releaseReadiness!: () => void;
|
|
68
|
+
const readinessGate = new Promise<void>((resolve) => {
|
|
69
|
+
releaseReadiness = resolve;
|
|
70
|
+
});
|
|
71
|
+
const waitReady = readinessGate.then(() => {
|
|
72
|
+
order.push("readiness");
|
|
73
|
+
});
|
|
74
|
+
const fakeClient = {
|
|
75
|
+
connect: async () => {
|
|
76
|
+
order.push("connect");
|
|
77
|
+
},
|
|
78
|
+
} as unknown as Client;
|
|
79
|
+
let observedConfig: ReturnType<typeof connection> | undefined;
|
|
80
|
+
const clientFactory: PositiveClientFactory = (config) => {
|
|
81
|
+
order.push("construction");
|
|
82
|
+
observedConfig = config;
|
|
83
|
+
return fakeClient;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
let connectionAttempt: Promise<Client> | undefined;
|
|
87
|
+
try {
|
|
88
|
+
const startedAt = Date.now();
|
|
89
|
+
connectionAttempt = connect(controlledHandle(waitReady), clientFactory);
|
|
90
|
+
await Bun.sleep(600);
|
|
91
|
+
|
|
92
|
+
expect(Date.now() - startedAt).toBeGreaterThanOrEqual(600);
|
|
93
|
+
expect(order).toEqual([]);
|
|
94
|
+
expect(observedConfig).toBeUndefined();
|
|
95
|
+
|
|
96
|
+
releaseReadiness();
|
|
97
|
+
expect(await connectionAttempt).toBe(fakeClient);
|
|
98
|
+
expect(order).toEqual(["readiness", "construction", "connect"]);
|
|
99
|
+
expect(observedConfig?.connectionTimeoutMillis).toBe(500);
|
|
100
|
+
} finally {
|
|
101
|
+
releaseReadiness();
|
|
102
|
+
await connectionAttempt?.catch(() => {});
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("positive client propagates readiness rejection before construction", async () => {
|
|
107
|
+
const readinessError = new Error("controlled readiness rejection");
|
|
108
|
+
const waitReady = Promise.reject(readinessError);
|
|
109
|
+
void waitReady.catch(() => {});
|
|
110
|
+
let constructionCount = 0;
|
|
111
|
+
let connectCount = 0;
|
|
112
|
+
const clientFactory: PositiveClientFactory = () => {
|
|
113
|
+
constructionCount += 1;
|
|
114
|
+
return {
|
|
115
|
+
connect: async () => {
|
|
116
|
+
connectCount += 1;
|
|
117
|
+
},
|
|
118
|
+
} as unknown as Client;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
await expect(connect(controlledHandle(waitReady), clientFactory)).rejects.toBe(readinessError);
|
|
122
|
+
expect(constructionCount).toBe(0);
|
|
123
|
+
expect(connectCount).toBe(0);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("positive client preserves the 500 ms post-readiness handshake timeout", async () => {
|
|
127
|
+
const acceptedSockets: net.Socket[] = [];
|
|
128
|
+
const stalledServer = net.createServer((socket) => {
|
|
129
|
+
acceptedSockets.push(socket);
|
|
130
|
+
});
|
|
131
|
+
await new Promise<void>((resolve) => stalledServer.listen(0, "127.0.0.1", resolve));
|
|
132
|
+
const address = stalledServer.address();
|
|
133
|
+
if (!address || typeof address === "string") {
|
|
134
|
+
throw new Error("Unable to allocate a controlled loopback port.");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
await expect(connect(controlledHandle(Promise.resolve(), address.port))).rejects.toMatchObject({
|
|
139
|
+
message: "timeout expired",
|
|
140
|
+
});
|
|
141
|
+
expect(acceptedSockets).toHaveLength(1);
|
|
142
|
+
} finally {
|
|
143
|
+
for (const socket of acceptedSockets) socket.destroy();
|
|
144
|
+
await new Promise<void>((resolve, reject) => {
|
|
145
|
+
stalledServer.close((error) => error ? reject(error) : resolve());
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
52
150
|
test("default and forced close are bounded without clients", async () => {
|
|
53
151
|
const graceful = await startPglite(0);
|
|
54
152
|
const forced = await startPglite(0);
|