Skip to content

Commit 9433c4c

Browse files
committed
adding batch test
1 parent 7e1d60f commit 9433c4c

File tree

7 files changed

+164
-50
lines changed

7 files changed

+164
-50
lines changed

lambdas/sftp-letters/src/__tests__/app/send.test.ts

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { mock } from 'jest-mock-extended';
22
import { TemplateRepository } from '../../infra/template-repository';
33
import { UserDataRepository } from '../../infra/user-data-repository';
44
import { App } from '../../app/send';
5-
import { Batch, Manifest } from '../../domain/batch';
5+
import { SyntheticBatch, Manifest } from '../../domain/synthetic-batch';
66
import { SftpClient } from '../../infra/sftp-client';
77
import { Readable } from 'node:stream';
88
import { mockTestDataCsv, streamToString } from '../helpers';
@@ -18,16 +18,16 @@ const testDataVersion = 'test-data-version-id';
1818
function setup() {
1919
const userDataRepository = mock<UserDataRepository>();
2020
const templateRepository = mock<TemplateRepository>();
21-
const batch = mock<Batch>();
22-
const { logger } = createMockLogger();
21+
const syntheticBatch = mock<SyntheticBatch>();
22+
const { logger, logMessages } = createMockLogger();
2323

2424
const sftpClient = mock<SftpClient>();
2525

2626
const app = new App(
2727
userDataRepository,
2828
templateRepository,
2929
sftpEnvironment,
30-
batch,
30+
syntheticBatch,
3131
logger
3232
);
3333

@@ -36,10 +36,11 @@ function setup() {
3636
mocks: {
3737
userDataRepository,
3838
templateRepository,
39-
batch,
39+
syntheticBatch,
4040
logger,
4141
sftpClient,
4242
},
43+
logMessages,
4344
};
4445
}
4546

