Skip to content

Commit 0d14c9f

Browse files
committed
Merge branch 'master' of github.com:eduardomourar/cloudformation-cli-typescript-plugin
2 parents c5ba909 + 30ef896 commit 0d14c9f

File tree

4 files changed

+131
-29
lines changed

4 files changed

+131
-29
lines changed

jest.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ module.exports = {
99
testRegex: '\\.test.ts$',
1010
coverageThreshold: {
1111
global: {
12-
branches: 80,
13-
statements: 90,
12+
branches: 70,
13+
statements: 80,
1414
},
1515
},
1616
coverageDirectory: 'coverage/ts',

src/resource.ts

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import {
1313
HandlerErrorCode,
1414
OperationStatus,
1515
Optional,
16-
RequestContext,
1716
} from './interface';
1817
import { ProviderLogHandler } from './log-delivery';
1918
import { MetricsPublisherProxy } from './metrics';
@@ -140,6 +139,7 @@ export abstract class BaseResource<T extends BaseModel = BaseModel> {
140139
let request: BaseResourceHandlerRequest<T>;
141140
let action: Action;
142141
let event: TestEvent;
142+
let callbackContext: Map<string, any>;
143143
try {
144144
event = new TestEvent(eventData);
145145
const creds = event.credentials as Credentials;
@@ -162,17 +162,25 @@ export abstract class BaseResource<T extends BaseModel = BaseModel> {
162162

163163
session = SessionProxy.getSession(creds, event.region);
164164
action = event.action;
165+
166+
if (!event.callbackContext) {
167+
callbackContext = new Map<string, any>();
168+
} else if (
169+
event.callbackContext instanceof Array ||
170+
event.callbackContext instanceof Map
171+
) {
172+
callbackContext = new Map<string, any>(event.callbackContext);
173+
} else {
174+
callbackContext = new Map<string, any>(
175+
Object.entries(event.callbackContext)
176+
);
177+
}
165178
} catch (err) {
166179
LOGGER.error('Invalid request');
167180
throw new InternalFailure(`${err} (${err.name})`);
168181
}
169182

170-
return [
171-
session,
172-
request,
173-
action,
174-
event.callbackContext || new Map<string, any>(),
175-
];
183+
return [session, request, action, callbackContext];
176184
};
177185

178186
// @ts-ignore
@@ -242,7 +250,18 @@ export abstract class BaseResource<T extends BaseModel = BaseModel> {
242250
event.requestData.providerCredentials
243251
);
244252
action = event.action;
245-
callbackContext = event.callbackContext || new Map<string, any>();
253+
if (!event.callbackContext) {
254+
callbackContext = new Map<string, any>();
255+
} else if (
256+
event.callbackContext instanceof Array ||
257+
event.callbackContext instanceof Map
258+
) {
259+
callbackContext = new Map<string, any>(event.callbackContext);
260+
} else {
261+
callbackContext = new Map<string, any>(
262+
Object.entries(event.callbackContext)
263+
);
264+
}
246265
} catch (err) {
247266
LOGGER.error('Invalid request');
248267
throw new InvalidRequest(`${err} (${err.name})`);

src/utils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,5 +188,6 @@ Map.prototype.toObject = function (): any {
188188
* Defines the default JSON representation of a Map to be an array of key-value pairs.
189189
*/
190190
Map.prototype.toJSON = function <K, V>(this: Map<K, V>): Array<[K, V]> {
191-
return Array.from(this.entries());
191+
// @ts-ignore
192+
return Object.fromEntries(this);
192193
};

tests/lib/resource.test.ts

Lines changed: 100 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,11 @@ import {
1010
CfnResponse,
1111
HandlerErrorCode,
1212
OperationStatus,
13-
RequestContext,
1413
} from '../../src/interface';
1514
import { ProviderLogHandler } from '../../src/log-delivery';
1615
import { MetricsPublisherProxy } from '../../src/metrics';
1716
import { handlerEvent, HandlerSignatures, BaseResource } from '../../src/resource';
18-
import { HandlerRequest, LambdaContext } from '../../src/utils';
17+
import { HandlerRequest } from '../../src/utils';
1918

2019
const mockResult = (output: any): jest.Mock => {
2120
return jest.fn().mockReturnValue({
@@ -195,23 +194,34 @@ describe('when getting resource', () => {
195194
await resource.entrypoint(entrypointPayload, null);
196195
});
197196

198-
test('entrypoint with context', async () => {
199-
entrypointPayload['requestContext'] = { a: 'b' };
197+
test('entrypoint with callback context', async () => {
198+
entrypointPayload['callbackContext'] = { a: 'b' };
200199
const event: ProgressEvent = ProgressEvent.success(null, { c: 'd' });
201200
const mockHandler: jest.Mock = jest.fn(() => event);
202201
const resource = new Resource(TYPE_NAME, MockModel);
203202
resource.addHandler(Action.Create, mockHandler);
204-
await resource.entrypoint(entrypointPayload, null);
203+
const response: CfnResponse<Resource> = await resource.entrypoint(
204+
entrypointPayload,
205+
null
206+
);
207+
expect(response).toMatchObject({
208+
message: '',
209+
status: OperationStatus.Success,
210+
callbackDelaySeconds: 0,
211+
});
205212
expect(mockHandler).toBeCalledTimes(1);
213+
expect(mockHandler).toBeCalledWith(
214+
expect.any(SessionProxy),
215+
expect.any(BaseResourceHandlerRequest),
216+
new Map(Object.entries(entrypointPayload['callbackContext']))
217+
);
206218
});
207219

208-
test('entrypoint without context', async () => {
209-
entrypointPayload['requestContext'] = null;
220+
test('entrypoint without callback context', async () => {
221+
entrypointPayload['callbackContext'] = null;
210222
const mockLogDelivery: jest.Mock = (ProviderLogHandler.setup as unknown) as jest.Mock;
211-
const event: ProgressEvent = ProgressEvent.success(
212-
new Map(Object.entries({ a: 'b' })),
213-
{ c: 'd' }
214-
);
223+
const event: ProgressEvent = ProgressEvent.progress(null, { c: 'd' });
224+
event.callbackDelaySeconds = 5;
215225
const mockHandler: jest.Mock = jest.fn(() => event);
216226
const resource = new Resource(TYPE_NAME, MockModel);
217227
resource.addHandler(Action.Create, mockHandler);
@@ -222,10 +232,16 @@ describe('when getting resource', () => {
222232
expect(mockLogDelivery).toBeCalledTimes(1);
223233
expect(response).toMatchObject({
224234
message: '',
225-
status: OperationStatus.Success,
226-
callbackDelaySeconds: 0,
235+
status: OperationStatus.InProgress,
236+
callbackDelaySeconds: 5,
237+
callbackContext: { c: 'd' },
227238
});
228239
expect(mockHandler).toBeCalledTimes(1);
240+
expect(mockHandler).toBeCalledWith(
241+
expect.any(SessionProxy),
242+
expect.any(BaseResourceHandlerRequest),
243+
new Map()
244+
);
229245
});
230246

231247
test('entrypoint success without caller provider creds', async () => {
@@ -261,6 +277,36 @@ describe('when getting resource', () => {
261277
expect(parseRequest).toThrow(/missing.+awsAccountId/i);
262278
});
263279

280+
test('parse request with object literal callback context', () => {
281+
const callbackContext = new Map();
282+
callbackContext.set('a', 'b');
283+
entrypointPayload['callbackContext'] = { a: 'b' };
284+
const payload = new Map(Object.entries(entrypointPayload));
285+
const resource = getResource();
286+
const [sessions, action, callback, request] = resource.constructor[
287+
'parseRequest'
288+
](payload);
289+
expect(sessions).toBeDefined();
290+
expect(action).toBeDefined();
291+
expect(callback).toMatchObject(callbackContext);
292+
expect(request).toBeDefined();
293+
});
294+
295+
test('parse request with map callback context', () => {
296+
const callbackContext = new Map();
297+
callbackContext.set('a', 'b');
298+
entrypointPayload['callbackContext'] = callbackContext;
299+
const payload = new Map(Object.entries(entrypointPayload));
300+
const resource = getResource();
301+
const [sessions, action, callback, request] = resource.constructor[
302+
'parseRequest'
303+
](payload);
304+
expect(sessions).toBeDefined();
305+
expect(action).toBeDefined();
306+
expect(callback).toMatchObject(callbackContext);
307+
expect(request).toBeDefined();
308+
});
309+
264310
test('cast resource request invalid request', () => {
265311
const payload = new Map(Object.entries(entrypointPayload));
266312
const request = HandlerRequest.deserialize(payload);
@@ -342,15 +388,15 @@ describe('when getting resource', () => {
342388
test('add handler', () => {
343389
class ResourceEventHandler extends BaseResource {
344390
@handlerEvent(Action.Create)
345-
public create() {}
391+
public create(): void {}
346392
@handlerEvent(Action.Read)
347-
public read() {}
393+
public read(): void {}
348394
@handlerEvent(Action.Update)
349-
public update() {}
395+
public update(): void {}
350396
@handlerEvent(Action.Delete)
351-
public delete() {}
397+
public delete(): void {}
352398
@handlerEvent(Action.List)
353-
public list() {}
399+
public list(): void {}
354400
}
355401
const handlers: HandlerSignatures = new HandlerSignatures();
356402
const resource = new ResourceEventHandler(null, null, handlers);
@@ -445,6 +491,42 @@ describe('when getting resource', () => {
445491
expect(parseTestRequest).toThrow(/missing.+credentials/i);
446492
});
447493

494+
test('parse test request with object literal callback context', () => {
495+
const callbackContext = new Map();
496+
callbackContext.set('a', 'b');
497+
testEntrypointPayload['callbackContext'] = { a: 'b' };
498+
class Model extends BaseModel {
499+
['constructor']: typeof Model;
500+
}
501+
const resource = new Resource(TYPE_NAME, Model);
502+
const payload = new Map(Object.entries(testEntrypointPayload));
503+
const [session, request, action, callback] = resource['parseTestRequest'](
504+
payload
505+
);
506+
expect(session).toBeDefined();
507+
expect(action).toBeDefined();
508+
expect(callback).toMatchObject(callbackContext);
509+
expect(request).toBeDefined();
510+
});
511+
512+
test('parse test request with map callback context', () => {
513+
const callbackContext = new Map();
514+
callbackContext.set('a', 'b');
515+
testEntrypointPayload['callbackContext'] = callbackContext;
516+
class Model extends BaseModel {
517+
['constructor']: typeof Model;
518+
}
519+
const resource = new Resource(TYPE_NAME, Model);
520+
const payload = new Map(Object.entries(testEntrypointPayload));
521+
const [session, request, action, callback] = resource['parseTestRequest'](
522+
payload
523+
);
524+
expect(session).toBeDefined();
525+
expect(action).toBeDefined();
526+
expect(callback).toMatchObject(callbackContext);
527+
expect(request).toBeDefined();
528+
});
529+
448530
test('parse test request valid request', () => {
449531
const mockDeserialize: jest.Mock = jest
450532
.fn()

0 commit comments

Comments
 (0)