Skip to content

Commit

Permalink
Increase coverage, change error text
Browse files Browse the repository at this point in the history
  • Loading branch information
pyldin601 committed Feb 8, 2018
1 parent 9710d33 commit f2b6c84
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 181 deletions.
156 changes: 78 additions & 78 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,78 +1,78 @@
# long-long-job

[![Build Status](https://travis-ci.org/pldin601/long-long-job.svg?branch=master)](https://travis-ci.org/pldin601/long-long-job)
[![Coverage Status](https://coveralls.io/repos/github/pldin601/long-long-job/badge.svg?branch=master)](https://coveralls.io/github/pldin601/long-long-job?branch=master)

```basic
10 PRINT "HELLO"
20 GOTO 10
```

## What?

This module ables you to create a chain of tasks (computations or actions) with ability to resume run state on restart.
Each task receives state of previous task (or initial state if it is first in chain) and must return action what to do next composed with new state.

## Example

First of all we need to define where job's state will be stored during transitions. Then we must initialize module with it.
For example, we will store state in `Map` object. This is simplest storage method and it won't preserve state during restarts.

### LongLongJob.js

```javascript
const { longLongJob } = require('long-long-job');

const mapBasedStorage = () => {
const stateStore = new Map();
return {
async hasState(id) {
return stateStore.has(id);
},
async setState(id, state) {
stateStore.set(id, state);
},
async getState(id) {
return stateStore.get(id);
},
async clean(id) {
stateStore.delete(id);
},
};
};

module.exports = longLongJob(mapBasedStorage());
```

### incrementJob.js

```javascript
const LongLongJob = require('./LongLongJob');
const { repeat, next } = require('long-long-job');

const incrementJob = new LongLongJob('increment-job', [
async ({ value, threshold }) => {
incrementJob.emit('tick', value);
return value < threshold
? repeat({ value: value + 1, threshold })
: next({ value, threshold });
},
]);

module.exports = incrementJob;
```

### main.js

```javascript
const incrementJob = require('./incrementJob');

incrementJob.on('start', () => console.log('Job started'));
incrementJob.on('resume', () => console.log('Job resumed'));
incrementJob.on('tick', value => console.log('Current value is %d', value));
incrementJob.on('done', () => console.log('Job finished'));

incrementJob
.start({ value: 0, threshold: 1000 })
.then(({ value }) => console.log('Task is done with value %d', value));
```
# long-long-job

[![Build Status](https://travis-ci.org/pldin601/long-long-job.svg?branch=master)](https://travis-ci.org/pldin601/long-long-job)
[![Coverage Status](https://coveralls.io/repos/github/pldin601/long-long-job/badge.svg?branch=master)](https://coveralls.io/github/pldin601/long-long-job?branch=master)

```basic
10 PRINT "HELLO"
20 GOTO 10
```

## What?

This module ables you to create a chain of tasks (computations or actions) with ability to resume run state on restart.
Each task receives state of previous task (or initial state if it is first in chain) and must return action what to do next composed with new state.

## Example

First of all we need to define where job's state will be stored during transitions. Then we must initialize module with it.
For example, we will store state in `Map` object. This is simplest storage method and it won't preserve state during restarts.

### LongLongJob.js

```javascript
const { longLongJob } = require('long-long-job');

const mapBasedStorage = () => {
const stateStore = new Map();
return {
async hasState(id) {
return stateStore.has(id);
},
async setState(id, state) {
stateStore.set(id, state);
},
async getState(id) {
return stateStore.get(id);
},
async clean(id) {
stateStore.delete(id);
},
};
};

module.exports = longLongJob(mapBasedStorage());
```

### incrementJob.js

```javascript
const LongLongJob = require('./LongLongJob');
const { repeat, next } = require('long-long-job');

const incrementJob = new LongLongJob('increment-job', [
async ({ value, threshold }) => {
incrementJob.emit('tick', value);
return value < threshold
? repeat({ value: value + 1, threshold })
: next({ value, threshold });
},
]);

module.exports = incrementJob;
```

### main.js

```javascript
const incrementJob = require('./incrementJob');

incrementJob.on('start', () => console.log('Job started'));
incrementJob.on('resume', () => console.log('Job resumed'));
incrementJob.on('tick', value => console.log('Current value is %d', value));
incrementJob.on('done', () => console.log('Job finished'));

incrementJob
.start({ value: 0, threshold: 1000 })
.then(({ value }) => console.log('Task is done with value %d', value));
```
66 changes: 51 additions & 15 deletions __test__/runner.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @flow
import factory from '../src/LongLongJob';
import { next, repeat, goto, label } from '../src';
import { next, repeat, goto, label, done, chain } from '../src';

const stateStore = new Map();

Expand Down Expand Up @@ -28,52 +28,62 @@ describe('Runner tests', () => {
});

test('Simple tasks chain (full)', async () => {
const job = new LongLongJob('test-job-2', [
const job = new LongLongJob('test-job-2', chain(
async state => next(state + 10),
async state => next(state * 2),
]);
));
const initialState = 5;
expect(await job.start(initialState)).toEqual(30);
});

test('Simple tasks chain (resume)', async () => {
stateStore.set('test-job-3', { cursor: 1, state: 15 });
const job = new LongLongJob('test-job-3', [
const job = new LongLongJob('test-job-3', chain(
async state => next(state + 10),
async state => next(state * 2),
]);
));
const initialState = 5;
expect(await job.start(initialState)).toEqual(30);
});

test('Tasks chain with repeat', async () => {
const job = new LongLongJob('test-job-4', [
const job = new LongLongJob('test-job-4', chain(
async state => next(state + 10),
async state => (state < 1000 ? repeat(state * 2) : next(state)),
]);
));
const initialState = 5;
expect(await job.start(initialState)).toEqual(1920);
});

test('Tasks chain with label', async () => {
const job = new LongLongJob('test-job-5', [
const job = new LongLongJob('test-job-5', chain(
label('begin'),
async state => next(state + 10),
async state => (state < 1000 ? goto('begin', state * 2) : next(state)),
]);
));
const initialState = 5;
expect(await job.start(initialState)).toEqual(1590);
});

test('Test done action', async () => {
const job = new LongLongJob('test-job-5', chain(
label('begin'),
async state => done(state + 10),
async state => (state < 1000 ? goto('begin', state * 2) : next(state)),
));
const initialState = 5;
expect(await job.start(initialState)).toEqual(15);
});

test('Test event emitter (start)', async () => {
const onStart = jest.fn();
const onResume = jest.fn();
const onDone = jest.fn();

const job = new LongLongJob('test-job-6', [
const job = new LongLongJob('test-job-6', chain(
async state => next(state + 10),
async state => next(state * 2),
]);
));
const initialState = 5;

job.on('start', onStart);
Expand All @@ -98,10 +108,10 @@ describe('Runner tests', () => {
const onResume = jest.fn();
const onDone = jest.fn();

const job = new LongLongJob('test-job-7', [
const job = new LongLongJob('test-job-7', chain(
async state => next(state + 10),
async state => next(state * 2),
]);
));
const initialState = 5;

job.on('start', onStart);
Expand All @@ -120,7 +130,7 @@ describe('Runner tests', () => {
});

test('Test termination', async () => {
const job = new LongLongJob('inc-dec', [
const job = new LongLongJob('inc-dec', chain(
async ({ initial }) => goto('inc', { current: initial, threshold: initial + 10 }),

label('inc'),
Expand All @@ -136,7 +146,7 @@ describe('Runner tests', () => {
current > threshold
? repeat({ current: current - 1, threshold })
: goto('inc', { current, threshold: current + 12 }),
]);
));

job.on('tick', (current) => {
if (current > 50) {
Expand All @@ -146,4 +156,30 @@ describe('Runner tests', () => {

await expect(job.start({ initial: 0 })).rejects.toEqual(new Error('Job terminated'));
});

test('Wrong return from task', async () => {
const job = new LongLongJob('wrong-return', chain(
async () => 'foo',
));

await expect(job.start()).rejects.toEqual(new Error('Task should return an action'));
});

test('Start already started job', async () => {
const job = new LongLongJob('wrong-return', chain(
async () => next('foo'),
));

job.start();

await expect(job.start()).rejects.toEqual(new Error('Already started'));
});

test('Got non-existent label', async () => {
const job = new LongLongJob('wrong-label', chain(
async () => goto('foo'),
));

await expect(job.start()).rejects.toEqual(new Error('Label "foo" does not exist'));
});
});
Loading

0 comments on commit f2b6c84

Please sign in to comment.