Skip to content

Commit

Permalink
feat: ensure that unexpected result shape triggers an error
Browse files Browse the repository at this point in the history
  • Loading branch information
gajus committed Nov 26, 2020
1 parent 674175e commit 4d8ac2b
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 0 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"dependencies": {
"@types/roarr": "^2.14.2",
"@types/set-interval-async": "^1.0.0",
"es6-error": "^4.1.1",
"roarr": "^2.15.4"
},
"description": "Database-agnostic task scheduler.",
Expand Down
28 changes: 28 additions & 0 deletions src/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// @flow

/* eslint-disable fp/no-class, fp/no-this */

import ExtendableError from 'es6-error';

export class UnexpectedStateError extends ExtendableError {
code: string;

constructor (message: string, code = 'UNEXPECTED_STATE_ERROR') {
super(message);

this.code = code;
}
}

export class UnexpectedTaskInstructionsError extends UnexpectedStateError {
unexpectedTaskInstructions: any;

constructor (unexpectedTaskInstructions: any) {
super(
'Unexpected task instruction shape.',
'UNEXPECTED_TASK_INSTRUCTION_SHAPE',
);

this.unexpectedTaskInstructions = unexpectedTaskInstructions;
}
}
25 changes: 25 additions & 0 deletions src/factories/createPlanton.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import delay from 'delay';
import Logger from '../Logger';
import {
UnexpectedTaskInstructionsError,
} from '../errors';
import type {
Emitter,
} from '../types';
Expand Down Expand Up @@ -125,6 +128,28 @@ const createPlanton = (configuration: PlantonConfigurationInput): Planton => {
taskInstructions = [];
}

if (!Array.isArray(taskInstructions)) {
events.emit('error', {
error: new UnexpectedTaskInstructionsError(taskInstructions),
taskName: task.name || '',
});

taskInstructions = [];
}

for (const taskInstruction of taskInstructions) {
if (typeof taskInstruction !== 'string') {
events.emit('error', {
error: new UnexpectedTaskInstructionsError(taskInstructions),
taskName: task.name || '',
});

taskInstructions = [];

break;
}
}

if (taskInstructions.length > 0) {
task.attemptNumber = 0;

Expand Down
82 changes: 82 additions & 0 deletions test/planton/factories/createPlanton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,88 @@ test('unhandled scheduler errors trigger error event', async (t) => {
});
});

test('unexpected scheduler result shape triggers an error (not array)', async (t) => {
const eventHandler = sinon.spy();

const planton = createPlanton({
getActiveTaskInstructions: () => {
return [];
},
tasks: [
{
delay: () => {
return 50;
},
name: 'foo',

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
schedule: async () => {
return {
foo: 'bar',
};
},
},
],
});

planton.events.on('error', eventHandler);

await delay(40);

t.is(eventHandler.callCount, 1);

t.like(eventHandler.firstCall.firstArg.error, {
code: 'UNEXPECTED_TASK_INSTRUCTION_SHAPE',
unexpectedTaskInstructions: {
foo: 'bar',
},
});
});

test('unexpected scheduler result shape triggers an error (not an array of string literals)', async (t) => {
const eventHandler = sinon.spy();

const planton = createPlanton({
getActiveTaskInstructions: () => {
return [];
},
tasks: [
{
delay: () => {
return 50;
},
name: 'foo',

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
schedule: async () => {
return [
{
foo: 'bar',
},
];
},
},
],
});

planton.events.on('error', eventHandler);

await delay(40);

t.is(eventHandler.callCount, 1);

t.like(eventHandler.firstCall.firstArg.error, {
code: 'UNEXPECTED_TASK_INSTRUCTION_SHAPE',
unexpectedTaskInstructions: [
{
foo: 'bar',
},
],
});
});

test('high-frequency issues do not block other tasks', async (t) => {
const foo = sinon
.stub()
Expand Down

0 comments on commit 4d8ac2b

Please sign in to comment.