@squiz/job-runner-lib 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/lib/domains/component/errors/JobError.spec.d.ts +1 -0
- package/lib/domains/job/ParsePartitionKey/ParsePartitionKey.d.ts +2 -2
- package/lib/domains/job/ParsePartitionKey/ParsePartitionKey.types.d.ts +5 -0
- package/lib/domains/job/S3Repository/JobDetailsRepository.d.ts +1 -2
- package/lib/domains/job/S3Repository/JobDetailsRepository.spec.d.ts +1 -1
- package/lib/domains/job/S3Repository/JobUploadsRepository.d.ts +16 -0
- package/lib/domains/job/{services/JobQueueService/JobQueueService.spec.d.ts → S3Repository/JobUploadsRepository.spec.d.ts} +1 -1
- package/lib/domains/job/S3Repository/S3RepositoryBase.d.ts +12 -5
- package/lib/domains/job/S3Repository/index.d.ts +2 -1
- package/lib/domains/job/constants/InjectTokens.d.ts +8 -0
- package/lib/domains/job/constants/JobExecutionStatus.constants.d.ts +2 -1
- package/lib/domains/job/constants/Repository.constants.d.ts +3 -3
- package/lib/domains/job/constants/RetryConfig.constants.d.ts +21 -0
- package/lib/domains/job/index.d.ts +6 -4
- package/lib/domains/job/manifest/JobManifestTypes.d.ts +7 -6
- package/lib/domains/job/model/Base/Base.d.ts +10 -5
- package/lib/domains/job/model/Job/Job.d.ts +9 -6
- package/lib/domains/job/model/JobContext/JobContext.d.ts +6 -5
- package/lib/domains/job/model/JobExecution/JobExecution.d.ts +64 -9
- package/lib/domains/job/model/LogPayload/LogPayload.d.ts +21 -12
- package/lib/domains/job/model/LogPayload/index.d.ts +1 -0
- package/lib/domains/job/model/LogPayload/mocks/LogPayload.mock.d.ts +6 -0
- package/lib/domains/job/repository/AbstractRepository.d.ts +20 -11
- package/lib/domains/job/repository/JobContextRepository/JobContextRepository.d.ts +6 -7
- package/lib/domains/job/repository/JobExecutionRepository/JobExecutionRepository.d.ts +7 -17
- package/lib/domains/job/repository/JobExecutionRepository/JobExecutionRepository.spec.d.ts +1 -1
- package/lib/domains/job/repository/JobExecutionRepository/utils/convertDynamoDbItemToJobExecution/convertDynamoDbItemToJobExecution.d.ts +2 -0
- package/lib/domains/job/repository/JobExecutionRepository/utils/index.d.ts +1 -0
- package/lib/domains/job/repository/JobManifestRepository/JobManifestRepository.d.ts +5 -6
- package/lib/domains/job/repository/JobRepository/JobRepository.d.ts +6 -7
- package/lib/domains/job/repository/MultiTenantJobExecutionRepository/MultiTenantJobExecutionRepository.d.ts +9 -0
- package/lib/domains/job/repository/MultiTenantJobExecutionRepository/MultiTenantJobExecutionRepository.spec.d.ts +1 -0
- package/lib/domains/job/repository/index.d.ts +1 -0
- package/lib/domains/job/services/JobContextService/JobContextService.d.ts +6 -3
- package/lib/domains/job/services/JobExecutionTaskService/JobExecutionTaskService.d.ts +10 -6
- package/lib/domains/job/services/JobExecutionTaskService/JobExecutionTaskService.defs.d.ts +1 -3
- package/lib/domains/job/services/JobManifestService/JobManifestService.d.ts +0 -1
- package/lib/domains/job/services/JobStartQueueService/JobStartQueueService.d.ts +17 -0
- package/lib/domains/job/services/JobStartQueueService/JobStartQueueService.defs.d.ts +25 -0
- package/lib/domains/job/services/JobUploadService/utils/manifestValidator.d.ts +1 -2
- package/lib/domains/job/services/index.d.ts +2 -1
- package/lib/domains/manifest/services/ManifestServiceForDev.d.ts +0 -3
- package/lib/index.d.ts +1 -0
- package/lib/index.js +13 -13
- package/lib/index.js.map +4 -4
- package/lib/jest-global-setup.d.ts +6 -1
- package/lib/mocks/mockIoc.d.ts +3 -3
- package/lib/utils/buildJobRunnerModule/buildJobRunnerModule.d.ts +2 -0
- package/lib/utils/buildJobRunnerModule/buildJobRunnerModule.types.d.ts +14 -0
- package/lib/utils/index.d.ts +2 -0
- package/package.json +12 -11
- package/src/domains/component/errors/JobError.spec.ts +30 -0
- package/src/domains/component/errors/JobError.ts +8 -1
- package/src/domains/job/ParsePartitionKey/ParsePartitionKey.spec.ts +17 -8
- package/src/domains/job/ParsePartitionKey/ParsePartitionKey.ts +13 -16
- package/src/domains/job/ParsePartitionKey/ParsePartitionKey.types.ts +6 -0
- package/src/domains/job/S3Repository/JobDetailsRepository.spec.ts +47 -31
- package/src/domains/job/S3Repository/JobDetailsRepository.ts +7 -8
- package/src/domains/job/S3Repository/JobUploadsRepository.spec.ts +66 -0
- package/src/domains/job/S3Repository/JobUploadsRepository.ts +35 -0
- package/src/domains/job/S3Repository/S3RepositoryBase.spec.ts +13 -19
- package/src/domains/job/S3Repository/S3RepositoryBase.ts +24 -9
- package/src/domains/job/S3Repository/index.ts +2 -1
- package/src/domains/job/constants/InjectTokens.ts +8 -0
- package/src/domains/job/constants/JobExecutionStatus.constants.ts +1 -0
- package/src/domains/job/constants/Repository.constants.ts +3 -3
- package/src/domains/job/constants/RetryConfig.constants.ts +29 -0
- package/src/domains/job/core/pagination/services/PaginationService.spec.ts +3 -5
- package/src/domains/job/index.ts +6 -4
- package/src/domains/job/manifest/JobManifestTypes.ts +8 -6
- package/src/domains/job/manifest/mocks/JobManifest.mock.ts +2 -2
- package/src/domains/job/manifest/mocks/JobManifestDto.mock.ts +3 -2
- package/src/domains/job/manifest/mocks/JobManifestRecord.mock.ts +4 -3
- package/src/domains/job/model/Base/Base.ts +11 -5
- package/src/domains/job/model/Job/Job.ts +11 -6
- package/src/domains/job/model/Job/mocks/Job.mock.ts +2 -2
- package/src/domains/job/model/Job/mocks/JobDto.mock.ts +3 -2
- package/src/domains/job/model/Job/mocks/JobRecord.mock.ts +3 -2
- package/src/domains/job/model/JobContext/JobContext.ts +7 -5
- package/src/domains/job/model/JobContext/mocks/JobContext.mock.ts +2 -2
- package/src/domains/job/model/JobContext/mocks/JobContextDto.mock.ts +3 -2
- package/src/domains/job/model/JobContext/mocks/JobContextRecord.mock.ts +3 -2
- package/src/domains/job/model/JobExecution/JobExecution.ts +74 -9
- package/src/domains/job/model/JobExecution/mocks/JobExecution.mock.ts +7 -4
- package/src/domains/job/model/JobExecution/mocks/JobExecutionDto.mock.ts +32 -16
- package/src/domains/job/model/JobExecution/mocks/JobExecutionRecord.mock.ts +10 -4
- package/src/domains/job/model/LogPayload/LogPayload.ts +32 -11
- package/src/domains/job/model/LogPayload/index.ts +1 -0
- package/src/domains/job/model/LogPayload/mocks/LogPayload.mock.ts +21 -0
- package/src/domains/job/repository/AbstractRepository.ts +91 -59
- package/src/domains/job/repository/JobContextRepository/JobContextRepository.spec.ts +39 -49
- package/src/domains/job/repository/JobContextRepository/JobContextRepository.ts +33 -21
- package/src/domains/job/repository/JobExecutionRepository/JobExecutionRepository.spec.ts +343 -169
- package/src/domains/job/repository/JobExecutionRepository/JobExecutionRepository.ts +112 -141
- package/src/domains/job/repository/JobExecutionRepository/utils/convertDynamoDbItemToJobExecution/convertDynamoDbItemToJobExecution.ts +22 -0
- package/src/domains/job/repository/JobExecutionRepository/utils/index.ts +1 -0
- package/src/domains/job/repository/JobManifestRepository/JobManifestRepository.spec.ts +23 -38
- package/src/domains/job/repository/JobManifestRepository/JobManifestRepository.ts +29 -36
- package/src/domains/job/repository/JobRepository/JobRepository.spec.ts +72 -80
- package/src/domains/job/repository/JobRepository/JobRepository.ts +66 -70
- package/src/domains/job/repository/MultiTenantJobExecutionRepository/MultiTenantJobExecutionRepository.spec.ts +60 -0
- package/src/domains/job/repository/MultiTenantJobExecutionRepository/MultiTenantJobExecutionRepository.ts +42 -0
- package/src/domains/job/repository/index.ts +1 -0
- package/src/domains/job/services/JobContextService/JobContextService.spec.ts +73 -39
- package/src/domains/job/services/JobContextService/JobContextService.ts +37 -6
- package/src/domains/job/services/JobExecutionTaskService/JobExecutionTaskService.defs.ts +1 -3
- package/src/domains/job/services/JobExecutionTaskService/JobExecutionTaskService.spec.ts +113 -31
- package/src/domains/job/services/JobExecutionTaskService/JobExecutionTaskService.ts +101 -49
- package/src/domains/job/services/JobManifestService/JobManifestService.spec.ts +4 -41
- package/src/domains/job/services/JobManifestService/JobManifestService.ts +2 -8
- package/src/domains/job/services/JobStartQueueService/JobStartQueueService.defs.ts +27 -0
- package/src/domains/job/services/JobStartQueueService/JobStartQueueService.ts +42 -0
- package/src/domains/job/services/JobUploadService/JobUploadService.spec.ts +1 -1
- package/src/domains/job/services/JobUploadService/JobUploadService.ts +1 -1
- package/src/domains/job/services/JobUploadService/utils/manifestValidator.spec.ts +12 -25
- package/src/domains/job/services/JobUploadService/utils/manifestValidator.ts +2 -7
- package/src/domains/job/services/index.ts +2 -1
- package/src/domains/job/utils/SlackClient/SlackClient.spec.ts +0 -2
- package/src/domains/manifest/services/ManifestServiceForDev.spec.ts +1 -2
- package/src/domains/manifest/services/ManifestServiceForDev.ts +0 -4
- package/src/index.ts +1 -0
- package/src/jest-global-setup.ts +8 -4
- package/src/mocks/mockIoc.ts +18 -43
- package/src/utils/buildJobRunnerModule/buildJobRunnerModule.ts +81 -0
- package/src/utils/buildJobRunnerModule/buildJobRunnerModule.types.ts +13 -0
- package/src/utils/index.ts +2 -0
- package/lib/domains/job/S3Repository/S3Repository.d.ts +0 -15
- package/lib/domains/job/S3Repository/S3Repository.spec.d.ts +0 -5
- package/lib/domains/job/services/JobQueueService/JobQueueService.d.ts +0 -9
- package/lib/domains/job/services/JobQueueService/JobQueueService.defs.d.ts +0 -9
- package/src/custom-types.d.ts +0 -7
- package/src/domains/job/S3Repository/S3Repository.spec.ts +0 -50
- package/src/domains/job/S3Repository/S3Repository.ts +0 -27
- package/src/domains/job/services/JobQueueService/JobQueueService.defs.ts +0 -10
- package/src/domains/job/services/JobQueueService/JobQueueService.spec.ts +0 -190
- package/src/domains/job/services/JobQueueService/JobQueueService.ts +0 -60
|
@@ -5,168 +5,205 @@
|
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
7
|
AttributeValue,
|
|
8
|
+
BatchWriteItemCommand,
|
|
8
9
|
DynamoDBClient,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
GetItemCommand,
|
|
11
|
+
PutItemCommand,
|
|
12
|
+
QueryCommand,
|
|
12
13
|
QueryCommandInput,
|
|
13
|
-
|
|
14
|
+
UpdateItemCommand,
|
|
14
15
|
} from '@aws-sdk/client-dynamodb';
|
|
16
|
+
import { faker } from '@faker-js/faker';
|
|
17
|
+
import { AwsClientStub, mockClient } from 'aws-sdk-client-mock';
|
|
18
|
+
import 'aws-sdk-client-mock-jest';
|
|
15
19
|
import { initIocContainer, iocContainer } from '../../../../mocks/mockIoc';
|
|
16
|
-
import {
|
|
20
|
+
import { InjectTokens } from '../../constants/InjectTokens';
|
|
21
|
+
import { JOB_EXECUTION_STATUS } from '../../constants/JobExecutionStatus.constants';
|
|
22
|
+
import { ENTITY_TYPES } from '../../constants/Repository.constants';
|
|
17
23
|
import {
|
|
24
|
+
createMockClientGetResponse,
|
|
18
25
|
createMockClientPutResponse,
|
|
19
26
|
createMockClientScanResponse,
|
|
20
|
-
createMockClientGetResponse,
|
|
21
27
|
} from '../../core/dynamoClient.mock';
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import
|
|
25
|
-
import {
|
|
28
|
+
import { PaginationInfo } from '../../core/pagination/model/PaginationInfo';
|
|
29
|
+
import { PAGINATION_DIRECTION_TYPE_BEFORE } from '../../core/pagination/model/PaginationTypes';
|
|
30
|
+
import * as PaginationUtils from '../../core/pagination/utils/PaginationUtils';
|
|
31
|
+
import { JobExecution, UpdateJobExecutionParameters } from '../../model/JobExecution/JobExecution';
|
|
32
|
+
import { createMockJobExecution, createMockJobExecutions } from '../../model/JobExecution/mocks/JobExecution.mock';
|
|
26
33
|
import {
|
|
27
34
|
createMockJobExecutionDto,
|
|
28
35
|
createMockJobExecutionDtos,
|
|
29
36
|
} from '../../model/JobExecution/mocks/JobExecutionDto.mock';
|
|
30
37
|
import { JobExecutionRepository } from './JobExecutionRepository';
|
|
31
|
-
import * as PaginationUtils from '../../core/pagination/utils/PaginationUtils';
|
|
32
|
-
import { PaginationInfo } from '../../core/pagination/model/PaginationInfo';
|
|
33
|
-
import { PAGINATION_DIRECTION_TYPE_BEFORE } from '../../core/pagination/model/PaginationTypes';
|
|
34
38
|
|
|
35
|
-
|
|
36
|
-
initIocContainer(testLogger);
|
|
39
|
+
initIocContainer();
|
|
37
40
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// Inject JobRepository with a mocked client
|
|
45
|
-
iocContainer.rebind<DynamoDBClient>(DynamoDBClient).toConstantValue(mockClient);
|
|
41
|
+
describe('JobExecutionRepository', (): void => {
|
|
42
|
+
let dynamoClient: AwsClientStub<DynamoDBClient>;
|
|
43
|
+
let jobExecutionRepository: JobExecutionRepository;
|
|
44
|
+
let tenant: string;
|
|
45
|
+
let tableName: string;
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
dynamoClient = mockClient(DynamoDBClient);
|
|
49
|
+
dynamoClient.reset();
|
|
48
50
|
|
|
49
|
-
describe('JobExecutionRepository', (): void => {
|
|
50
|
-
beforeAll(() => {
|
|
51
51
|
jobExecutionRepository = iocContainer.get(JobExecutionRepository);
|
|
52
|
+
tenant = iocContainer.get(InjectTokens.Tenant);
|
|
53
|
+
tableName = iocContainer.get(InjectTokens.DynamoTableName);
|
|
52
54
|
});
|
|
53
55
|
|
|
54
56
|
describe('list', () => {
|
|
55
|
-
beforeEach(() => {
|
|
56
|
-
jest.resetAllMocks();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
57
|
it(`should return an empty list`, async (): Promise<void> => {
|
|
60
|
-
|
|
58
|
+
dynamoClient.on(QueryCommand).resolvesOnce(createMockClientScanResponse());
|
|
61
59
|
|
|
62
|
-
const response = await jobExecutionRepository.list({
|
|
63
|
-
|
|
60
|
+
const response = await jobExecutionRepository.list({
|
|
61
|
+
filters: { jobName: 'does-not-exist' },
|
|
62
|
+
});
|
|
64
63
|
expect(response).toStrictEqual([]);
|
|
64
|
+
expect(dynamoClient).toHaveReceivedCommandTimes(QueryCommand, 1);
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
it(`should return a list of existing job executions`, async (): Promise<void> => {
|
|
68
|
-
const
|
|
68
|
+
const mockJobExecution = createMockJobExecution();
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}),
|
|
70
|
+
dynamoClient.on(QueryCommand).resolvesOnce(
|
|
71
|
+
createMockClientScanResponse({
|
|
72
|
+
Items: [createMockJobExecutionDto(mockJobExecution)],
|
|
73
|
+
LastEvaluatedKey: undefined,
|
|
74
|
+
}),
|
|
76
75
|
);
|
|
77
76
|
|
|
78
77
|
const response = await jobExecutionRepository.list();
|
|
79
|
-
expect(
|
|
80
|
-
expect(
|
|
78
|
+
expect(response).toEqual([mockJobExecution]);
|
|
79
|
+
expect(dynamoClient).toHaveReceivedCommandWith(QueryCommand, {
|
|
80
|
+
ExclusiveStartKey: undefined,
|
|
81
|
+
ExpressionAttributeNames: { '#pk': 'pk' },
|
|
82
|
+
ExpressionAttributeValues: { ':pk': { S: `jobExecution~${tenant}` } },
|
|
83
|
+
IndexName: undefined,
|
|
84
|
+
KeyConditionExpression: '#pk = :pk',
|
|
85
|
+
ScanIndexForward: false,
|
|
86
|
+
TableName: tableName,
|
|
87
|
+
});
|
|
81
88
|
});
|
|
82
89
|
|
|
83
90
|
it(`should return a list of existing job executions by name`, async (): Promise<void> => {
|
|
84
91
|
const mockName = `mock`;
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
92
|
+
const mockJobExecutions = [
|
|
93
|
+
createMockJobExecution({ jobName: mockName }),
|
|
94
|
+
createMockJobExecution({ jobName: mockName }),
|
|
88
95
|
];
|
|
89
96
|
|
|
90
|
-
|
|
91
|
-
(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}),
|
|
97
|
+
dynamoClient.on(QueryCommand).resolvesOnce(
|
|
98
|
+
createMockClientScanResponse({
|
|
99
|
+
Items: mockJobExecutions.map((execution) => createMockJobExecutionDto(execution)),
|
|
100
|
+
LastEvaluatedKey: undefined,
|
|
101
|
+
}),
|
|
96
102
|
);
|
|
97
103
|
|
|
98
|
-
const response = await jobExecutionRepository.list({
|
|
99
|
-
|
|
100
|
-
|
|
104
|
+
const response = await jobExecutionRepository.list({
|
|
105
|
+
filters: { jobName: mockName },
|
|
106
|
+
});
|
|
107
|
+
expect(response).toEqual(mockJobExecutions);
|
|
108
|
+
expect(dynamoClient).toHaveReceivedCommandWith(QueryCommand, {
|
|
109
|
+
ExclusiveStartKey: undefined,
|
|
110
|
+
ExpressionAttributeNames: { '#pk': 'pk', '#sk': 'sk' },
|
|
111
|
+
ExpressionAttributeValues: {
|
|
112
|
+
':pk': { S: `jobExecution~${tenant}` },
|
|
113
|
+
':skPrefix': { S: `${mockName}~` },
|
|
114
|
+
},
|
|
115
|
+
IndexName: undefined,
|
|
116
|
+
KeyConditionExpression: '#pk = :pk and begins_with(#sk, :skPrefix)',
|
|
117
|
+
ScanIndexForward: false,
|
|
118
|
+
TableName: tableName,
|
|
119
|
+
});
|
|
101
120
|
});
|
|
102
121
|
|
|
103
122
|
it(`should return a list of existing job executions by status`, async (): Promise<void> => {
|
|
104
123
|
const mockStatus = JOB_EXECUTION_STATUS.running;
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
124
|
+
const mockJobExecutions = [
|
|
125
|
+
createMockJobExecution({ status: mockStatus }),
|
|
126
|
+
createMockJobExecution({ status: mockStatus }),
|
|
108
127
|
];
|
|
109
128
|
|
|
110
|
-
|
|
111
|
-
(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}),
|
|
129
|
+
dynamoClient.on(QueryCommand).resolvesOnce(
|
|
130
|
+
createMockClientScanResponse({
|
|
131
|
+
Items: mockJobExecutions.map((execution) => createMockJobExecutionDto(execution)),
|
|
132
|
+
LastEvaluatedKey: undefined,
|
|
133
|
+
}),
|
|
116
134
|
);
|
|
117
135
|
|
|
118
|
-
const response = await jobExecutionRepository.list({
|
|
119
|
-
|
|
120
|
-
|
|
136
|
+
const response = await jobExecutionRepository.list({
|
|
137
|
+
filters: { status: mockStatus },
|
|
138
|
+
});
|
|
139
|
+
expect(response).toEqual(mockJobExecutions);
|
|
140
|
+
expect(dynamoClient).toHaveReceivedCommandWith(QueryCommand, {
|
|
141
|
+
ExclusiveStartKey: undefined,
|
|
142
|
+
ExpressionAttributeNames: {
|
|
143
|
+
'#lsi1sk': 'lsi1sk',
|
|
144
|
+
'#pk': 'pk',
|
|
145
|
+
},
|
|
146
|
+
ExpressionAttributeValues: {
|
|
147
|
+
':lsi1skPrefix': { S: `${mockStatus}~` },
|
|
148
|
+
':pk': { S: `jobExecution~${tenant}` },
|
|
149
|
+
},
|
|
150
|
+
IndexName: 'lsi1',
|
|
151
|
+
KeyConditionExpression: '#pk = :pk and begins_with(#lsi1sk, :lsi1skPrefix)',
|
|
152
|
+
ScanIndexForward: false,
|
|
153
|
+
TableName: tableName,
|
|
154
|
+
});
|
|
121
155
|
});
|
|
122
156
|
|
|
123
157
|
it(`should paginate results to return a list of existing job executions`, async (): Promise<void> => {
|
|
124
158
|
const mockRecordsPage1 = [
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
159
|
+
createMockJobExecution({ jobName: 'testJob1' }),
|
|
160
|
+
createMockJobExecution({ jobName: 'testJob1' }),
|
|
161
|
+
createMockJobExecution({ jobName: 'testJob1' }),
|
|
128
162
|
];
|
|
129
163
|
const mockRecordsPage2 = [
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
164
|
+
createMockJobExecution({ jobName: 'testJob2' }),
|
|
165
|
+
createMockJobExecution({ jobName: 'testJob2' }),
|
|
166
|
+
createMockJobExecution({ jobName: 'testJob2' }),
|
|
133
167
|
];
|
|
134
168
|
|
|
135
|
-
|
|
136
|
-
.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
169
|
+
dynamoClient
|
|
170
|
+
.on(QueryCommand)
|
|
171
|
+
.resolvesOnce(
|
|
172
|
+
createMockClientScanResponse({
|
|
173
|
+
Items: mockRecordsPage1.map((execution) => createMockJobExecutionDto(execution)),
|
|
174
|
+
LastEvaluatedKey: createMockJobExecutionDto(mockRecordsPage1.slice(-1)[0]),
|
|
175
|
+
}),
|
|
142
176
|
)
|
|
143
|
-
.
|
|
144
|
-
(
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}),
|
|
177
|
+
.resolvesOnce(
|
|
178
|
+
createMockClientScanResponse({
|
|
179
|
+
Items: mockRecordsPage2.map((execution) => createMockJobExecutionDto(execution)),
|
|
180
|
+
LastEvaluatedKey: undefined,
|
|
181
|
+
}),
|
|
149
182
|
);
|
|
150
183
|
|
|
151
|
-
const response = await jobExecutionRepository.list({
|
|
152
|
-
|
|
153
|
-
|
|
184
|
+
const response = await jobExecutionRepository.list({
|
|
185
|
+
filters: { jobName: 'testJob1' },
|
|
186
|
+
limit: 4,
|
|
187
|
+
});
|
|
188
|
+
expect(response).toEqual([mockRecordsPage1[0], mockRecordsPage1[1], mockRecordsPage1[2], mockRecordsPage2[0]]);
|
|
189
|
+
expect(dynamoClient).toHaveReceivedCommandTimes(QueryCommand, 2);
|
|
190
|
+
expect(dynamoClient).toHaveReceivedCommandWith(QueryCommand, {
|
|
191
|
+
Limit: 4,
|
|
192
|
+
});
|
|
154
193
|
});
|
|
155
194
|
|
|
156
195
|
it(`should stop paginating if unexpected result is returned`, async (): Promise<void> => {
|
|
157
|
-
|
|
196
|
+
dynamoClient.on(QueryCommand).resolvesOnce({});
|
|
158
197
|
|
|
159
|
-
const response = await jobExecutionRepository.list({
|
|
160
|
-
|
|
161
|
-
|
|
198
|
+
const response = await jobExecutionRepository.list({
|
|
199
|
+
filters: { jobName: 'testJob1' },
|
|
200
|
+
});
|
|
201
|
+
expect(response).toEqual([]);
|
|
202
|
+
expect(dynamoClient).toHaveReceivedCommandTimes(QueryCommand, 1);
|
|
162
203
|
});
|
|
163
204
|
});
|
|
164
205
|
|
|
165
206
|
describe('findOne', () => {
|
|
166
|
-
beforeEach(() => {
|
|
167
|
-
jest.resetAllMocks();
|
|
168
|
-
});
|
|
169
|
-
|
|
170
207
|
it(`should return job execution by timeQueued and id and handle any null values`, async (): Promise<void> => {
|
|
171
208
|
const mockJobExecutionRecord = createMockJobExecutionDto({
|
|
172
209
|
ecsTaskId: 'ecs-task-id',
|
|
@@ -175,79 +212,70 @@ describe('JobExecutionRepository', (): void => {
|
|
|
175
212
|
version: '1.0.0',
|
|
176
213
|
});
|
|
177
214
|
|
|
178
|
-
|
|
179
|
-
(
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}),
|
|
215
|
+
dynamoClient.on(GetItemCommand).resolvesOnce(
|
|
216
|
+
createMockClientGetResponse({
|
|
217
|
+
Item: mockJobExecutionRecord,
|
|
218
|
+
}),
|
|
183
219
|
);
|
|
184
220
|
|
|
185
|
-
const response = await jobExecutionRepository.findOne(
|
|
186
|
-
|
|
187
|
-
mockJobExecutionRecord.
|
|
188
|
-
);
|
|
221
|
+
const response = await jobExecutionRepository.findOne({
|
|
222
|
+
jobName: mockJobExecutionRecord.jobName.S as string,
|
|
223
|
+
id: mockJobExecutionRecord.id.S as string,
|
|
224
|
+
});
|
|
189
225
|
expect(response).toStrictEqual({
|
|
190
226
|
context: mockJobExecutionRecord.context.S as string,
|
|
191
|
-
ecsTaskId: mockJobExecutionRecord.ecsTaskId.
|
|
227
|
+
ecsTaskId: mockJobExecutionRecord.ecsTaskId.S as string,
|
|
192
228
|
id: mockJobExecutionRecord.id.S as string,
|
|
193
229
|
jobName: mockJobExecutionRecord.jobName.S as string,
|
|
194
230
|
status: mockJobExecutionRecord.status.S as string,
|
|
195
|
-
timeFinished: mockJobExecutionRecord.timeFinished.
|
|
196
|
-
? null
|
|
197
|
-
: (mockJobExecutionRecord.timeFinished.S as string),
|
|
231
|
+
timeFinished: mockJobExecutionRecord.timeFinished.S as string,
|
|
198
232
|
timeQueued: mockJobExecutionRecord.timeQueued.S as string,
|
|
199
|
-
timeStarted: mockJobExecutionRecord.timeStarted.
|
|
233
|
+
timeStarted: mockJobExecutionRecord.timeStarted.S as string,
|
|
200
234
|
type: `jobExecution-${mockJobExecutionRecord.jobName.S as string}`,
|
|
201
|
-
version: mockJobExecutionRecord.version.
|
|
235
|
+
version: mockJobExecutionRecord.version.S as string,
|
|
202
236
|
input: mockJobExecutionRecord.input.NULL ? null : JSON.parse(mockJobExecutionRecord.input.S as string),
|
|
237
|
+
retryCount: 0,
|
|
238
|
+
lastFailureReason: null,
|
|
239
|
+
retryAfter: null,
|
|
203
240
|
} as JobExecution);
|
|
204
|
-
expect(
|
|
241
|
+
expect(dynamoClient).toHaveReceivedCommandWith(GetItemCommand, {});
|
|
205
242
|
});
|
|
206
243
|
|
|
207
244
|
it(`should return null if job execution does not exist`, async (): Promise<void> => {
|
|
208
|
-
|
|
209
|
-
(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}),
|
|
245
|
+
dynamoClient.on(GetItemCommand).resolvesOnce(
|
|
246
|
+
createMockClientGetResponse({
|
|
247
|
+
Item: undefined,
|
|
248
|
+
}),
|
|
213
249
|
);
|
|
214
250
|
|
|
215
|
-
const response = await jobExecutionRepository.findOne(
|
|
216
|
-
expect(mockSend).toBeCalledTimes(1);
|
|
251
|
+
const response = await jobExecutionRepository.findOne({ jobName: 'null', id: 'null' });
|
|
217
252
|
expect(response).toBe(null);
|
|
253
|
+
expect(dynamoClient).toHaveReceivedCommandTimes(GetItemCommand, 1);
|
|
218
254
|
});
|
|
219
255
|
});
|
|
220
256
|
|
|
221
257
|
describe('create', () => {
|
|
222
|
-
beforeEach(() => {
|
|
223
|
-
jest.resetAllMocks();
|
|
224
|
-
});
|
|
225
|
-
|
|
226
258
|
it(`should create a new job execution record and return job execution record in the response`, async (): Promise<void> => {
|
|
227
259
|
const newJobExecutionToCreate = createMockJobExecution();
|
|
228
260
|
const mockResponse = createMockClientPutResponse({
|
|
229
261
|
Attributes: {
|
|
230
262
|
jobName: { S: newJobExecutionToCreate.jobName },
|
|
231
|
-
pk: { S:
|
|
263
|
+
pk: { S: ENTITY_TYPES.jobExecution },
|
|
232
264
|
sk: { S: `${newJobExecutionToCreate.jobName}` },
|
|
233
265
|
},
|
|
234
266
|
});
|
|
235
267
|
|
|
236
|
-
|
|
268
|
+
dynamoClient.on(PutItemCommand).resolvesOnce(mockResponse);
|
|
237
269
|
|
|
238
270
|
const response = await jobExecutionRepository.create(newJobExecutionToCreate);
|
|
239
|
-
expect(mockSend).toBeCalledTimes(1);
|
|
240
271
|
expect(response).toStrictEqual({
|
|
241
272
|
...newJobExecutionToCreate,
|
|
242
273
|
});
|
|
274
|
+
expect(dynamoClient).toHaveReceivedCommandWith(PutItemCommand, {});
|
|
243
275
|
});
|
|
244
276
|
});
|
|
245
277
|
|
|
246
278
|
describe('begin', () => {
|
|
247
|
-
beforeEach(() => {
|
|
248
|
-
jest.resetAllMocks();
|
|
249
|
-
});
|
|
250
|
-
|
|
251
279
|
it(`should create a new queued job record`, async (): Promise<void> => {
|
|
252
280
|
const newJobExecutionToCreate = createMockJobExecution({
|
|
253
281
|
status: JOB_EXECUTION_STATUS.queued,
|
|
@@ -257,7 +285,7 @@ describe('JobExecutionRepository', (): void => {
|
|
|
257
285
|
});
|
|
258
286
|
const mockReponse = createMockClientPutResponse({
|
|
259
287
|
Attributes: {
|
|
260
|
-
pk: { S: `${
|
|
288
|
+
pk: { S: `${ENTITY_TYPES.jobExecution}-${newJobExecutionToCreate.jobName}` },
|
|
261
289
|
sk: { S: `${newJobExecutionToCreate.timeQueued}-${newJobExecutionToCreate.id}` },
|
|
262
290
|
name: { S: newJobExecutionToCreate.jobName },
|
|
263
291
|
context: { S: newJobExecutionToCreate.context },
|
|
@@ -268,7 +296,7 @@ describe('JobExecutionRepository', (): void => {
|
|
|
268
296
|
},
|
|
269
297
|
});
|
|
270
298
|
|
|
271
|
-
|
|
299
|
+
dynamoClient.on(PutItemCommand).resolvesOnce(mockReponse);
|
|
272
300
|
|
|
273
301
|
const response = await jobExecutionRepository.begin({
|
|
274
302
|
context: newJobExecutionToCreate.context,
|
|
@@ -276,7 +304,6 @@ describe('JobExecutionRepository', (): void => {
|
|
|
276
304
|
version: newJobExecutionToCreate.version,
|
|
277
305
|
input: newJobExecutionToCreate.input,
|
|
278
306
|
});
|
|
279
|
-
expect(mockSend).toBeCalledTimes(1);
|
|
280
307
|
expect(response.id).not.toBeNull();
|
|
281
308
|
expect(response.timeQueued).not.toBeNull();
|
|
282
309
|
expect(response.ecsTaskId).toBeNull();
|
|
@@ -286,18 +313,21 @@ describe('JobExecutionRepository', (): void => {
|
|
|
286
313
|
expect(response.jobName).toBe(newJobExecutionToCreate.jobName);
|
|
287
314
|
expect(response.version).toBe(newJobExecutionToCreate.version);
|
|
288
315
|
expect(response.input).toBe(newJobExecutionToCreate.input);
|
|
316
|
+
expect(dynamoClient).toHaveReceivedCommandWith(PutItemCommand, {});
|
|
289
317
|
});
|
|
290
318
|
});
|
|
291
319
|
|
|
292
320
|
describe('getExecutions', () => {
|
|
321
|
+
const jobName = 'something';
|
|
322
|
+
const jobExecutionId = faker.string.uuid();
|
|
293
323
|
let mockExclusiveStartKey: Record<string, AttributeValue>;
|
|
294
324
|
let mockPaginationInfo: PaginationInfo;
|
|
295
325
|
let mockParams: QueryCommandInput;
|
|
296
326
|
|
|
297
327
|
beforeEach(() => {
|
|
298
328
|
mockExclusiveStartKey = {
|
|
299
|
-
pk: { S: `${
|
|
300
|
-
sk: { S:
|
|
329
|
+
pk: { S: `${ENTITY_TYPES.jobExecution}~${tenant}` },
|
|
330
|
+
sk: { S: `${jobName}~${jobExecutionId}` },
|
|
301
331
|
};
|
|
302
332
|
mockPaginationInfo = {
|
|
303
333
|
direction: PAGINATION_DIRECTION_TYPE_BEFORE,
|
|
@@ -308,61 +338,205 @@ describe('JobExecutionRepository', (): void => {
|
|
|
308
338
|
mockParams = {
|
|
309
339
|
ExclusiveStartKey: mockExclusiveStartKey,
|
|
310
340
|
ExpressionAttributeValues: {
|
|
311
|
-
':pk': { S: `${
|
|
341
|
+
':pk': { S: `${ENTITY_TYPES.jobExecution}~${tenant}` },
|
|
342
|
+
':skPrefix': { S: `${jobName}~` },
|
|
312
343
|
},
|
|
313
|
-
KeyConditionExpression: 'pk = :pk',
|
|
314
|
-
TableName:
|
|
344
|
+
KeyConditionExpression: 'pk = :pk and begins_with(sk, :skPrefix)',
|
|
345
|
+
TableName: tableName,
|
|
315
346
|
};
|
|
316
347
|
|
|
317
348
|
jest.spyOn(PaginationUtils, 'decodeTokenString').mockReturnValue(mockExclusiveStartKey);
|
|
318
349
|
});
|
|
319
350
|
|
|
320
351
|
it('should return an empty array if no executions are found', async () => {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
}),
|
|
326
|
-
);
|
|
327
|
-
|
|
328
|
-
const mockRequestData: PaginationInfo = mockPaginationInfo;
|
|
352
|
+
dynamoClient.on(QueryCommand).resolvesOnce({
|
|
353
|
+
Items: [],
|
|
354
|
+
LastEvaluatedKey: undefined,
|
|
355
|
+
});
|
|
329
356
|
|
|
330
|
-
const result = await jobExecutionRepository.getExecutions(
|
|
357
|
+
const result = await jobExecutionRepository.getExecutions(mockPaginationInfo, 'something');
|
|
331
358
|
|
|
332
|
-
expect(
|
|
333
|
-
expect.objectContaining({
|
|
334
|
-
input: { ...mockParams },
|
|
335
|
-
}),
|
|
336
|
-
);
|
|
359
|
+
expect(dynamoClient).toHaveReceivedCommandWith(QueryCommand, mockParams);
|
|
337
360
|
expect(result.items).toEqual([]);
|
|
338
|
-
expect(result.lastEvaluatedKey).toBe(
|
|
361
|
+
expect(result.lastEvaluatedKey).toBe(undefined);
|
|
339
362
|
});
|
|
340
363
|
|
|
341
|
-
it('should return an array of
|
|
364
|
+
it('should return an array of job executions if found', async () => {
|
|
342
365
|
const mockJobExecutionRecords = createMockJobExecutionDtos();
|
|
343
366
|
const mockLastEvaluatedKey = {
|
|
344
|
-
pk: { S: `${
|
|
367
|
+
pk: { S: `${ENTITY_TYPES.job}-${'something'}` },
|
|
345
368
|
sk: { S: 'mockSk' },
|
|
346
369
|
};
|
|
347
370
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
}),
|
|
353
|
-
);
|
|
354
|
-
|
|
355
|
-
const mockRequestData: PaginationInfo = mockPaginationInfo;
|
|
371
|
+
dynamoClient.on(QueryCommand).resolvesOnce({
|
|
372
|
+
Items: mockJobExecutionRecords,
|
|
373
|
+
LastEvaluatedKey: mockLastEvaluatedKey,
|
|
374
|
+
});
|
|
356
375
|
|
|
357
|
-
const result = await jobExecutionRepository.getExecutions(
|
|
376
|
+
const result = await jobExecutionRepository.getExecutions(mockPaginationInfo, 'something');
|
|
358
377
|
|
|
359
|
-
expect(
|
|
360
|
-
expect.objectContaining({
|
|
361
|
-
input: { ...mockParams },
|
|
362
|
-
}),
|
|
363
|
-
);
|
|
378
|
+
expect(dynamoClient).toHaveReceivedCommandWith(QueryCommand, mockParams);
|
|
364
379
|
expect(result.items).toHaveLength(mockJobExecutionRecords.length);
|
|
365
380
|
expect(result.lastEvaluatedKey).toStrictEqual(mockLastEvaluatedKey);
|
|
366
381
|
});
|
|
367
382
|
});
|
|
383
|
+
|
|
384
|
+
describe('update', () => {
|
|
385
|
+
it('Updates the record properties', async () => {
|
|
386
|
+
const jobExecution = createMockJobExecution({ status: JOB_EXECUTION_STATUS.queued });
|
|
387
|
+
const updatedAttributes: UpdateJobExecutionParameters = {
|
|
388
|
+
input: faker.lorem.words(),
|
|
389
|
+
ecsTaskId: faker.string.uuid(),
|
|
390
|
+
version: faker.system.semver(),
|
|
391
|
+
timeStarted: faker.date.recent().toISOString(),
|
|
392
|
+
timeFinished: null,
|
|
393
|
+
context: faker.lorem.words(),
|
|
394
|
+
};
|
|
395
|
+
const updatedJobExecution = createMockJobExecution({
|
|
396
|
+
...jobExecution,
|
|
397
|
+
...updatedAttributes,
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
dynamoClient.on(UpdateItemCommand).resolvesOnce({
|
|
401
|
+
Attributes: createMockJobExecutionDto(updatedJobExecution),
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
const result = await jobExecutionRepository.update(jobExecution, updatedAttributes);
|
|
405
|
+
|
|
406
|
+
expect(result).toEqual(updatedJobExecution);
|
|
407
|
+
expect(dynamoClient).toHaveReceivedCommandWith(UpdateItemCommand, {
|
|
408
|
+
ExpressionAttributeNames: {
|
|
409
|
+
'#context': 'context',
|
|
410
|
+
'#ecsTaskId': 'ecsTaskId',
|
|
411
|
+
'#input': 'input',
|
|
412
|
+
'#timeFinished': 'timeFinished',
|
|
413
|
+
'#timeStarted': 'timeStarted',
|
|
414
|
+
'#version': 'version',
|
|
415
|
+
},
|
|
416
|
+
ExpressionAttributeValues: {
|
|
417
|
+
':context': { S: updatedAttributes.context! },
|
|
418
|
+
':ecsTaskId': { S: updatedAttributes.ecsTaskId! },
|
|
419
|
+
':input': { S: updatedAttributes.input },
|
|
420
|
+
':timeFinished': { NULL: true },
|
|
421
|
+
':timeStarted': { S: updatedAttributes.timeStarted! },
|
|
422
|
+
':version': { S: updatedAttributes.version! },
|
|
423
|
+
},
|
|
424
|
+
Key: {
|
|
425
|
+
pk: { S: `jobExecution~${tenant}` },
|
|
426
|
+
sk: { S: `${jobExecution.jobName}~${jobExecution.id}` },
|
|
427
|
+
},
|
|
428
|
+
ReturnValues: 'ALL_NEW',
|
|
429
|
+
TableName: tableName,
|
|
430
|
+
UpdateExpression:
|
|
431
|
+
'SET #input = :input, #ecsTaskId = :ecsTaskId, #version = :version, #timeStarted = :timeStarted, #timeFinished = :timeFinished, #context = :context',
|
|
432
|
+
});
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it('Updates the record keys when the status is updated', async () => {
|
|
436
|
+
const jobExecution = createMockJobExecution({ status: JOB_EXECUTION_STATUS.queued });
|
|
437
|
+
const updatedJobExecution = createMockJobExecution({
|
|
438
|
+
...jobExecution,
|
|
439
|
+
status: JOB_EXECUTION_STATUS.running,
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
dynamoClient.on(UpdateItemCommand).resolvesOnce({
|
|
443
|
+
Attributes: createMockJobExecutionDto(updatedJobExecution),
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
const result = await jobExecutionRepository.update(jobExecution, {
|
|
447
|
+
status: updatedJobExecution.status,
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
expect(result).toEqual(updatedJobExecution);
|
|
451
|
+
expect(dynamoClient).toHaveReceivedCommandWith(UpdateItemCommand, {
|
|
452
|
+
ExpressionAttributeNames: {
|
|
453
|
+
'#gsi1pk': 'gsi1pk',
|
|
454
|
+
'#lsi1sk': 'lsi1sk',
|
|
455
|
+
'#status': 'status',
|
|
456
|
+
},
|
|
457
|
+
ExpressionAttributeValues: {
|
|
458
|
+
':gsi1pk': { S: `jobExecution~${updatedJobExecution.status}` },
|
|
459
|
+
':lsi1sk': { S: `${updatedJobExecution.status}~${updatedJobExecution.jobName}` },
|
|
460
|
+
':status': { S: updatedJobExecution.status },
|
|
461
|
+
},
|
|
462
|
+
Key: {
|
|
463
|
+
pk: { S: `jobExecution~${tenant}` },
|
|
464
|
+
sk: { S: `${jobExecution.jobName}~${jobExecution.id}` },
|
|
465
|
+
},
|
|
466
|
+
ReturnValues: 'ALL_NEW',
|
|
467
|
+
TableName: tableName,
|
|
468
|
+
UpdateExpression: 'SET #status = :status, #lsi1sk = :lsi1sk, #gsi1pk = :gsi1pk',
|
|
469
|
+
});
|
|
470
|
+
});
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
describe('batchDelete', () => {
|
|
474
|
+
it('should delete the requested dynamo records', async () => {
|
|
475
|
+
dynamoClient.on(BatchWriteItemCommand).resolves({});
|
|
476
|
+
|
|
477
|
+
const jobExecutions = createMockJobExecutions(3);
|
|
478
|
+
const result = await jobExecutionRepository.batchDelete(jobExecutions);
|
|
479
|
+
|
|
480
|
+
expect(result).toEqual({ unprocessedItems: [] });
|
|
481
|
+
expect(dynamoClient).toHaveReceivedCommandWith(BatchWriteItemCommand, {
|
|
482
|
+
RequestItems: {
|
|
483
|
+
[tableName]: [
|
|
484
|
+
{
|
|
485
|
+
DeleteRequest: {
|
|
486
|
+
Key: {
|
|
487
|
+
pk: { S: `jobExecution~${tenant}` },
|
|
488
|
+
sk: { S: `${jobExecutions[0].jobName}~${jobExecutions[0].id}` },
|
|
489
|
+
},
|
|
490
|
+
},
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
DeleteRequest: {
|
|
494
|
+
Key: {
|
|
495
|
+
pk: { S: `jobExecution~${tenant}` },
|
|
496
|
+
sk: { S: `${jobExecutions[1].jobName}~${jobExecutions[1].id}` },
|
|
497
|
+
},
|
|
498
|
+
},
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
DeleteRequest: {
|
|
502
|
+
Key: {
|
|
503
|
+
pk: { S: `jobExecution~${tenant}` },
|
|
504
|
+
sk: { S: `${jobExecutions[2].jobName}~${jobExecutions[2].id}` },
|
|
505
|
+
},
|
|
506
|
+
},
|
|
507
|
+
},
|
|
508
|
+
],
|
|
509
|
+
},
|
|
510
|
+
});
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
it('should return without attempting to delete if an empty array of SK is provided', async () => {
|
|
514
|
+
const result = await jobExecutionRepository.batchDelete([]);
|
|
515
|
+
|
|
516
|
+
expect(result).toEqual({ unprocessedItems: [] });
|
|
517
|
+
expect(dynamoClient).not.toHaveReceivedCommand(BatchWriteItemCommand);
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
it('should return the unprocessed SK items if some items fail to delete', async () => {
|
|
521
|
+
const jobExecutions = createMockJobExecutions(3);
|
|
522
|
+
|
|
523
|
+
dynamoClient.on(BatchWriteItemCommand).resolves({
|
|
524
|
+
UnprocessedItems: {
|
|
525
|
+
[tableName]: [
|
|
526
|
+
{
|
|
527
|
+
DeleteRequest: {
|
|
528
|
+
Key: {
|
|
529
|
+
pk: { S: `jobExecution~${tenant}` },
|
|
530
|
+
sk: { S: `${jobExecutions[1].jobName}~${jobExecutions[1].id}` },
|
|
531
|
+
},
|
|
532
|
+
},
|
|
533
|
+
},
|
|
534
|
+
],
|
|
535
|
+
},
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
const result = await jobExecutionRepository.batchDelete(jobExecutions);
|
|
539
|
+
expect(result).toEqual({ unprocessedItems: [jobExecutions[1]] });
|
|
540
|
+
});
|
|
541
|
+
});
|
|
368
542
|
});
|