Skip to content
This repository was archived by the owner on Aug 1, 2022. It is now read-only.

Commit 8071e71

Browse files
Merge pull request #104 from sam-n-johnston/feat/use-name-in-description-and-bugfix
2 parents 7076339 + d85f5a1 commit 8071e71

File tree

11 files changed

+94
-34
lines changed

11 files changed

+94
-34
lines changed

README.md

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ If the plugin is being useful in your company and/or project and want to keep th
2323

2424
## Requirements
2525

26+
- [serverless](https://github.com/serverless/serverless)
2627
- [serverless-offline](https://github.com/dherault/serverless-offline)
2728
- [serverless-step-functions plugin](https://github.com/serverless-operations/serverless-step-functions)
2829
- [serverless-webpack (optional)](https://github.com/serverless-heaven/serverless-webpack)
@@ -67,16 +68,16 @@ plugins:
6768

6869
## State Types Supported
6970

70-
| States | Notes |
71-
| ------ | ------ |
72-
| ***Task*** | Retry/Catch now supported!, `Timeout` and `Heartbeat` are not supported yet. |
73-
| ***Choice*** | ✅ |
74-
| ***Wait*** | ✅ |
75-
| ***Parallel*** | Not Supported at all yet. |
76-
| ***Pass*** | ✅ |
77-
| ***Fail***| ✅ |
78-
| ***Succeed***|✅|
79-
| ***Map*** | Basic Support ✅ |
71+
| States | Notes |
72+
| -------------- | ---------------------------------------------------------------------------------- |
73+
| **_Task_** | Basic Retry/Catch now supported!, `Timeout` and `Heartbeat` are not supported yet. |
74+
| **_Choice_** | ✅ |
75+
| **_Wait_** | ✅ |
76+
| **_Parallel_** | Not Supported at all yet. |
77+
| **_Pass_** | ✅ |
78+
| **_Fail_** | ✅ |
79+
| **_Succeed_** | ✅ |
80+
| **_Map_** | Not Supported at all yet. |
8081

8182
## Credits and inspiration
8283

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@fernthedev/serverless-offline-step-functions",
3-
"version": "1.0.0-alpha.13",
3+
"version": "1.0.0-alpha.14",
44
"description": "Serverless Offline Plugin to Support Step Functions for Local Development",
55
"main": "dist/main.js",
66
"types": "dist/main.d.ts",

src/StateMachine/StateMachine.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { StateMachineDefinition, StateMachineDescription } from '../types/StateMachineDescription';
2+
3+
export class StateMachine {
4+
private constructor(
5+
private readonly _stateMachineKey: string,
6+
private readonly _stateMachineDescription: StateMachineDescription,
7+
) {}
8+
9+
public static create(stateMachineKey: string, stateMachineDescription: StateMachineDescription): StateMachine {
10+
return new StateMachine(stateMachineKey, stateMachineDescription);
11+
}
12+
13+
public get definition(): StateMachineDefinition {
14+
return this._stateMachineDescription.definition;
15+
}
16+
17+
public get name(): string {
18+
return this._stateMachineDescription.name || this._stateMachineKey;
19+
}
20+
}

src/StateMachine/StateMachines.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { StateMachinesDescription } from '../types/StateMachineDescription';
2+
import { StateMachine } from './StateMachine';
3+
4+
export class StateMachines {
5+
private constructor(private readonly _stateMachines: StateMachine[]) {}
6+
7+
public static create(stateMachines: StateMachinesDescription): StateMachines {
8+
const stateMachineTupleArray = Object.entries(stateMachines);
9+
const stateMachineArray = stateMachineTupleArray.map(([key, val]) => StateMachine.create(key, val));
10+
11+
return new StateMachines(stateMachineArray);
12+
}
13+
14+
public getStateMachineBy(name: string): StateMachine {
15+
return this._stateMachines.filter((val) => val.name === name)[0];
16+
}
17+
18+
public get stateMachines(): StateMachine[] {
19+
return this._stateMachines;
20+
}
21+
}

src/StateMachineExecutor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import type { StateMachine } from './types/StateMachine';
21
import type { StateDefinition, TaskStateDefinition } from './types/State';
32

43
import { StateTypeExecutorFactory } from './stateTasks/StateTypeExecutorFactory';
@@ -7,6 +6,7 @@ import { Logger } from './utils/Logger';
76
import { Context } from './Context/Context';
87
import { StateContext } from './Context/StateContext';
98
import { ContextToJson } from './Context/ContextToJson';
9+
import { StateMachine } from './StateMachine/StateMachine';
1010
import { isJsonByteLengthValid } from './utils/isJsonByteLengthValid';
1111

1212
export type ExecuteType = () => Promise<ExecuteType | string | void>;
@@ -40,7 +40,7 @@ export class StateMachineExecutor {
4040

4141
this.logger.debug(`StateMachineExecutor - execute1 - ${stateExecutorOutput}`);
4242

43-
if (isJsonByteLengthValid(stateExecutorOutput.json)) {
43+
if (!isJsonByteLengthValid(stateExecutorOutput.json)) {
4444
this.logger.error(
4545
`The state/task '${this.context.State.Name}' returned a result with a size exceeding the maximum number of bytes service limit.`,
4646
);

src/StateProcessor.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,12 @@ export class StateProcessor {
8787
return JSON.stringify(input);
8888
}
8989

90-
public static processOutputPath(json: string, outputPath?: string): string {
90+
public static processOutputPath(json?: string, outputPath?: string): string {
91+
// TODO: check if AWS throws or skips this
92+
if (!json) {
93+
throw new Error('Output JSON of lambda was undefined');
94+
}
95+
9196
const result = JSONPath({
9297
path: outputPath || '$',
9398
json: JSON.parse(json),

src/StepFunctionSimulatorServer.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ import { createHttpTerminator, HttpTerminator } from 'http-terminator';
22
import express, { Express, Request, Response } from 'express';
33
import type { StepFunctions } from 'aws-sdk';
44

5-
import type { StateMachines } from './types/StateMachine';
65
import type { StateDefinition } from './types/State';
76
import { ExecuteType, StateMachineExecutor } from './StateMachineExecutor';
87
import { Logger } from './utils/Logger';
98
import { StateMachineContext } from './Context/StateMachineContext';
109
import { ExecutionContext } from './Context/ExecutionContext';
1110
import { Context } from './Context/Context';
1211
import { StateContext } from './Context/StateContext';
12+
import { StateMachines } from './StateMachine/StateMachines';
1313

1414
export type StepFunctionSimulatorServerOptions = {
1515
port: number;
@@ -21,11 +21,13 @@ export class StepFunctionSimulatorServer {
2121
private httpTerminator?: HttpTerminator;
2222
// TODO: Move State Machines and type it
2323
private options: StepFunctionSimulatorServerOptions;
24+
private stateMachines: StateMachines;
2425
private readonly logger: Logger;
2526
private pendingStateMachineExecutions: { [key: string]: ExecuteType } = {};
2627

2728
constructor(options: StepFunctionSimulatorServerOptions) {
2829
this.options = options;
30+
this.stateMachines = this.options.stateMachines;
2931
this.logger = Logger.getInstance();
3032
this.express = express();
3133
this.setupMiddlewares();
@@ -97,10 +99,12 @@ export class StepFunctionSimulatorServer {
9799

98100
const executionInput: StepFunctions.Types.StartExecutionInput = req.body;
99101
const stateMachineContext = StateMachineContext.create(executionInput.stateMachineArn);
100-
const stateMachineToExecute = this.options.stateMachines[stateMachineContext.Name];
102+
const stateMachineToExecute = this.stateMachines.getStateMachineBy(stateMachineContext.Name);
101103

102104
if (!stateMachineToExecute) {
103-
return res.status(500);
105+
const message = `No state machine with name ${stateMachineContext.Name} exists in the serverless`;
106+
this.logger.error(message);
107+
return res.status(200).send({ message });
104108
}
105109

106110
const executionContext = ExecutionContext.create(stateMachineContext, executionInput.input);

src/main.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import { Logger } from './utils/Logger';
1010
import { MapStateDefinition, StateDefinition, TaskStateDefinition } from './types/State';
1111
import { StateType } from './stateTasks/StateType';
1212
import { EnvVarResolver } from './utils/EnvVarResolver';
13+
import { StateMachines } from './StateMachine/StateMachines';
14+
import { StateMachinesDescription } from './types/StateMachineDescription';
1315

1416
class ServerlessOfflineStepFunctionsPlugin {
1517
public hooks?: ServerlessOfflineHooks;
@@ -62,13 +64,19 @@ class ServerlessOfflineStepFunctionsPlugin {
6264
envVarResolver.injectGlobalEnvVars();
6365

6466
// Get Handler and Path of the Local Functions
65-
const definedStateMachines = this.serverless.service.initialServerlessConfig?.stepFunctions?.stateMachines;
67+
const definedStateMachines: StateMachinesDescription = this.serverless.service.initialServerlessConfig
68+
?.stepFunctions?.stateMachines;
6669

67-
this.resolveHandlers(definedStateMachines);
70+
const stateMachines = StateMachines.create(definedStateMachines);
71+
72+
if (!stateMachines) {
73+
throw new Error('No step machines defined');
74+
}
75+
this.resolveHandlers(stateMachines);
6876

6977
this.stepFunctionSimulatorServer = new StepFunctionSimulatorServer({
7078
port: this.options?.port || 8014,
71-
stateMachines: definedStateMachines,
79+
stateMachines,
7280
});
7381
}
7482

@@ -149,14 +157,12 @@ class ServerlessOfflineStepFunctionsPlugin {
149157
}
150158
}
151159

152-
private resolveHandlers(definedStateMachines: any) {
153-
const definedStateMachinesArr = Object.entries(definedStateMachines);
154-
160+
private resolveHandlers(definedStateMachines: StateMachines) {
155161
// Per StateMachine
156-
for (const [stateMachineName, stateMachineOptions] of definedStateMachinesArr) {
157-
const states: [string, StateDefinition][] = Object.entries((stateMachineOptions as any).definition.States);
162+
for (const stateMachine of definedStateMachines.stateMachines) {
163+
const states: [string, StateDefinition][] = Object.entries(stateMachine.definition.States);
158164

159-
this.setStateInfo(states, stateMachineName);
165+
this.setStateInfo(states, stateMachine.name);
160166
}
161167
}
162168
}

src/stateTasks/executors/MapExecutor.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import type { MapStateDefinition } from '../../types/State';
44

55
import { Context } from '../../Context/Context';
66
import { ExecuteType, StateMachineExecutor } from '../../StateMachineExecutor';
7-
import { StateMachine } from '../../types/StateMachine';
87
import { StateContext } from '../../Context/StateContext';
98
import { StateProcessor } from '../../StateProcessor';
9+
import { StateMachineDescription } from '../../types/StateMachineDescription';
10+
import { StateMachine } from '../../StateMachine/StateMachine';
1011

1112
export class MapExecutor extends StateTypeExecutor {
1213
private pendingStateMachineExecutions: { [key: string]: ExecuteType } = {};
@@ -16,10 +17,12 @@ export class MapExecutor extends StateTypeExecutor {
1617
stateDefinition: MapStateDefinition,
1718
inputJson: string | undefined,
1819
): Promise<StateExecutorOutput> {
19-
const stateMachine: StateMachine = {
20-
name: stateDefinition.Comment || '',
20+
const stateMachineDescription: StateMachineDescription = {
21+
name: stateDefinition.Comment,
2122
definition: stateDefinition.Iterator,
2223
};
24+
25+
const stateMachine = StateMachine.create(stateMachineDescription.name || '', stateMachineDescription);
2326
// TODO: Extract common logic from StepFunctionSimulatorServer
2427
// TODO: Make nested Maps work
2528
// TODO: Make the waitForTaskToken work in Map & nested maps

src/types/State.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { StateMachineDefinition } from './StateMachine';
1+
import type { StateMachineDefinition } from './StateMachineDescription';
22
import { StateType } from '../stateTasks/StateType';
33
import { StatesErrors } from './StatesErrors';
44

src/types/StateMachine.ts renamed to src/types/StateMachineDescription.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ export type StateMachineDefinition = {
77
};
88
};
99

10-
export type StateMachine = {
11-
name: string;
10+
export type StateMachineDescription = {
11+
name?: string;
1212
definition: StateMachineDefinition;
1313
};
1414

1515
// TODO: Temporal, move to Serverless type
16-
export type StateMachines = {
17-
[key: string]: StateMachine;
16+
export type StateMachinesDescription = {
17+
[key: string]: StateMachineDescription;
1818
};

0 commit comments

Comments
 (0)