Skip to content

Commit 2331380

Browse files
saby1101claude
andcommitted
chore: dependency upgrades and add comprehensive test suite
- Update AWS SDK packages to ^3.873.0 - Update Azure packages (@azure/identity to ^4.11.1, @azure/storage-blob to ^12.28.0) - Update Google Cloud packages (@google-cloud/pubsub to ^5.2.0, @google-cloud/storage to ^7.17.0) - Update rabbitmq-client to ^5.0.5 - Update dev dependencies (Node types, Jest, lint-staged, ts-jest, TypeScript) - Add comprehensive test coverage for event-bus, file-store, integration, and utils modules 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent be4085d commit 2331380

6 files changed

Lines changed: 1485 additions & 12 deletions

File tree

package.json

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,33 +28,33 @@
2828
"LICENSE"
2929
],
3030
"dependencies": {
31-
"@aws-sdk/client-s3": "^3.844.0",
32-
"@aws-sdk/credential-provider-node": "^3.844.0",
33-
"@azure/identity": "^4.10.2",
31+
"@aws-sdk/client-s3": "^3.873.0",
32+
"@aws-sdk/credential-provider-node": "^3.873.0",
33+
"@azure/identity": "^4.11.1",
3434
"@azure/service-bus": "^7.9.5",
35-
"@azure/storage-blob": "^12.27.0",
36-
"@google-cloud/pubsub": "^5.1.0",
37-
"@google-cloud/storage": "^7.16.0",
35+
"@azure/storage-blob": "^12.28.0",
36+
"@google-cloud/pubsub": "^5.2.0",
37+
"@google-cloud/storage": "^7.17.0",
3838
"fastify-plugin": "^5.0.1",
3939
"mnemonist": "^0.40.3",
4040
"prom-client": "^15.1.3",
41-
"rabbitmq-client": "^5.0.4"
41+
"rabbitmq-client": "^5.0.5"
4242
},
4343
"peerDependencies": {
4444
"fastify": "^3.0.0 || ^4.0.0 || ^5.0.0"
4545
},
4646
"devDependencies": {
4747
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
4848
"@types/jest": "^30.0.0",
49-
"@types/node": "^24.0.13",
49+
"@types/node": "^24.3.0",
5050
"husky": "^9.1.7",
51-
"jest": "^30.0.4",
52-
"lint-staged": "^16.1.2",
51+
"jest": "^30.0.5",
52+
"lint-staged": "^16.1.5",
5353
"npm-run-all": "^4.1.5",
5454
"prettier": "^3.6.2",
5555
"rimraf": "^6.0.1",
56-
"ts-jest": "^29.4.0",
56+
"ts-jest": "^29.4.1",
5757
"ts-node": "^10.9.2",
58-
"typescript": "^5.8.3"
58+
"typescript": "^5.9.2"
5959
}
6060
}

