Skip to content

Commit 4594481

Browse files
Increase default util inspect depth for objects (#27)
* increase default util inspect depth for objects * make model type reference a public property * have additional empty string test * improve types for progress event
1 parent 40cc222 commit 4594481

File tree

12 files changed

+135
-102
lines changed

12 files changed

+135
-102
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"name": "cfn-rpdk",
33
"version": "0.4.0",
44
"description": "The CloudFormation Resource Provider Development Kit (RPDK) allows you to author your own resource providers that can be used by CloudFormation. This plugin library helps to provide runtime bindings for the execution of your providers by CloudFormation.",
5+
"private": false,
56
"main": "dist/index.js",
67
"directories": {
78
"test": "tests"

python/rpdk/typescript/templates/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Congratulations on starting development! Next steps:
1010
Implement CloudFormation resource here. Each function must always return a ProgressEvent.
1111

1212
```typescript
13-
const progress: ProgressEvent = ProgressEvent.builder<ProgressEvent<ResourceModel>>()
13+
const progress = ProgressEvent.builder<ProgressEvent<ResourceModel>>()
1414

1515
// Required
1616
// Must be one of OperationStatus.InProgress, OperationStatus.Failed, OperationStatus.Success

python/rpdk/typescript/templates/handlers.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ class Resource extends BaseResource<ResourceModel> {
3232
request: ResourceHandlerRequest<ResourceModel>,
3333
callbackContext: CallbackContext,
3434
logger: LoggerProxy
35-
): Promise<ProgressEvent> {
36-
const model: ResourceModel = new ResourceModel(request.desiredResourceState);
35+
): Promise<ProgressEvent<ResourceModel, CallbackContext>> {
36+
const model = new ResourceModel(request.desiredResourceState);
3737
const progress = ProgressEvent.progress<ProgressEvent<ResourceModel, CallbackContext>>(model);
3838
// TODO: put code here
3939

@@ -69,8 +69,8 @@ class Resource extends BaseResource<ResourceModel> {
6969
request: ResourceHandlerRequest<ResourceModel>,
7070
callbackContext: CallbackContext,
7171
logger: LoggerProxy
72-
): Promise<ProgressEvent> {
73-
const model: ResourceModel = new ResourceModel(request.desiredResourceState);
72+
): Promise<ProgressEvent<ResourceModel, CallbackContext>> {
73+
const model = new ResourceModel(request.desiredResourceState);
7474
const progress = ProgressEvent.progress<ProgressEvent<ResourceModel, CallbackContext>>(model);
7575
// TODO: put code here
7676
progress.status = OperationStatus.Success;
@@ -93,8 +93,8 @@ class Resource extends BaseResource<ResourceModel> {
9393
request: ResourceHandlerRequest<ResourceModel>,
9494
callbackContext: CallbackContext,
9595
logger: LoggerProxy
96-
): Promise<ProgressEvent> {
97-
const model: ResourceModel = new ResourceModel(request.desiredResourceState);
96+
): Promise<ProgressEvent<ResourceModel, CallbackContext>> {
97+
const model = new ResourceModel(request.desiredResourceState);
9898
const progress = ProgressEvent.progress<ProgressEvent<ResourceModel, CallbackContext>>();
9999
// TODO: put code here
100100
progress.status = OperationStatus.Success;
@@ -116,8 +116,8 @@ class Resource extends BaseResource<ResourceModel> {
116116
request: ResourceHandlerRequest<ResourceModel>,
117117
callbackContext: CallbackContext,
118118
logger: LoggerProxy
119-
): Promise<ProgressEvent> {
120-
const model: ResourceModel = new ResourceModel(request.desiredResourceState);
119+
): Promise<ProgressEvent<ResourceModel, CallbackContext>> {
120+
const model = new ResourceModel(request.desiredResourceState);
121121
// TODO: put code here
122122
const progress = ProgressEvent.success<ProgressEvent<ResourceModel, CallbackContext>>(model);
123123
return progress;
@@ -138,8 +138,8 @@ class Resource extends BaseResource<ResourceModel> {
138138
request: ResourceHandlerRequest<ResourceModel>,
139139
callbackContext: CallbackContext,
140140
logger: LoggerProxy
141-
): Promise<ProgressEvent> {
142-
const model: ResourceModel = new ResourceModel(request.desiredResourceState);
141+
): Promise<ProgressEvent<ResourceModel, CallbackContext>> {
142+
const model = new ResourceModel(request.desiredResourceState);
143143
// TODO: put code here
144144
const progress = ProgressEvent.builder<ProgressEvent<ResourceModel, CallbackContext>>()
145145
.status(OperationStatus.Success)
@@ -149,7 +149,7 @@ class Resource extends BaseResource<ResourceModel> {
149149
}
150150
}
151151

152-
const resource = new Resource(ResourceModel.TYPE_NAME, ResourceModel);
152+
export const resource = new Resource(ResourceModel.TYPE_NAME, ResourceModel);
153153

154154
export const entrypoint = resource.entrypoint;
155155

src/exceptions.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { HandlerErrorCode } from './interface';
1+
import { BaseModel, HandlerErrorCode } from './interface';
22
import { ProgressEvent } from './proxy';
33

44
export abstract class BaseHandlerException extends Error {
@@ -13,8 +13,8 @@ export abstract class BaseHandlerException extends Error {
1313
Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain
1414
}
1515

16-
public toProgressEvent(): ProgressEvent {
17-
return ProgressEvent.failed(this.errorCode, this.toString());
16+
public toProgressEvent<T extends BaseModel = BaseModel>(): ProgressEvent<T> {
17+
return ProgressEvent.failed<ProgressEvent<T>>(this.errorCode, this.toString());
1818
}
1919
}
2020

src/log-delivery.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { format } from 'util';
1+
import { format, inspect, InspectOptions } from 'util';
22
import { AWSError, Request } from 'aws-sdk';
33
import CloudWatchLogs, {
44
DescribeLogStreamsResponse,
@@ -563,6 +563,16 @@ export class LoggerProxy implements Logger {
563563
private readonly logPublishers = new Array<LogPublisher>();
564564
private readonly queue = new Array<PromiseFunction>();
565565

566+
constructor(defaultOptions: InspectOptions = {}) {
567+
// Allow passing Node.js inspect options,
568+
// and change default depth from 4 to 10
569+
inspect.defaultOptions = {
570+
...inspect.defaultOptions,
571+
depth: 10,
572+
...defaultOptions,
573+
};
574+
}
575+
566576
public addLogPublisher(logPublisher: LogPublisher): void {
567577
this.logPublishers.push(logPublisher);
568578
}

src/resource.ts

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,14 @@ const MUTATING_ACTIONS: [Action, Action, Action] = [
4141
Action.Delete,
4242
];
4343

44-
export type HandlerSignature = Callable<
44+
export type HandlerSignature<T extends BaseModel> = Callable<
4545
[Optional<SessionProxy>, any, Dict, LoggerProxy],
46-
Promise<ProgressEvent>
46+
Promise<ProgressEvent<T>>
4747
>;
48-
export class HandlerSignatures extends Map<Action, HandlerSignature> {}
48+
export class HandlerSignatures<T extends BaseModel> extends Map<
49+
Action,
50+
HandlerSignature<T>
51+
> {}
4952
class HandlerEvents extends Map<Action, string | symbol> {}
5053

5154
/**
@@ -69,8 +72,8 @@ function ensureSerialize<T extends BaseModel>(toResponse = false): MethodDecorat
6972
descriptor.value = async function (
7073
event: any | Dict,
7174
context: any
72-
): Promise<ProgressEvent | CfnResponse<T>> {
73-
const progress: ProgressEvent = await originalMethod.apply(this, [
75+
): Promise<ProgressEvent<T> | CfnResponse<T>> {
76+
const progress: ProgressEvent<T> = await originalMethod.apply(this, [
7477
event,
7578
context,
7679
]);
@@ -106,12 +109,12 @@ export abstract class BaseResource<T extends BaseModel = BaseModel> {
106109
private providerEventsLogger: CloudWatchLogPublisher | S3LogPublisher;
107110

108111
constructor(
109-
public typeName: string,
110-
private modelCls: Constructor<T>,
111-
private handlers?: HandlerSignatures
112+
public readonly typeName: string,
113+
public readonly modelTypeReference: Constructor<T>,
114+
private handlers?: HandlerSignatures<T>
112115
) {
113116
this.typeName = typeName || '';
114-
this.handlers = handlers || new HandlerSignatures();
117+
this.handlers = handlers || new HandlerSignatures<T>();
115118

116119
this.lambdaLogger = console;
117120

@@ -256,7 +259,10 @@ export abstract class BaseResource<T extends BaseModel = BaseModel> {
256259
}
257260
}
258261

259-
public addHandler = (action: Action, f: HandlerSignature): HandlerSignature => {
262+
public addHandler = (
263+
action: Action,
264+
f: HandlerSignature<T>
265+
): HandlerSignature<T> => {
260266
this.handlers.set(action, f);
261267
return f;
262268
};
@@ -266,24 +272,24 @@ export abstract class BaseResource<T extends BaseModel = BaseModel> {
266272
request: BaseResourceHandlerRequest<T>,
267273
action: Action,
268274
callbackContext: Dict
269-
): Promise<ProgressEvent> => {
270-
const handle: HandlerSignature = this.handlers.get(action);
271-
if (!handle) {
272-
return ProgressEvent.failed(
273-
HandlerErrorCode.InternalFailure,
274-
`No handler for ${action}`
275-
);
275+
): Promise<ProgressEvent<T>> => {
276+
const actionName = action == null ? '<null>' : action.toString();
277+
if (!this.handlers.has(action)) {
278+
throw new Error(`Unknown action ${actionName}`);
276279
}
280+
const handle: HandlerSignature<T> = this.handlers.get(action);
277281
// We will make the callback context and resource states readonly
278282
// to avoid modification at a later time
279283
deepFreeze(callbackContext);
280284
deepFreeze(request);
285+
this.log(`[${action}] invoking handler...`);
281286
const progress = await handle(
282287
session,
283288
request,
284289
callbackContext,
285290
this.loggerProxy
286291
);
292+
this.log(`[${action}] handler invoked`);
287293
const isInProgress = progress.status === OperationStatus.InProgress;
288294
const isMutable = MUTATING_ACTIONS.some((x) => x === action);
289295
if (isInProgress && !isMutable) {
@@ -310,7 +316,7 @@ export abstract class BaseResource<T extends BaseModel = BaseModel> {
310316
);
311317
}
312318
request = UnmodeledRequest.deserialize(event.request).toModeled<T>(
313-
this.modelCls
319+
this.modelTypeReference
314320
);
315321

316322
this.callerSession = SessionProxy.getSession(creds, event.region);
@@ -327,15 +333,18 @@ export abstract class BaseResource<T extends BaseModel = BaseModel> {
327333
// @ts-ignore
328334
public async testEntrypoint(
329335
eventData: any | Dict,
330-
context: any
331-
): Promise<ProgressEvent>;
336+
context?: any
337+
): Promise<ProgressEvent<T>>;
332338
@boundMethod
333339
@ensureSerialize<T>()
334-
public async testEntrypoint(eventData: Dict, context: any): Promise<ProgressEvent> {
340+
public async testEntrypoint(
341+
eventData: Dict,
342+
context?: any
343+
): Promise<ProgressEvent<T>> {
335344
let msg = 'Uninitialized';
336-
let progress: ProgressEvent;
345+
let progress: ProgressEvent<T>;
337346
try {
338-
if (!this.modelCls) {
347+
if (!this.modelTypeReference) {
339348
throw new exceptions.InternalFailure(
340349
'Missing Model class to be used to deserialize JSON data.'
341350
);
@@ -356,11 +365,14 @@ export abstract class BaseResource<T extends BaseModel = BaseModel> {
356365
err.stack = `${new Error().stack}\n${err.stack}`;
357366
if (err instanceof BaseHandlerException) {
358367
this.log(`Handler error: ${err.message}`, err);
359-
progress = err.toProgressEvent();
368+
progress = err.toProgressEvent<T>();
360369
} else {
361370
this.log(`Exception caught: ${err.message}`, err);
362371
msg = err.message || msg;
363-
progress = ProgressEvent.failed(HandlerErrorCode.InternalFailure, msg);
372+
progress = ProgressEvent.failed<ProgressEvent<T>>(
373+
HandlerErrorCode.InternalFailure,
374+
msg
375+
);
364376
}
365377
}
366378
return Promise.resolve(progress);
@@ -411,7 +423,7 @@ export abstract class BaseResource<T extends BaseModel = BaseModel> {
411423
logicalResourceIdentifier: request.requestData.logicalResourceId,
412424
region: request.region,
413425
});
414-
return unmodeled.toModeled<T>(this.modelCls);
426+
return unmodeled.toModeled<T>(this.modelTypeReference);
415427
} catch (err) {
416428
this.log('Invalid request');
417429
throw new InvalidRequest(`${err} (${err.name})`);
@@ -428,11 +440,11 @@ export abstract class BaseResource<T extends BaseModel = BaseModel> {
428440
public async entrypoint(
429441
eventData: Dict,
430442
context: LambdaContext
431-
): Promise<ProgressEvent> {
432-
let progress: ProgressEvent;
443+
): Promise<ProgressEvent<T>> {
444+
let progress: ProgressEvent<T>;
433445
let bearerToken: string;
434446
try {
435-
if (!this.modelCls) {
447+
if (!this.modelTypeReference) {
436448
throw new exceptions.InternalFailure(
437449
'Missing Model class to be used to deserialize JSON data.'
438450
);
@@ -495,10 +507,10 @@ export abstract class BaseResource<T extends BaseModel = BaseModel> {
495507
err.stack = `${new Error().stack}\n${err.stack}`;
496508
if (err instanceof BaseHandlerException) {
497509
this.log(`Handler error: ${err.message}`, err);
498-
progress = err.toProgressEvent();
510+
progress = err.toProgressEvent<T>();
499511
} else {
500512
this.log(`Exception caught: ${err.message}`, err);
501-
progress = ProgressEvent.failed(
513+
progress = ProgressEvent.failed<ProgressEvent<T>>(
502514
HandlerErrorCode.InternalFailure,
503515
err.message
504516
);

tests/data/sample-model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ export class SerializableModel extends BaseModel {
236236
public static readonly TYPE_NAME: string = 'Organization::Service::Serializable';
237237

238238
@Expose() somekey?: Optional<string>;
239+
@Expose() somestring?: Optional<string>;
239240
@Expose() someotherkey?: Optional<string>;
240241
@Expose({ name: 'SomeInt' })
241242
@Transform((value, obj) => transformValue(Integer, 'someint', value, obj), {

tests/lib/interface.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@ describe('when getting interface', () => {
1515
test('base resource model serialize', () => {
1616
const model = SerializableModel.deserialize({
1717
somekey: 'a',
18+
somestring: '',
1819
someotherkey: null,
1920
someint: null,
2021
});
2122
const serialized = JSON.parse(JSON.stringify(model));
22-
expect(Object.keys(serialized).length).toBe(1);
23+
expect(Object.keys(serialized).length).toBe(2);
24+
expect(serialized.somekey).toBe('a');
25+
expect(serialized.somestring).toBe('');
2326
expect(serialized.someotherkey).not.toBeDefined();
2427
});
2528

tests/lib/log-delivery.test.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import CloudWatchLogs, {
33
} from 'aws-sdk/clients/cloudwatchlogs';
44
import S3, { ListObjectsV2Output } from 'aws-sdk/clients/s3';
55
import awsUtil from 'aws-sdk/lib/util';
6+
import { inspect } from 'util';
67

78
import { SessionProxy } from '../../src/proxy';
89
import { MetricsPublisherProxy } from '../../src/metrics';
@@ -129,7 +130,7 @@ describe('when delivering logs', () => {
129130
if (name === 'CloudWatchLogs') return cwLogs(options);
130131
if (name === 'S3') return s3(options);
131132
};
132-
loggerProxy = new LoggerProxy();
133+
loggerProxy = new LoggerProxy({ depth: 8 });
133134
metricsPublisherProxy = new MetricsPublisherProxy();
134135
publishExceptionMetric = mockResult({
135136
ResponseMetadata: { RequestId: 'mock-request' },
@@ -493,7 +494,9 @@ describe('when delivering logs', () => {
493494
code: 'AccessDeniedException',
494495
})
495496
),
496-
on: () => {},
497+
on: (_event: string, callback: Function) => {
498+
callback({ httpRequest: { headers: [] } });
499+
},
497500
});
498501
const msgToLog = 'How is it going?';
499502
try {
@@ -1213,6 +1216,7 @@ describe('when delivering logs', () => {
12131216
loggerProxy.log('timestamp: [%s]', new Date('2020-01-03'));
12141217
loggerProxy.log('timestamp: [%s]', new Date('2020-01-04'));
12151218
expect(loggerProxy['queue'].length).toBe(9);
1219+
expect(inspect.defaultOptions.depth).toBe(8);
12161220
await loggerProxy.processQueue();
12171221

12181222
expect(cloudWatchLogger['logStreamName']).toBe(LOG_STREAM_NAME);

0 commit comments

Comments
 (0)