first commit
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
import { test, expect } from "bun:test";
|
||||
import { createPubSub } from "../src/index.ts";
|
||||
|
||||
test("publish reaches exact + wildcard subscribers", async () => {
|
||||
const bus = createPubSub();
|
||||
const got: string[] = [];
|
||||
bus.subscribe("order:created", (m: { id: number }) => {
|
||||
got.push(`exact:${m.id}`);
|
||||
});
|
||||
bus.subscribe("order:*", (_m, topic) => {
|
||||
got.push(`prefix:${topic}`);
|
||||
});
|
||||
bus.subscribe("*", (_m, topic) => {
|
||||
got.push(`all:${topic}`);
|
||||
});
|
||||
|
||||
await bus.publish("order:created", { id: 7 });
|
||||
await bus.publish("user:login", { id: 1 });
|
||||
|
||||
expect(got).toContain("exact:7");
|
||||
expect(got).toContain("prefix:order:created");
|
||||
expect(got).toContain("all:order:created");
|
||||
expect(got).toContain("all:user:login");
|
||||
expect(got).not.toContain("prefix:user:login"); // order:* doesn't match user:*
|
||||
});
|
||||
|
||||
test("unsubscribe stops delivery", async () => {
|
||||
const bus = createPubSub();
|
||||
let n = 0;
|
||||
const off = bus.subscribe("t", () => {
|
||||
n++;
|
||||
});
|
||||
await bus.publish("t", 1);
|
||||
off();
|
||||
await bus.publish("t", 2);
|
||||
expect(n).toBe(1);
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
import { afterEach, expect, test } from "bun:test";
|
||||
import { redisDriver } from "../src/redis.ts";
|
||||
|
||||
const bun = globalThis.Bun as typeof Bun & { connect: (options: unknown) => Promise<unknown> };
|
||||
const originalConnect = bun.connect;
|
||||
afterEach(() => {
|
||||
bun.connect = originalConnect;
|
||||
});
|
||||
|
||||
test("rediss URLs enable TLS and decode credentials", () => {
|
||||
const options: Array<Record<string, unknown>> = [];
|
||||
bun.connect = ((value: Record<string, unknown>) => {
|
||||
options.push(value);
|
||||
return new Promise(() => {});
|
||||
}) as typeof bun.connect;
|
||||
const driver = redisDriver("rediss://user:p%40ss@redis.example.com:6380/2");
|
||||
expect(options).toHaveLength(2);
|
||||
expect(options[0]).toMatchObject({ hostname: "redis.example.com", port: 6380, tls: true });
|
||||
driver.close();
|
||||
});
|
||||
|
||||
test("rejects invalid Redis URLs before connecting", () => {
|
||||
expect(() => redisDriver("http://localhost:6379")).toThrow("redis:// or rediss://");
|
||||
expect(() => redisDriver("redis://localhost/not-a-db")).toThrow("database");
|
||||
});
|
||||
|
||||
test("bounds writes queued while Redis is unavailable", () => {
|
||||
bun.connect = (() => new Promise(() => {})) as typeof bun.connect;
|
||||
const driver = redisDriver("redis://localhost:6379");
|
||||
for (let index = 0; index < 1000; index++) driver.publish("topic", index);
|
||||
expect(() => driver.publish("topic", "overflow")).toThrow("queue is full");
|
||||
driver.close();
|
||||
});
|
||||
@@ -0,0 +1,51 @@
|
||||
import { test, expect } from "bun:test";
|
||||
import { encodeCommand, parseReply, concat } from "../src/resp.ts";
|
||||
|
||||
const enc = new TextEncoder();
|
||||
const dec = new TextDecoder();
|
||||
|
||||
test("encodeCommand produces a RESP array of bulk strings", () => {
|
||||
const bytes = encodeCommand(["PUBLISH", "order:created", '{"id":7}']);
|
||||
expect(dec.decode(bytes)).toBe(
|
||||
'*3\r\n$7\r\nPUBLISH\r\n$13\r\norder:created\r\n$8\r\n{"id":7}\r\n',
|
||||
);
|
||||
});
|
||||
|
||||
test("parseReply reads a Redis message push", () => {
|
||||
const wire = enc.encode("*3\r\n$7\r\nmessage\r\n$5\r\ntopic\r\n$5\r\nhello\r\n");
|
||||
const r = parseReply(wire);
|
||||
expect(r).not.toBeNull();
|
||||
expect(r!.value).toEqual(["message", "topic", "hello"]);
|
||||
expect(r!.next).toBe(wire.length);
|
||||
});
|
||||
|
||||
test("parseReply reads a pmessage push (pattern, channel, payload)", () => {
|
||||
const wire = enc.encode(
|
||||
"*4\r\n$8\r\npmessage\r\n$6\r\norder:*\r\n$13\r\norder:created\r\n$2\r\n{}\r\n".replace(
|
||||
"$6\r\norder:*",
|
||||
"$7\r\norder:*",
|
||||
),
|
||||
);
|
||||
const r = parseReply(wire)!;
|
||||
expect(r.value).toEqual(["pmessage", "order:*", "order:created", "{}"]);
|
||||
});
|
||||
|
||||
test("parseReply returns null for an incomplete buffer, then completes", () => {
|
||||
const full = enc.encode("*1\r\n$5\r\nhello\r\n");
|
||||
// Half the bytes → incomplete.
|
||||
expect(parseReply(full.subarray(0, 8))).toBeNull();
|
||||
// Full → parses.
|
||||
expect(parseReply(full)!.value).toEqual(["hello"]);
|
||||
});
|
||||
|
||||
test("parseReply handles integers and simple strings (subscribe confirmations)", () => {
|
||||
const sub = enc.encode("*3\r\n$9\r\nsubscribe\r\n$5\r\ntopic\r\n:1\r\n");
|
||||
expect(parseReply(sub)!.value).toEqual(["subscribe", "topic", 1]);
|
||||
const ok = enc.encode("+OK\r\n");
|
||||
expect(parseReply(ok)!.value).toBe("OK");
|
||||
});
|
||||
|
||||
test("concat joins byte chunks in order", () => {
|
||||
const joined = concat([enc.encode("ab"), enc.encode("cd")]);
|
||||
expect(dec.decode(joined)).toBe("abcd");
|
||||
});
|
||||
Reference in New Issue
Block a user