src/event-bus/index.spec.ts

Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
import Fastify from "fastify";
2+
import EventBusPlugin from "./index";
3+
import { EventBusOptions, EventHandler } from "./interfaces";
4+
5+
describe("EventBus Plugin", () => {
6+
let fastify: ReturnType<typeof Fastify>;
7+
let mockValidateMsg: jest.Mock;
8+
let mockProcessError: jest.Mock;
9+
let mockHandler: EventHandler;
10+
11+
beforeEach(() => {
12+
fastify = Fastify({ logger: false });
13+
mockValidateMsg = jest.fn();
14+
mockProcessError = jest.fn().mockReturnValue({ err: new Error("test"), status: 500 });
15+
mockHandler = jest.fn().mockResolvedValue(undefined);
16+
});
17+
18+
afterEach(async () => {
19+
try {
20+
await fastify.close();
21+
} catch (error) {
22+
// Ignore errors from fastify already being closed
23+
if (!error.message.includes('already been closed')) {
24+
throw error;
25+
}
26+
}
27+
});
28+
29+
describe("Plugin Registration", () => {
30+
it("should register with in-process bus type (default)", async () => {
31+
const options: EventBusOptions = {
32+
busType: "in-process",
33+
handlers: [{
34+
file: "test.ts",
35+
handlers: { testEvent: mockHandler }
36+
}],
37+
validateMsg: mockValidateMsg,
38+
processError: mockProcessError,
39+
};
40+
41+
await fastify.register(EventBusPlugin, options);
42+
expect(fastify.EventBus).toBeDefined();
43+
});
44+
45+
it("should require proper environment variables for rabbitmq", async () => {
46+
// Test that rabbitmq registration fails without required env vars
47+
const options: EventBusOptions = {
48+
busType: "rabbitmq",
49+
handlers: [],
50+
validateMsg: mockValidateMsg,
51+
processError: mockProcessError,
52+
};
53+
54+
await expect(fastify.register(EventBusPlugin, options)).rejects.toThrow();
55+
});
56+
57+
it("should register with gcp-pubsub bus type", async () => {
58+
process.env.EVENT_TOPIC = "test-topic";
59+
60+
const options: EventBusOptions = {
61+
busType: "gcp-pubsub",
62+
topic: "test-topic",
63+
handlers: [{
64+
file: "test.ts",
65+
handlers: { testEvent: mockHandler }
66+
}],
67+
validateMsg: mockValidateMsg,
68+
processError: mockProcessError,
69+
};
70+
71+
await fastify.register(EventBusPlugin, options);
72+
expect(fastify.EventBus).toBeDefined();
73+
74+
delete process.env.EVENT_TOPIC;
75+
});
76+
77+
it("should register with azure-servicebus bus type", async () => {
78+
process.env.EVENT_TOPIC = "test-topic";
79+
80+
const options: EventBusOptions = {
81+
busType: "azure-servicebus",
82+
namespace: "test-namespace",
83+
topic: "test-topic",
84+
handlers: [{
85+
file: "test.ts",
86+
handlers: { testEvent: mockHandler }
87+
}],
88+
validateMsg: mockValidateMsg,
89+
processError: mockProcessError,
90+
};
91+
92+
await fastify.register(EventBusPlugin, options);
93+
expect(fastify.EventBus).toBeDefined();
94+
95+
delete process.env.EVENT_TOPIC;
96+
});
97+
98+
it("should throw error for azure-servicebus without namespace", async () => {
99+
const options: EventBusOptions = {
100+
busType: "azure-servicebus",
101+
handlers: [{
102+
file: "test.ts",
103+
handlers: { testEvent: mockHandler }
104+
}],
105+
validateMsg: mockValidateMsg,
106+
processError: mockProcessError,
107+
};
108+
109+
await expect(fastify.register(EventBusPlugin, options)).rejects.toThrow(
110+
"Azure ServiceBus needs the namespace specified"
111+
);
112+
});
113+
});
114+
115+
describe("Event Publish Route", () => {
116+
beforeEach(async () => {
117+
const options: EventBusOptions = {
118+
busType: "in-process",
119+
handlers: [{
120+
file: "test.ts",
121+
handlers: { testEvent: mockHandler }
122+
}],
123+
validateMsg: mockValidateMsg,
124+
processError: mockProcessError,
125+
};
126+
127+
await fastify.register(EventBusPlugin, options);
128+
});
129+
130+
it("should register publish route by default", async () => {
131+
const response = await fastify.inject({
132+
method: "POST",
133+
url: "/event-bus/publish/testEvent",
134+
payload: { test: "data" }
135+
});
136+
137+
expect(response.statusCode).toBe(200);
138+
expect(response.body).toBe("OK");
139+
});
140+
141+
it("should handle string payload via query param", async () => {
142+
const response = await fastify.inject({
143+
method: "POST",
144+
url: "/event-bus/publish/testEvent?stringPayload=test-string",
145+
payload: {}
146+
});
147+
148+
expect(response.statusCode).toBe(200);
149+
expect(response.body).toBe("OK");
150+
});
151+
152+
it("should handle integer payload via query param", async () => {
153+
const response = await fastify.inject({
154+
method: "POST",
155+
url: "/event-bus/publish/testEvent?integerPayload=123",
156+
payload: {}
157+
});
158+
159+
expect(response.statusCode).toBe(200);
160+
expect(response.body).toBe("OK");
161+
});
162+
163+
it("should not register publish route when disabled", async () => {
164+
const fastifyDisabled = Fastify({ logger: false });
165+
166+
const options: EventBusOptions = {
167+
busType: "in-process",
168+
handlers: [{
169+
file: "test.ts",
170+
handlers: { testEvent: mockHandler }
171+
}],
172+
validateMsg: mockValidateMsg,
173+
processError: mockProcessError,
174+
disableEventPublishRoute: true,
175+
};
176+
177+
await fastifyDisabled.register(EventBusPlugin, options);
178+
179+
const response = await fastifyDisabled.inject({
180+
method: "POST",
181+
url: "/event-bus/publish/testEvent",
182+
payload: { test: "data" }
183+
});
184+
185+
expect(response.statusCode).toBe(404);
186+
await fastifyDisabled.close();
187+
});
188+
});
189+
190+
describe("EventBus Decorator", () => {
191+
beforeEach(async () => {
192+
const options: EventBusOptions = {
193+
busType: "in-process",
194+
handlers: [{
195+
file: "test.ts",
196+
handlers: { testEvent: mockHandler }
197+
}],
198+
validateMsg: mockValidateMsg,
199+
processError: mockProcessError,
200+
};
201+
202+
await fastify.register(EventBusPlugin, options);
203+
});
204+
205+
it("should provide EventBus on fastify instance", () => {
206+
expect(fastify.EventBus).toBeDefined();
207+
expect(typeof fastify.EventBus.publish).toBe("function");
208+
});
209+
210+
it("should allow publishing events programmatically", () => {
211+
expect(() => {
212+
fastify.EventBus.publish("testEvent", { test: "data" });
213+
}).not.toThrow();
214+
});
215+
216+
it("should allow publishing events with delay", () => {
217+
expect(() => {
218+
fastify.EventBus.publish("testEvent", { test: "data" }, 1000);
219+
}).not.toThrow();
220+
});
221+
});
222+
223+
describe("Configuration Options", () => {
224+
it("should handle empty handlers array", async () => {
225+
const options: EventBusOptions = {
226+
busType: "in-process",
227+
handlers: [],
228+
validateMsg: mockValidateMsg,
229+
processError: mockProcessError,
230+
};
231+
232+
await fastify.register(EventBusPlugin, options);
233+
expect(fastify.EventBus).toBeDefined();
234+
});
235+
236+
it("should handle multiple handler files", async () => {
237+
const handler1: EventHandler = jest.fn().mockResolvedValue(undefined);
238+
const handler2: EventHandler = jest.fn().mockResolvedValue(undefined);
239+
240+
const options: EventBusOptions = {
241+
busType: "in-process",
242+
handlers: [
243+
{
244+
file: "handlers1.ts",
245+
handlers: { event1: handler1 }
246+
},
247+
{
248+
file: "handlers2.ts",
249+
handlers: { event2: handler2 }
250+
}
251+
],
252+
validateMsg: mockValidateMsg,
253+
processError: mockProcessError,
254+
};
255+
256+
await fastify.register(EventBusPlugin, options);
257+
expect(fastify.EventBus).toBeDefined();
258+
});
259+
260+
it("should handle topic and namespace options", async () => {
261+
const options: EventBusOptions = {
262+
busType: "in-process",
263+
topic: "test-topic",
264+
namespace: "test-namespace",
265+
handlers: [{
266+
file: "test.ts",
267+
handlers: { testEvent: mockHandler }
268+
}],
269+
validateMsg: mockValidateMsg,
270+
processError: mockProcessError,
271+
};
272+
273+
await fastify.register(EventBusPlugin, options);
274+
expect(fastify.EventBus).toBeDefined();
275+
});
276+
277+
it("should handle actionConcurrency option", async () => {
278+
const options: EventBusOptions = {
279+
busType: "in-process",
280+
handlers: [{
281+
file: "test.ts",
282+
handlers: { testEvent: mockHandler }
283+
}],
284+
validateMsg: mockValidateMsg,
285+
processError: mockProcessError,
286+
actionConcurrency: 5,
287+
};
288+
289+
await fastify.register(EventBusPlugin, options);
290+
expect(fastify.EventBus).toBeDefined();
291+
});
292+
});
293+
});

0 commit comments

Comments
 (0)