@@ -128,18 +129,18 @@ describe('App', () => {
128129

129130
const testDataCsv = mockTestDataCsv(['custom1', 'custom2'], testData);
130131

131-
mocks.batch.getId.mockReturnValueOnce(batchId);
132+
mocks.syntheticBatch.getId.mockReturnValueOnce(batchId);
132133

133134
mocks.userDataRepository.get.mockResolvedValueOnce({
134135
testData: testDataCsv,
135136
pdf,
136137
});
137138

138-
mocks.batch.buildBatch.mockReturnValueOnce(batchData);
139+
mocks.syntheticBatch.buildBatch.mockReturnValueOnce(batchData);
139140

140-
mocks.batch.getHeader.mockReturnValueOnce(batchColumns.join(','));
141+
mocks.syntheticBatch.getHeader.mockReturnValueOnce(batchColumns.join(','));
141142

142-
mocks.batch.buildManifest.mockReturnValueOnce(manifestData);
143+
mocks.syntheticBatch.buildManifest.mockReturnValueOnce(manifestData);
143144

144145
// manifest doesn't already exist
145146
mocks.sftpClient.exists.mockResolvedValueOnce(false);
@@ -154,18 +155,20 @@ describe('App', () => {
154155
testDataVersion
155156
);
156157

157-
expect(mocks.batch.buildBatch).toHaveBeenCalledTimes(1);
158-
expect(mocks.batch.buildBatch).toHaveBeenCalledWith(
158+
expect(mocks.syntheticBatch.buildBatch).toHaveBeenCalledTimes(1);
159+
expect(mocks.syntheticBatch.buildBatch).toHaveBeenCalledWith(
159160
templateId,
160161
personalisationFields,
161162
testData
162163
);
163164

164-
expect(mocks.batch.getHeader).toHaveBeenCalledTimes(1);
165-
expect(mocks.batch.getHeader).toHaveBeenCalledWith(personalisationFields);
165+
expect(mocks.syntheticBatch.getHeader).toHaveBeenCalledTimes(1);
166+
expect(mocks.syntheticBatch.getHeader).toHaveBeenCalledWith(
167+
personalisationFields
168+
);
166169

167-
expect(mocks.batch.buildManifest).toHaveBeenCalledTimes(1);
168-
expect(mocks.batch.buildManifest).toHaveBeenCalledWith(
170+
expect(mocks.syntheticBatch.buildManifest).toHaveBeenCalledTimes(1);
171+
expect(mocks.syntheticBatch.buildManifest).toHaveBeenCalledWith(
169172
templateId,
170173
batchId,
171174
batchCsv
@@ -239,7 +242,7 @@ describe('App', () => {
239242
});
240243

241244
test('exist early and does not send if the manifest is already in the SFTP server', async () => {
242-
const { app, mocks } = setup();
245+
const { app, mocks, logMessages } = setup();
243246

244247
const personalisationFields = ['pdsField'];
245248
const batchColumns = ['clientRef', 'template', ...personalisationFields];
@@ -287,44 +290,47 @@ describe('App', () => {
287290
md5sum: batchHash,
288291
};
289292

290-
mocks.batch.getId.mockReturnValueOnce(batchId);
293+
mocks.syntheticBatch.getId.mockReturnValueOnce(batchId);
291294

292295
mocks.userDataRepository.get.mockResolvedValueOnce({
293296
testData: undefined,
294297
pdf,
295298
});
296299

297-
mocks.batch.buildBatch.mockReturnValueOnce(batchData);
300+
mocks.syntheticBatch.buildBatch.mockReturnValueOnce(batchData);
298301

299-
mocks.batch.getHeader.mockReturnValueOnce(batchColumns.join(','));
302+
mocks.syntheticBatch.getHeader.mockReturnValueOnce(batchColumns.join(','));
300303

301-
mocks.batch.buildManifest.mockReturnValueOnce(manifestData);
304+
mocks.syntheticBatch.buildManifest.mockReturnValueOnce(manifestData);
302305

303306
// manifest already exists
304307
mocks.sftpClient.exists.mockResolvedValueOnce('-');
305308

306309
await app.send(JSON.stringify(event), mocks.sftpClient, baseUploadDir);
307310

308-
expect(mocks.userDataRepository.get).toHaveBeenCalledTimes(1);
309-
expect(mocks.userDataRepository.get).toHaveBeenCalledWith(
310-
owner,
311-
templateId,
312-
pdfVersion,
313-
testDataVersion
311+
expect(logMessages).toContainEqual(
312+
expect.objectContaining({
313+
level: 'warn',
314+
message: 'Manifest already exists, assuming duplicate event',
315+
})
314316
);
315317

316-
expect(mocks.batch.buildBatch).toHaveBeenCalledTimes(1);
317-
expect(mocks.batch.buildBatch).toHaveBeenCalledWith(
318+
expect(mocks.userDataRepository.get).toHaveBeenCalledTimes(1);
319+
320+
expect(mocks.syntheticBatch.buildBatch).toHaveBeenCalledTimes(1);
321+
expect(mocks.syntheticBatch.buildBatch).toHaveBeenCalledWith(
318322
templateId,
319323
personalisationFields,
320324
undefined
321325
);
322326

323-
expect(mocks.batch.getHeader).toHaveBeenCalledTimes(1);
324-
expect(mocks.batch.getHeader).toHaveBeenCalledWith(personalisationFields);
327+
expect(mocks.syntheticBatch.getHeader).toHaveBeenCalledTimes(1);
328+
expect(mocks.syntheticBatch.getHeader).toHaveBeenCalledWith(
329+
personalisationFields
330+
);
325331

326-
expect(mocks.batch.buildManifest).toHaveBeenCalledTimes(1);
327-
expect(mocks.batch.buildManifest).toHaveBeenCalledWith(
332+
expect(mocks.syntheticBatch.buildManifest).toHaveBeenCalledTimes(1);
333+
expect(mocks.syntheticBatch.buildManifest).toHaveBeenCalledWith(
328334
templateId,
329335
batchId,
330336
batchCsv

lambdas/sftp-letters/src/__tests__/domain/batch.test.ts

Whitespace-only changes.
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import { SyntheticBatch } from '../../domain/synthetic-batch';
2+
3+
describe('SyntheticBatch', () => {
4+
describe('buildBatch', () => {
5+
test('merges mock PDS data, user test data, and other details into a synthetic batch', () => {
6+
let mockIdIdx = 0;
7+
const mockGenerateId = () => {
8+
mockIdIdx += 1;
9+
return mockIdIdx.toString();
10+
};
11+
12+
const syntheticBatch = new SyntheticBatch(
13+
mockGenerateId,
14+
() => new Date('2025-04-10T07:38:41.502Z')
15+
);
16+
17+
const userData = [
18+
{ userData1: 'a', userData2: 'b' },
19+
{ userData1: 'c d', userData2: 'e f' },
20+
{ userData1: 'ghi', userData2: 'jklmn' },
21+
];
22+
23+
const templateId = '84755bd6-3cc1-4759-98b9-d1dbd8b3eff8';
24+
25+
const fieldsInTemplate = [
26+
'date',
27+
'nhsNumber',
28+
'fullName',
29+
'firstName',
30+
'address_line_1',
31+
'address_line_2',
32+
'address_line_3',
33+
'address_line_4',
34+
'address_line_5',
35+
'address_line_6',
36+
'address_line_7',
37+
'userData1',
38+
'userData2',
39+
];
40+
41+
const batch = syntheticBatch.buildBatch(
42+
templateId,
43+
fieldsInTemplate,
44+
userData
45+
);
46+
47+
expect(batch).toEqual([
48+
{
49+
address_line_1: 'Ms A A AAAAAAAAAABBBBBBBBBBDDDDDDDDDDEEEEE',
50+
address_line_2: '14 Dean Garden Rise',
51+
address_line_3: '?!""#$%&\'()*+,-./0123456789',
52+
address_line_4: 'HIGH WYCOMBE:;<=',
53+
address_line_5: 'HP11 1RE',
54+
address_line_6: '',
55+
address_line_7: '',
56+
clientRef: '1_2_2025 08:38:41 GMT+0100 (British Summer Time)',
57+
date: '10 April 2025',
58+
firstName: 'AAAAAAAAAABBBBBBBBBBDDDDDDDDDDEEEEE',
59+
fullName:
60+
'Ms AAAAAAAAAABBBBBBBBBBDDDDDDDDDDEEEEE AAAAAAAAAABBBBBBBBBBDDDDDDDDDDEEEEE AAAAAAAAAABBBBBBBBBBDDDDDDDDDDEEEEE',
61+
nhsNumber: '9464416181',
62+
template: '84755bd6-3cc1-4759-98b9-d1dbd8b3eff8',
63+
userData1: 'a',
64+
userData2: 'b',
65+
},
66+
{
67+
address_line_1: 'MR John Barry LESTER',
68+
address_line_2: '1 PAUL LANE',
69+
address_line_3: 'APPLEBY',
70+
address_line_4: 'SCUNTHORPE',
71+
address_line_5: 'S HUMBERSIDE',
72+
address_line_6: 'DN15 0AR',
73+
address_line_7: '',
74+
clientRef: '1_2_ 2025 08:38:41 GMT+0100 (British Summer Time)',
75+
date: '10 April 2025',
76+
firstName: 'John',
77+
fullName: 'MR John Barry LESTER',
78+
nhsNumber: '9728543417',
79+
template: '84755bd6-3cc1-4759-98b9-d1dbd8b3eff8',
80+
userData1: 'c d',
81+
userData2: 'e f',
82+
},
83+
{
84+
address_line_1: 'MR Louie NAPIER',
85+
address_line_2: 'c/o Wayne Shirt (CM Test)',
86+
address_line_3: '6th Floor',
87+
address_line_4: '7&8 Wellington Place',
88+
address_line_5: 'Leeds',
89+
address_line_6: 'West Yorkshire',
90+
address_line_7: 'LS1 4AP',
91+
clientRef: '1_2_ 2025 08:38:41 GMT+0100 (British Summer Time)',
92+
date: '10 April 2025',
93+
firstName: 'Louie',
94+
fullName: 'MR Louie NAPIER',
95+
nhsNumber: '9728543751',
96+
template: '84755bd6-3cc1-4759-98b9-d1dbd8b3eff8',
97+
userData1: 'ghi',
98+
userData2: 'jklmn',
99+
},
100+
]);
101+
});
102+
});
103+
});

lambdas/sftp-letters/src/app/send.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { SftpClient } from '../infra/sftp-client';
22
import type { UserDataRepository } from '../infra/user-data-repository';
33
import type { Logger } from 'nhs-notify-web-template-management-utils/logger';
4-
import type { Batch } from '../domain/batch';
4+
import type { SyntheticBatch } from '../domain/synthetic-batch';
55
import type { TemplateRepository } from '../infra/template-repository';
66
import { parseTestPersonalisation } from '../domain/test-data';
77
import { serialiseCsv } from '../infra/serialise-csv';
@@ -26,7 +26,7 @@ export class App {
2626
private readonly userDataRepository: UserDataRepository,
2727
private readonly templateRepository: TemplateRepository,
2828
private readonly sftpEnvironment: string,
29-
private readonly batch: Batch,
29+
private readonly batch: SyntheticBatch,
3030
private readonly logger: Logger
3131
) {}
3232
async send(eventBody: string, sftpClient: SftpClient, baseUploadDir: string) {

lambdas/sftp-letters/src/container-send.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { loadConfig } from './config/config';
66
import { App } from './app/send';
77
import { logger } from 'nhs-notify-web-template-management-utils/logger';
88
import { randomId } from './infra/ksuid-like-id';
9-
import { Batch } from './domain/batch';
9+
import { SyntheticBatch } from './domain/synthetic-batch';
1010
import { TemplateRepository } from './infra/template-repository';
1111
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
1212
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
@@ -47,7 +47,7 @@ export function createContainer() {
4747
ssmClient
4848
);
4949

50-
const batch = new Batch(randomId, () => new Date());
50+
const batch = new SyntheticBatch(randomId, () => new Date());
5151

5252
const app = new App(
5353
userDataRepository,

lambdas/sftp-letters/src/domain/batch.ts renamed to lambdas/sftp-letters/src/domain/synthetic-batch.ts

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export type Manifest = {
1212
md5sum: string;
1313
};
1414

15-
export class Batch {
15+
export class SyntheticBatch {
1616
constructor(
1717
private readonly randomId: () => string,
1818
private readonly getDate: () => Date
@@ -45,15 +45,6 @@ export class Batch {
4545
});
4646
}
4747

48-
getId(templateId: string, pdfVersion: string) {
49-
const pseudoRandomSegment = pdfVersion.replaceAll('-', '').slice(27);
50-
return `${templateId}-0000000000000_${pseudoRandomSegment}`;
51-
}
52-
53-
getHeader(fields: string[]) {
54-
return `clientRef,template,${fields.join(',')}`;
55-
}
56-
5748
private fieldValue(
5849
field: string,
5950
date: Date,
@@ -70,9 +61,22 @@ export class Batch {
7061
}
7162

7263
private clientRef(date: Date) {
73-
return [this.randomId(), this.randomId(), date.toString().slice(10)].join(
74-
'_'
75-
);
64+
console.log('D', date.getTime());
65+
66+
return [
67+
this.randomId(),
68+
this.randomId(),
69+
date.getTime().toString().slice(10),
70+
].join('_');
71+
}
72+
73+
getId(templateId: string, pdfVersion: string) {
74+
const pseudoRandomSegment = pdfVersion.replaceAll('-', '').slice(27);
75+
return `${templateId}-0000000000000_${pseudoRandomSegment}`;
76+
}
77+
78+
getHeader(fields: string[]) {
79+
return `clientRef,template,${fields.join(',')}`;
7680
}
7781

7882
buildManifest(

utils/test-helper-utils/src/mock-logger.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ export function createMockLogger() {
1212
transports: [
1313
new winston.transports.Stream({
1414
stream: new Writable({
15-
write: (msg) => {
15+
write: (msg, _, cb) => {
1616
logMessages.push(JSON.parse(msg));
17+
cb();
1718
},
1819
}),
1920
}),

0 commit comments

Comments
 (0)