Skip to content

Commit 2dd6034

Browse files
committed
Refactor NewsPassID Lambda implementation by removing the old index.js, adding TypeScript support, and implementing a new handler with improved segment processing and error handling. Introduce unit tests for the new functionality and update dependencies in package.json and package-lock.json.
1 parent ca396b7 commit 2dd6034

18 files changed

Lines changed: 20331 additions & 277 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
# Dependencies
66
/node_modules
7+
/lambda/node_modules
78
/.pnp
89
.pnp.js
910

lambda/src/index.js

Lines changed: 0 additions & 228 deletions
This file was deleted.

lambda/src/index.test.ts

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import { handler } from './index';
2+
import { S3 } from 'aws-sdk';
3+
import { APIGatewayProxyEvent } from 'aws-lambda';
4+
import { Request, AWSError, Response } from 'aws-sdk/lib/core';
5+
import { PromiseResult } from 'aws-sdk/lib/request';
6+
7+
interface MockS3Response<T> extends Request<T, AWSError> {
8+
promise: () => Promise<PromiseResult<T, AWSError>>;
9+
}
10+
11+
jest.mock('aws-sdk', () => {
12+
const mockS3 = {
13+
getObject: jest.fn(),
14+
putObject: jest.fn()
15+
};
16+
return {
17+
S3: jest.fn(() => mockS3)
18+
};
19+
});
20+
21+
describe('NewsPassID Lambda Handler', () => {
22+
const mockS3 = new S3() as jest.Mocked<S3>;
23+
24+
beforeEach(() => {
25+
jest.clearAllMocks();
26+
process.env.STORAGE_BUCKET = 'test-bucket';
27+
process.env.ID_FOLDER = 'newspassid';
28+
});
29+
30+
it('should process valid request and return success', async () => {
31+
// Mock S3 responses
32+
mockS3.getObject.mockReturnValue({
33+
promise: () => Promise.resolve({
34+
Body: Buffer.from('segments,expire_timestamp\nsegment1,9999999999999'),
35+
$response: {} as Response<S3.GetObjectOutput, AWSError>
36+
})
37+
} as MockS3Response<S3.GetObjectOutput>);
38+
mockS3.putObject.mockReturnValue({
39+
promise: () => Promise.resolve({
40+
$response: {} as Response<S3.PutObjectOutput, AWSError>
41+
})
42+
} as MockS3Response<S3.PutObjectOutput>);
43+
44+
const event: Partial<APIGatewayProxyEvent> = {
45+
body: JSON.stringify({
46+
id: 'publisher-123',
47+
timestamp: 1234567890,
48+
url: 'https://example.com',
49+
consentString: 'consent123',
50+
previousId: 'publisher-122',
51+
publisherSegments: ['seg1', 'seg2']
52+
}),
53+
headers: {
54+
origin: 'https://example.com'
55+
}
56+
};
57+
58+
const response = await handler(event as APIGatewayProxyEvent);
59+
expect(response.statusCode).toBe(200);
60+
expect(JSON.parse(response.body)).toEqual({
61+
success: true,
62+
id: 'publisher-123',
63+
segments: ['segment1']
64+
});
65+
66+
// Verify S3 calls
67+
expect(mockS3.putObject).toHaveBeenCalledTimes(2);
68+
expect(mockS3.putObject).toHaveBeenCalledWith(
69+
expect.objectContaining({
70+
Bucket: 'test-bucket',
71+
Key: 'newspassid/publisher/example.com/publisher-123/1234567890.csv',
72+
ContentType: 'text/csv'
73+
})
74+
);
75+
});
76+
77+
it('should handle missing required fields', async () => {
78+
const event: Partial<APIGatewayProxyEvent> = {
79+
body: JSON.stringify({
80+
id: 'publisher-123',
81+
timestamp: 1234567890
82+
// Missing url and consentString
83+
})
84+
};
85+
86+
const response = await handler(event as APIGatewayProxyEvent);
87+
expect(response.statusCode).toBe(400);
88+
expect(JSON.parse(response.body)).toEqual({
89+
success: false,
90+
error: 'Missing required fields. All requests must include id, timestamp, url, and consentString.'
91+
});
92+
});
93+
94+
it('should handle invalid ID format', async () => {
95+
const event: Partial<APIGatewayProxyEvent> = {
96+
body: JSON.stringify({
97+
id: 'invalid-id-without-publisher-prefix',
98+
timestamp: 1234567890,
99+
url: 'https://example.com',
100+
consentString: 'consent123'
101+
})
102+
};
103+
104+
const response = await handler(event as APIGatewayProxyEvent);
105+
expect(response.statusCode).toBe(400);
106+
expect(JSON.parse(response.body)).toEqual({
107+
success: false,
108+
error: 'Invalid ID format'
109+
});
110+
});
111+
112+
it('should handle S3 errors gracefully', async () => {
113+
mockS3.getObject.mockReturnValue({
114+
promise: () => Promise.reject(new Error('S3 Error'))
115+
} as MockS3Response<S3.GetObjectOutput>);
116+
117+
const event: Partial<APIGatewayProxyEvent> = {
118+
body: JSON.stringify({
119+
id: 'publisher-123',
120+
timestamp: 1234567890,
121+
url: 'https://example.com',
122+
consentString: 'consent123'
123+
})
124+
};
125+
126+
const response = await handler(event as APIGatewayProxyEvent);
127+
expect(response.statusCode).toBe(500);
128+
expect(JSON.parse(response.body)).toEqual({
129+
success: false,
130+
error: 'Internal server error'
131+
});
132+
});
133+
});

0 commit comments

Comments
 (0)