diff --git a/package.json b/package.json index 4c10786..ae01b9f 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "cfn-rpdk", "version": "0.4.0", "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.", + "private": false, "main": "dist/index.js", "directories": { "test": "tests" diff --git a/python/rpdk/typescript/templates/README.md b/python/rpdk/typescript/templates/README.md index 27dbe66..e837451 100644 --- a/python/rpdk/typescript/templates/README.md +++ b/python/rpdk/typescript/templates/README.md @@ -10,7 +10,7 @@ Congratulations on starting development! Next steps: Implement CloudFormation resource here. Each function must always return a ProgressEvent. ```typescript -const progress: ProgressEvent = ProgressEvent.builder>() +const progress = ProgressEvent.builder>() // Required // Must be one of OperationStatus.InProgress, OperationStatus.Failed, OperationStatus.Success diff --git a/python/rpdk/typescript/templates/handlers.ts b/python/rpdk/typescript/templates/handlers.ts index 4009152..a7ba230 100644 --- a/python/rpdk/typescript/templates/handlers.ts +++ b/python/rpdk/typescript/templates/handlers.ts @@ -32,8 +32,8 @@ class Resource extends BaseResource { request: ResourceHandlerRequest, callbackContext: CallbackContext, logger: LoggerProxy - ): Promise { - const model: ResourceModel = new ResourceModel(request.desiredResourceState); + ): Promise> { + const model = new ResourceModel(request.desiredResourceState); const progress = ProgressEvent.progress>(model); // TODO: put code here @@ -69,8 +69,8 @@ class Resource extends BaseResource { request: ResourceHandlerRequest, callbackContext: CallbackContext, logger: LoggerProxy - ): Promise { - const model: ResourceModel = new ResourceModel(request.desiredResourceState); + ): Promise> { + const model = new ResourceModel(request.desiredResourceState); const progress = ProgressEvent.progress>(model); // TODO: put code here progress.status = OperationStatus.Success; @@ -93,8 +93,8 @@ class Resource extends BaseResource { request: ResourceHandlerRequest, callbackContext: CallbackContext, logger: LoggerProxy - ): Promise { - const model: ResourceModel = new ResourceModel(request.desiredResourceState); + ): Promise> { + const model = new ResourceModel(request.desiredResourceState); const progress = ProgressEvent.progress>(); // TODO: put code here progress.status = OperationStatus.Success; @@ -116,8 +116,8 @@ class Resource extends BaseResource { request: ResourceHandlerRequest, callbackContext: CallbackContext, logger: LoggerProxy - ): Promise { - const model: ResourceModel = new ResourceModel(request.desiredResourceState); + ): Promise> { + const model = new ResourceModel(request.desiredResourceState); // TODO: put code here const progress = ProgressEvent.success>(model); return progress; @@ -138,8 +138,8 @@ class Resource extends BaseResource { request: ResourceHandlerRequest, callbackContext: CallbackContext, logger: LoggerProxy - ): Promise { - const model: ResourceModel = new ResourceModel(request.desiredResourceState); + ): Promise> { + const model = new ResourceModel(request.desiredResourceState); // TODO: put code here const progress = ProgressEvent.builder>() .status(OperationStatus.Success) @@ -149,7 +149,7 @@ class Resource extends BaseResource { } } -const resource = new Resource(ResourceModel.TYPE_NAME, ResourceModel); +export const resource = new Resource(ResourceModel.TYPE_NAME, ResourceModel); export const entrypoint = resource.entrypoint; diff --git a/src/exceptions.ts b/src/exceptions.ts index 85fe377..1c776af 100644 --- a/src/exceptions.ts +++ b/src/exceptions.ts @@ -1,4 +1,4 @@ -import { HandlerErrorCode } from './interface'; +import { BaseModel, HandlerErrorCode } from './interface'; import { ProgressEvent } from './proxy'; export abstract class BaseHandlerException extends Error { @@ -13,8 +13,8 @@ export abstract class BaseHandlerException extends Error { Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain } - public toProgressEvent(): ProgressEvent { - return ProgressEvent.failed(this.errorCode, this.toString()); + public toProgressEvent(): ProgressEvent { + return ProgressEvent.failed>(this.errorCode, this.toString()); } } diff --git a/src/log-delivery.ts b/src/log-delivery.ts index 09ef57c..3831944 100644 --- a/src/log-delivery.ts +++ b/src/log-delivery.ts @@ -1,4 +1,4 @@ -import { format } from 'util'; +import { format, inspect, InspectOptions } from 'util'; import { AWSError, Request } from 'aws-sdk'; import CloudWatchLogs, { DescribeLogStreamsResponse, @@ -563,6 +563,16 @@ export class LoggerProxy implements Logger { private readonly logPublishers = new Array(); private readonly queue = new Array(); + constructor(defaultOptions: InspectOptions = {}) { + // Allow passing Node.js inspect options, + // and change default depth from 4 to 10 + inspect.defaultOptions = { + ...inspect.defaultOptions, + depth: 10, + ...defaultOptions, + }; + } + public addLogPublisher(logPublisher: LogPublisher): void { this.logPublishers.push(logPublisher); } diff --git a/src/resource.ts b/src/resource.ts index bfba008..2757adc 100644 --- a/src/resource.ts +++ b/src/resource.ts @@ -41,11 +41,14 @@ const MUTATING_ACTIONS: [Action, Action, Action] = [ Action.Delete, ]; -export type HandlerSignature = Callable< +export type HandlerSignature = Callable< [Optional, any, Dict, LoggerProxy], - Promise + Promise> >; -export class HandlerSignatures extends Map {} +export class HandlerSignatures extends Map< + Action, + HandlerSignature +> {} class HandlerEvents extends Map {} /** @@ -69,8 +72,8 @@ function ensureSerialize(toResponse = false): MethodDecorat descriptor.value = async function ( event: any | Dict, context: any - ): Promise> { - const progress: ProgressEvent = await originalMethod.apply(this, [ + ): Promise | CfnResponse> { + const progress: ProgressEvent = await originalMethod.apply(this, [ event, context, ]); @@ -106,12 +109,12 @@ export abstract class BaseResource { private providerEventsLogger: CloudWatchLogPublisher | S3LogPublisher; constructor( - public typeName: string, - private modelCls: Constructor, - private handlers?: HandlerSignatures + public readonly typeName: string, + public readonly modelTypeReference: Constructor, + private handlers?: HandlerSignatures ) { this.typeName = typeName || ''; - this.handlers = handlers || new HandlerSignatures(); + this.handlers = handlers || new HandlerSignatures(); this.lambdaLogger = console; @@ -256,7 +259,10 @@ export abstract class BaseResource { } } - public addHandler = (action: Action, f: HandlerSignature): HandlerSignature => { + public addHandler = ( + action: Action, + f: HandlerSignature + ): HandlerSignature => { this.handlers.set(action, f); return f; }; @@ -266,24 +272,24 @@ export abstract class BaseResource { request: BaseResourceHandlerRequest, action: Action, callbackContext: Dict - ): Promise => { - const handle: HandlerSignature = this.handlers.get(action); - if (!handle) { - return ProgressEvent.failed( - HandlerErrorCode.InternalFailure, - `No handler for ${action}` - ); + ): Promise> => { + const actionName = action == null ? '' : action.toString(); + if (!this.handlers.has(action)) { + throw new Error(`Unknown action ${actionName}`); } + const handle: HandlerSignature = this.handlers.get(action); // We will make the callback context and resource states readonly // to avoid modification at a later time deepFreeze(callbackContext); deepFreeze(request); + this.log(`[${action}] invoking handler...`); const progress = await handle( session, request, callbackContext, this.loggerProxy ); + this.log(`[${action}] handler invoked`); const isInProgress = progress.status === OperationStatus.InProgress; const isMutable = MUTATING_ACTIONS.some((x) => x === action); if (isInProgress && !isMutable) { @@ -310,7 +316,7 @@ export abstract class BaseResource { ); } request = UnmodeledRequest.deserialize(event.request).toModeled( - this.modelCls + this.modelTypeReference ); this.callerSession = SessionProxy.getSession(creds, event.region); @@ -327,15 +333,18 @@ export abstract class BaseResource { // @ts-ignore public async testEntrypoint( eventData: any | Dict, - context: any - ): Promise; + context?: any + ): Promise>; @boundMethod @ensureSerialize() - public async testEntrypoint(eventData: Dict, context: any): Promise { + public async testEntrypoint( + eventData: Dict, + context?: any + ): Promise> { let msg = 'Uninitialized'; - let progress: ProgressEvent; + let progress: ProgressEvent; try { - if (!this.modelCls) { + if (!this.modelTypeReference) { throw new exceptions.InternalFailure( 'Missing Model class to be used to deserialize JSON data.' ); @@ -356,11 +365,14 @@ export abstract class BaseResource { err.stack = `${new Error().stack}\n${err.stack}`; if (err instanceof BaseHandlerException) { this.log(`Handler error: ${err.message}`, err); - progress = err.toProgressEvent(); + progress = err.toProgressEvent(); } else { this.log(`Exception caught: ${err.message}`, err); msg = err.message || msg; - progress = ProgressEvent.failed(HandlerErrorCode.InternalFailure, msg); + progress = ProgressEvent.failed>( + HandlerErrorCode.InternalFailure, + msg + ); } } return Promise.resolve(progress); @@ -411,7 +423,7 @@ export abstract class BaseResource { logicalResourceIdentifier: request.requestData.logicalResourceId, region: request.region, }); - return unmodeled.toModeled(this.modelCls); + return unmodeled.toModeled(this.modelTypeReference); } catch (err) { this.log('Invalid request'); throw new InvalidRequest(`${err} (${err.name})`); @@ -428,11 +440,11 @@ export abstract class BaseResource { public async entrypoint( eventData: Dict, context: LambdaContext - ): Promise { - let progress: ProgressEvent; + ): Promise> { + let progress: ProgressEvent; let bearerToken: string; try { - if (!this.modelCls) { + if (!this.modelTypeReference) { throw new exceptions.InternalFailure( 'Missing Model class to be used to deserialize JSON data.' ); @@ -495,10 +507,10 @@ export abstract class BaseResource { err.stack = `${new Error().stack}\n${err.stack}`; if (err instanceof BaseHandlerException) { this.log(`Handler error: ${err.message}`, err); - progress = err.toProgressEvent(); + progress = err.toProgressEvent(); } else { this.log(`Exception caught: ${err.message}`, err); - progress = ProgressEvent.failed( + progress = ProgressEvent.failed>( HandlerErrorCode.InternalFailure, err.message ); diff --git a/tests/data/sample-model.ts b/tests/data/sample-model.ts index fc218af..aed0cec 100644 --- a/tests/data/sample-model.ts +++ b/tests/data/sample-model.ts @@ -236,6 +236,7 @@ export class SerializableModel extends BaseModel { public static readonly TYPE_NAME: string = 'Organization::Service::Serializable'; @Expose() somekey?: Optional; + @Expose() somestring?: Optional; @Expose() someotherkey?: Optional; @Expose({ name: 'SomeInt' }) @Transform((value, obj) => transformValue(Integer, 'someint', value, obj), { diff --git a/tests/lib/interface.test.ts b/tests/lib/interface.test.ts index 4337246..94dd574 100644 --- a/tests/lib/interface.test.ts +++ b/tests/lib/interface.test.ts @@ -15,11 +15,14 @@ describe('when getting interface', () => { test('base resource model serialize', () => { const model = SerializableModel.deserialize({ somekey: 'a', + somestring: '', someotherkey: null, someint: null, }); const serialized = JSON.parse(JSON.stringify(model)); - expect(Object.keys(serialized).length).toBe(1); + expect(Object.keys(serialized).length).toBe(2); + expect(serialized.somekey).toBe('a'); + expect(serialized.somestring).toBe(''); expect(serialized.someotherkey).not.toBeDefined(); }); diff --git a/tests/lib/log-delivery.test.ts b/tests/lib/log-delivery.test.ts index 3bc2a0a..c287fcd 100644 --- a/tests/lib/log-delivery.test.ts +++ b/tests/lib/log-delivery.test.ts @@ -3,6 +3,7 @@ import CloudWatchLogs, { } from 'aws-sdk/clients/cloudwatchlogs'; import S3, { ListObjectsV2Output } from 'aws-sdk/clients/s3'; import awsUtil from 'aws-sdk/lib/util'; +import { inspect } from 'util'; import { SessionProxy } from '../../src/proxy'; import { MetricsPublisherProxy } from '../../src/metrics'; @@ -129,7 +130,7 @@ describe('when delivering logs', () => { if (name === 'CloudWatchLogs') return cwLogs(options); if (name === 'S3') return s3(options); }; - loggerProxy = new LoggerProxy(); + loggerProxy = new LoggerProxy({ depth: 8 }); metricsPublisherProxy = new MetricsPublisherProxy(); publishExceptionMetric = mockResult({ ResponseMetadata: { RequestId: 'mock-request' }, @@ -493,7 +494,9 @@ describe('when delivering logs', () => { code: 'AccessDeniedException', }) ), - on: () => {}, + on: (_event: string, callback: Function) => { + callback({ httpRequest: { headers: [] } }); + }, }); const msgToLog = 'How is it going?'; try { @@ -1213,6 +1216,7 @@ describe('when delivering logs', () => { loggerProxy.log('timestamp: [%s]', new Date('2020-01-03')); loggerProxy.log('timestamp: [%s]', new Date('2020-01-04')); expect(loggerProxy['queue'].length).toBe(9); + expect(inspect.defaultOptions.depth).toBe(8); await loggerProxy.processQueue(); expect(cloudWatchLogger['logStreamName']).toBe(LOG_STREAM_NAME); diff --git a/tests/lib/proxy.test.ts b/tests/lib/proxy.test.ts index ab3d5bc..fe03525 100644 --- a/tests/lib/proxy.test.ts +++ b/tests/lib/proxy.test.ts @@ -21,7 +21,7 @@ describe('when getting session proxy', () => { }); test('get session returns proxy', () => { - const proxy: SessionProxy = SessionProxy.getSession({ + const proxy = SessionProxy.getSession({ accessKeyId: '', secretAccessKey: '', sessionToken: '', @@ -31,14 +31,14 @@ describe('when getting session proxy', () => { }); test('get session returns null', () => { - const proxy: SessionProxy = SessionProxy.getSession(null); + const proxy = SessionProxy.getSession(null); expect(proxy).toBeNull(); }); test('progress event failed is json serializable', () => { - const errorCode: HandlerErrorCode = HandlerErrorCode.AlreadyExists; + const errorCode = HandlerErrorCode.AlreadyExists; const message = 'message of failed event'; - const event: ProgressEvent = ProgressEvent.failed(errorCode, message); + const event = ProgressEvent.failed(errorCode, message); expect(event.status).toBe(OperationStatus.Failed); expect(event.errorCode).toBe(errorCode); expect(event.message).toBe(message); @@ -76,7 +76,7 @@ describe('when getting session proxy', () => { someotherkey: 'b', somenullkey: null, }); - const event = ProgressEvent.progress(model, null); + const event = ProgressEvent.progress>(model, null); event.message = message; const serialized = event.serialize(); expect(serialized).toMatchObject({ @@ -102,7 +102,7 @@ describe('when getting session proxy', () => { someotherkey: 'd', }), ]; - const event = new ProgressEvent({ + const event = new ProgressEvent({ status: OperationStatus.Success, message, resourceModels: models, diff --git a/tests/lib/recast.test.ts b/tests/lib/recast.test.ts index 95525e7..7187c9e 100644 --- a/tests/lib/recast.test.ts +++ b/tests/lib/recast.test.ts @@ -34,7 +34,7 @@ describe('when recasting objects', () => { ListListInt: [['1', '2', '3', '']], ListSetInt: [['1', '2', '3']], ASet: ['1', '2', '3'], - AnotherSet: ['a', 'b', 'c'], + AnotherSet: ['a', 'b', 'c', ''], AFreeformDict: { somekey: 'somevalue', someotherkey: '1' }, ANumberDict: { key: '52.76' }, AnInt: '1', @@ -66,7 +66,7 @@ describe('when recasting objects', () => { ListListInt: [[1, 2, 3, null]], ListListAny: [[{ key: 'val' }]], ASet: new Set(['1', '2', '3']), - AnotherSet: new Set(['a', 'b', 'c']), + AnotherSet: new Set(['a', 'b', 'c', '']), AFreeformDict: new Map([ ['somekey', 'somevalue'], ['someotherkey', '1'], @@ -147,8 +147,10 @@ describe('when recasting objects', () => { const bool = recastPrimitive(Boolean, k, v); const num = recastPrimitive(Number, k, v); const int = recastPrimitive(BigInt, k, v); + const string = recastPrimitive(String, k, v); expect(bool).toBeNull(); expect(num).toBeNull(); expect(int).toBeNull(); + expect(string).toBe(''); }); }); diff --git a/tests/lib/resource.test.ts b/tests/lib/resource.test.ts index 2c8275f..36db98a 100644 --- a/tests/lib/resource.test.ts +++ b/tests/lib/resource.test.ts @@ -42,11 +42,11 @@ describe('when getting resource', () => { let spySessionClient: jest.SpyInstance; let spyInitializeRuntime: jest.SpyInstance; const TYPE_NAME = 'Test::Foo::Bar'; - class Resource extends BaseResource {} class MockModel extends SimpleStateModel { ['constructor']: typeof MockModel; public static readonly TYPE_NAME: string = TYPE_NAME; } + class Resource extends BaseResource {} beforeEach(() => { const mockCloudformation = (CloudFormation as unknown) as jest.Mock; @@ -120,7 +120,7 @@ describe('when getting resource', () => { jest.restoreAllMocks(); }); - const getResource = (handlers?: HandlerSignatures) => { + const getResource = (handlers?: HandlerSignatures): Resource => { const instance = new Resource(TYPE_NAME, MockModel, handlers); return instance; }; @@ -204,6 +204,7 @@ describe('when getting resource', () => { }); test('entrypoint redacting credentials', async () => { + expect.assertions(13); const spyPublishLogEvent = jest.spyOn( LogPublisher.prototype, 'publishLogEvent' @@ -217,29 +218,31 @@ describe('when getting resource', () => { const resource = new Resource(TYPE_NAME, MockModel); entrypointPayload['action'] = 'READ'; const mockHandler: jest.Mock = jest.fn(() => ProgressEvent.success()); - resource.addHandler(Action.Create, mockHandler); + resource.addHandler(Action.Read, mockHandler); await resource.entrypoint(entrypointPayload, null); expect(spySession).toHaveBeenCalled(); expect(spySessionClient).toBeCalledTimes(3); expect(spyPrepareLogStream).toBeCalledTimes(1); - expect(spyPublishLogEvent).toHaveBeenCalledTimes(2); - expect(mockPublishMessage).toHaveBeenCalledTimes(2); + expect(spyPublishLogEvent).toHaveBeenCalled(); + expect(mockPublishMessage).toHaveBeenCalled(); mockPublishMessage.mock.calls.forEach((value: any[]) => { - const message = value[0]; - expect(message).toMatch(/bearerToken: ''/); - expect(message).toMatch( - /providerCredentials: {\s+accessKeyId: '',\s+secretAccessKey: '',\s+sessionToken: ''\s+}/ - ); - expect(message).toMatch( - /callerCredentials: {\s+accessKeyId: '',\s+secretAccessKey: '',\s+sessionToken: ''\s+}/ - ); - expect(message).toMatch(/stack\/sample-stack\//); + const message = value[0] as string; + if (message && message.startsWith('entrypoint event data')) { + expect(message).toMatch(/bearerToken: ''/); + expect(message).toMatch( + /providerCredentials: {\s+accessKeyId: '',\s+secretAccessKey: '',\s+sessionToken: ''\s+}/ + ); + expect(message).toMatch( + /callerCredentials: {\s+accessKeyId: '',\s+secretAccessKey: '',\s+sessionToken: ''\s+}/ + ); + expect(message).toMatch(/stack\/sample-stack\//); + } }); }); test('entrypoint with callback context', async () => { entrypointPayload['callbackContext'] = { a: 'b' }; - const event: ProgressEvent = ProgressEvent.success(null, { c: 'd' }); + const event = ProgressEvent.success(null, { c: 'd' }); const mockHandler: jest.Mock = jest.fn(() => event); const resource = new Resource(TYPE_NAME, MockModel); resource.addHandler(Action.Create, mockHandler); @@ -260,7 +263,7 @@ describe('when getting resource', () => { test('entrypoint without callback context', async () => { entrypointPayload['callbackContext'] = null; - const event: ProgressEvent = ProgressEvent.progress(null, { c: 'd' }); + const event = ProgressEvent.progress(null, { c: 'd' }); event.callbackDelaySeconds = 5; const mockHandler: jest.Mock = jest.fn(() => event); const resource = new Resource(TYPE_NAME, MockModel); @@ -421,7 +424,7 @@ describe('when getting resource', () => { test('entrypoint uncaught exception', async () => { const mockParseRequest = jest.spyOn(BaseResource, 'parseRequest'); mockParseRequest.mockImplementationOnce(() => { - throw new Error('exception'); + throw { message: 'exception' }; }); const resource = getResource(); const event = await resource.entrypoint({}, null); @@ -432,7 +435,7 @@ describe('when getting resource', () => { }); test('add handler', () => { - class ResourceEventHandler extends BaseResource { + class ResourceEventHandler extends BaseResource { @handlerEvent(Action.Create) public create(): void {} @handlerEvent(Action.Read) @@ -444,7 +447,7 @@ describe('when getting resource', () => { @handlerEvent(Action.List) public list(): void {} } - const handlers: HandlerSignatures = new HandlerSignatures(); + const handlers = new HandlerSignatures(); const resource = new ResourceEventHandler(null, null, handlers); expect(resource['handlers'].get(Action.Create)).toBe(resource.create); expect(resource['handlers'].get(Action.Read)).toBe(resource.read); @@ -456,17 +459,17 @@ describe('when getting resource', () => { test('check resource instance and type name', async () => { class ResourceEventHandler extends BaseResource { @handlerEvent(Action.Create) - public async create(): Promise { - const progress: ProgressEvent = ProgressEvent.builder() + public async create(): Promise> { + const progress = ProgressEvent.builder>() .message(this.typeName) .status(OperationStatus.Success) .resourceModels([]) - .build() as ProgressEvent; + .build(); return progress; } } const spyCreate = jest.spyOn(ResourceEventHandler.prototype, 'create'); - const handlers: HandlerSignatures = new HandlerSignatures(); + const handlers = new HandlerSignatures(); const resource = new ResourceEventHandler(TYPE_NAME, MockModel, handlers); const event = await resource.testEntrypoint(testEntrypointPayload, null); expect(spyCreate).toHaveReturnedTimes(1); @@ -475,29 +478,26 @@ describe('when getting resource', () => { }); test('invoke handler not found', async () => { + expect.assertions(1); const resource = getResource(); const callbackContext = {}; - const actual = await resource['invokeHandler']( - null, - null, - Action.Create, - callbackContext - ); - const expected = ProgressEvent.failed( - HandlerErrorCode.InternalFailure, - 'No handler for CREATE' - ); - expect(actual).toStrictEqual(expected); + try { + await resource['invokeHandler'](null, null, Action.Create, callbackContext); + } catch (e) { + expect(e).toMatchObject({ + message: 'Unknown action CREATE', + }); + } }); test('invoke handler was found', async () => { - const event: ProgressEvent = ProgressEvent.progress(); + const event = ProgressEvent.progress(); const mockHandler: jest.Mock = jest.fn(() => event); - const handlers: HandlerSignatures = new HandlerSignatures(); + const handlers = new HandlerSignatures(); handlers.set(Action.Create, mockHandler); const resource = getResource(handlers); const session = new SessionProxy({}); - const request = new BaseResourceHandlerRequest(); + const request = new BaseResourceHandlerRequest(); const callbackContext = {}; const response = await resource['invokeHandler']( session, @@ -519,7 +519,7 @@ describe('when getting resource', () => { const promises: any[] = []; [Action.List, Action.Read].forEach(async (action: Action) => { const mockHandler: jest.Mock = jest.fn(() => ProgressEvent.progress()); - const handlers: HandlerSignatures = new HandlerSignatures(); + const handlers = new HandlerSignatures(); handlers.set(action, mockHandler); const resource = getResource(handlers); const callbackContext = {}; @@ -540,9 +540,9 @@ describe('when getting resource', () => { }); test('invoke handler try object modification', async () => { - const event: ProgressEvent = ProgressEvent.progress(); + const event = ProgressEvent.progress(); const mockHandler: jest.Mock = jest.fn(() => event); - const handlers: HandlerSignatures = new HandlerSignatures(); + const handlers = new HandlerSignatures(); handlers.set(Action.Create, mockHandler); const resource = getResource(handlers); const callbackContext = { @@ -633,7 +633,7 @@ describe('when getting resource', () => { test('test entrypoint handler error', async () => { const resource = getResource(); - const event: ProgressEvent = await resource.testEntrypoint({}, null); + const event = await resource.testEntrypoint({}, null); expect(event.status).toBe(OperationStatus.Failed); expect(event.errorCode).toBe(HandlerErrorCode.InternalFailure); }); @@ -642,9 +642,9 @@ describe('when getting resource', () => { const resource = getResource(); const mockParseRequest = jest.spyOn(resource, 'parseTestRequest'); mockParseRequest.mockImplementationOnce(() => { - throw new Error('exception'); + throw { message: 'exception' }; }); - const event: ProgressEvent = await resource.testEntrypoint({}, null); + const event = await resource.testEntrypoint({}, null); expect(event.status).toBe(OperationStatus.Failed); expect(event.errorCode).toBe(HandlerErrorCode.InternalFailure); expect(event.message).toBe('exception'); @@ -664,7 +664,7 @@ describe('when getting resource', () => { const spyDeserialize: jest.SpyInstance = jest.spyOn(MockModel, 'deserialize'); const resource = new Resource(TYPE_NAME, MockModel); - const progressEvent: ProgressEvent = ProgressEvent.progress(); + const progressEvent = ProgressEvent.progress(); const mockHandler: jest.Mock = jest.fn(() => progressEvent); resource.addHandler(Action.Create, mockHandler); const event = await resource.testEntrypoint(testEntrypointPayload, null);