Skip to content

Commit aafbece

Browse files
authored
fix(pubsub): assign Message instance back to event.data.message (#1864)
* fix(pubsub): assign Message instance back to event.data.message The refactor in 01ed20c that replaced patchV1Compat with addV1Compat dropped the mutation of event.data.message, leaving it as a raw POJO without the .json getter. This caused event.data.message.json to return undefined instead of the parsed JSON payload. Add the missing assignment and regression tests that exercise the POJO-to-Message wrapping path the runtime actually delivers. * fix: lint error.
1 parent da64c26 commit aafbece

2 files changed

Lines changed: 110 additions & 0 deletions

File tree

spec/v2/providers/pubsub.spec.ts

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,114 @@ describe("onMessagePublished", () => {
220220
expect(result).to.deep.equal({ test: "data" });
221221
});
222222

223+
describe("event.data.message wrapping (POJO -> Message instance)", () => {
224+
const rawMessagePOJO = {
225+
messageId: "pojo-msg-id",
226+
data: Buffer.from(JSON.stringify({ regression: "test" })).toString("base64"),
227+
attributes: { env: "test" },
228+
orderingKey: "key1",
229+
publishTime: new Date().toISOString(),
230+
};
231+
232+
function makeRawEvent(
233+
message: any,
234+
subscription = "projects/aProject/subscriptions/aSub"
235+
): CloudEvent<any> {
236+
return {
237+
specversion: "1.0",
238+
source: "//pubsub.googleapis.com/projects/aProject/topics/topic",
239+
id: "raw-event-id",
240+
type: EVENT_TRIGGER.eventType,
241+
time: rawMessagePOJO.publishTime,
242+
data: { message, subscription },
243+
};
244+
}
245+
246+
it("should convert a raw POJO message into a Message instance on event.data.message", async () => {
247+
let capturedMessage: any;
248+
const func = pubsub.onMessagePublished("topic", (event) => {
249+
capturedMessage = event.data.message;
250+
});
251+
252+
// Pass a raw POJO, NOT a Message instance — this is what the runtime delivers
253+
await func(makeRawEvent({ ...rawMessagePOJO }));
254+
255+
expect(capturedMessage).to.be.an.instanceOf(pubsub.Message);
256+
});
257+
258+
it("should provide a working .json getter on event.data.message when input is a raw POJO", async () => {
259+
let json: unknown;
260+
const func = pubsub.onMessagePublished("topic", (event) => {
261+
json = event.data.message.json;
262+
});
263+
264+
await func(makeRawEvent({ ...rawMessagePOJO }));
265+
266+
expect(json).to.deep.equal({ regression: "test" });
267+
});
268+
269+
it("should preserve all Message fields when wrapping a raw POJO", async () => {
270+
let msg: any;
271+
const func = pubsub.onMessagePublished("topic", (event) => {
272+
msg = event.data.message;
273+
});
274+
275+
await func(makeRawEvent({ ...rawMessagePOJO }));
276+
277+
expect(msg.messageId).to.equal("pojo-msg-id");
278+
expect(msg.data).to.equal(rawMessagePOJO.data);
279+
expect(msg.attributes).to.deep.equal({ env: "test" });
280+
expect(msg.orderingKey).to.equal("key1");
281+
expect(msg.publishTime).to.equal(rawMessagePOJO.publishTime);
282+
});
283+
284+
it("should not re-wrap if event.data.message is already a Message instance", async () => {
285+
const original = new pubsub.Message(rawMessagePOJO);
286+
let capturedMessage: any;
287+
const func = pubsub.onMessagePublished("topic", (event) => {
288+
capturedMessage = event.data.message;
289+
});
290+
291+
await func(makeRawEvent(original));
292+
293+
expect(capturedMessage).to.equal(original); // same reference
294+
expect(capturedMessage.json).to.deep.equal({ regression: "test" });
295+
});
296+
297+
it("should throw on a malformed event without a message property", async () => {
298+
const func = pubsub.onMessagePublished("topic", () => undefined);
299+
const badEvent: CloudEvent<any> = {
300+
specversion: "1.0",
301+
source: "//pubsub.googleapis.com/projects/aProject/topics/topic",
302+
id: "bad-event",
303+
type: EVENT_TRIGGER.eventType,
304+
time: new Date().toISOString(),
305+
data: { subscription: "sub" }, // no message!
306+
};
307+
308+
try {
309+
await func(badEvent);
310+
expect.fail("should have thrown");
311+
} catch (err: any) {
312+
expect(err.message).to.match(/missing 'message' property/i);
313+
}
314+
});
315+
316+
it("should make event.data.message.json and event.message.json return the same value", async () => {
317+
let v2Json: unknown;
318+
let v1Json: unknown;
319+
const func = pubsub.onMessagePublished("topic", (event) => {
320+
v2Json = event.data.message.json;
321+
v1Json = (event as any).message.json;
322+
});
323+
324+
await func(makeRawEvent({ ...rawMessagePOJO }));
325+
326+
expect(v2Json).to.deep.equal({ regression: "test" });
327+
expect(v1Json).to.deep.equal({ regression: "test" });
328+
});
329+
});
330+
223331
describe("v1-compatible getters", () => {
224332
let capturedEvent: any;
225333
const messageData = {

src/v2/providers/pubsub.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,8 @@ export function onMessagePublished<T = any>(
346346
pubsubData.message instanceof Message
347347
? pubsubData.message
348348
: new Message<T>(pubsubData.message);
349+
350+
(pubsubData as any).message = v2Message;
349351
} else {
350352
throw new Error("Malformed Pub/Sub event: missing 'message' property.");
351353
}

0 commit comments

Comments
 (0)