Initial release
[websub-hub] / test / src / worker.js
1 /* eslint-env mocha */
2 'use strict';
3
4 const assert = require('assert');
5 const sinon = require('sinon'); // eslint-disable-line node/no-unpublished-require
6
7 const Worker = require('../../src/worker');
8 const Config = require('../../config');
9
10 const stubLogger = require('../stub-logger');
11
12 const noExpectedException = 'did not get expected exception';
13
14 describe('Worker', function () {
15 let config;
16 let worker;
17 let promiseGiver;
18
19 beforeEach(function () {
20 config = new Config('test');
21 promiseGiver = sinon.stub();
22 worker = new Worker(stubLogger, promiseGiver, config);
23 });
24
25 afterEach(function () {
26 sinon.restore();
27 });
28
29 describe('constructor', function () {
30 it('instantiates', function () {
31 assert(worker);
32 });
33
34 it('requires a promiseGiver function', function () {
35 try {
36 worker = new Worker(stubLogger, undefined, config);
37 assert.fail('should require function argument');
38 } catch (e) {
39 assert(e instanceof TypeError);
40 }
41 });
42 }); // constructor
43
44 describe('start', function () {
45 it('starts without polling', function () {
46 config.worker.pollingEnabled = false;
47 worker = new Worker(stubLogger, promiseGiver, config);
48 worker.start();
49 assert.strictEqual(worker.running, false);
50 });
51 it('starts with polling', function () {
52 config.worker.pollingEnabled = true;
53 worker = new Worker(stubLogger, promiseGiver, config);
54 sinon.stub(worker, '_recurr');
55 worker.start();
56 clearTimeout(worker.nextTimeout);
57 assert.strictEqual(worker.running, true);
58 });
59 }); // start
60
61 describe('stop', function () {
62 it('stops', function () {
63 worker = new Worker(stubLogger, promiseGiver, config);
64 worker.start();
65 worker.stop();
66 assert.strictEqual(worker.running, false);
67 assert.strictEqual(worker.nextTimeout, undefined);
68 });
69 }); // stop
70
71 describe('watchedPromise', function () {
72 let promise;
73 it('watches a resolvable promise', async function () {
74 const res = 'yay';
75 promise = Promise.resolve(res);
76 const watched = Worker.watchedPromise(promise);
77 const result = await watched;
78 assert.strictEqual(result, res);
79 assert.strictEqual(watched.resolved, res);
80 assert(watched.isSettled);
81 });
82 it('watches a rejectable promise', async function () {
83 const rej = new Error('boo');
84 promise = Promise.reject(rej);
85 const watched = Worker.watchedPromise(promise);
86 try {
87 await watched;
88 assert.fail(noExpectedException);
89 } catch (e) {
90 assert.deepStrictEqual(e, rej);
91 assert.deepStrictEqual(watched.rejected, rej);
92 assert(watched.isSettled);
93 }
94 });
95 it('covers wrapped promise', async function () {
96 const res = 'yay';
97 promise = Promise.resolve(res);
98 const watched = Worker.watchedPromise(promise);
99 const rewatched = Worker.watchedPromise(watched);
100 const result = await rewatched;
101 assert.strictEqual(result, res);
102 assert.strictEqual(rewatched.resolved, res);
103 assert(rewatched.isSettled);
104 });
105 }); // watchedPromise
106
107 describe('_handleWatchedList', function () {
108 let handler;
109 beforeEach(function () {
110 handler = sinon.stub();
111 });
112 it('handled resolveds', function () {
113 worker.inFlight = [
114 { isSettled: false, resolved: undefined, rejected: undefined },
115 { isSettled: true, resolved: 'value', rejected: undefined },
116 { isSettled: true, resolved: undefined, rejected: 'error' },
117 { isSettled: false, resolved: undefined, rejected: undefined },
118 ];
119 const result = worker._handleWatchedList(handler);
120 assert.strictEqual(result, 2);
121 assert.strictEqual(worker.inFlight.length, 2);
122 assert.strictEqual(handler.callCount, 2);
123 });
124 }); // _handleWatchedList
125
126 describe('_getWork', function () {
127 it('gets tasks', async function () {
128 const expected = [
129 Promise.resolve('first'),
130 Promise.reject('bad'),
131 Promise.resolve('second'),
132 ];
133 worker.promiseGiver.resolves(expected);
134 const result = await worker._getWork();
135 assert.deepStrictEqual(result, expected);
136 assert.strictEqual(worker.inFlight.length, expected.length);
137 });
138 it('covers none wanted', async function () {
139 worker.concurrency = 3;
140 worker.inFlight = [
141 Promise.resolve('first'),
142 Promise.reject('bad'),
143 Promise.resolve('second'),
144 ];
145 const result = await worker._getWork();
146 assert(!worker.promiseGiver.called);
147 assert.deepStrictEqual(result, []);
148 });
149 }); // _getWork
150
151 describe('_watchedHandler', function () {
152 it('covers resolved', function () {
153 worker._watchedHandler('resolved', undefined);
154 });
155 it('covers rejected', function () {
156 worker._watchedHandler(undefined, 'rejected');
157 });
158 }); // _watchedHandler
159
160 describe('_recurr', function () {
161 it('covers', function (done) {
162 worker.recurrSleepMs = 10;
163 this.slow(worker.recurrSleepMs * 3);
164 sinon.stub(worker, 'process').callsFake(done);
165 worker.running = true;
166 worker._recurr();
167 });
168 it('covers not running', function () {
169 worker.running = false;
170 worker._recurr();
171 });
172 }); // _recurr
173
174 describe('process', function () {
175 beforeEach(function () {
176 sinon.stub(worker, '_getWork');
177 sinon.stub(worker, '_recurr');
178 });
179 it('covers', async function () {
180 worker.inFlight = [
181 Worker.watchedPromise(Promise.resolve('one')),
182 Worker.watchedPromise(Promise.reject('foo')),
183 ];
184 await worker.process();
185 assert.strictEqual(worker._getWork.callCount, 2);
186 assert.strictEqual(worker._recurr.callCount, 1);
187 });
188 it('covers no work', async function () {
189 await worker.process();
190 assert.strictEqual(worker._getWork.callCount, 1);
191 assert.strictEqual(worker._recurr.callCount, 1);
192 });
193 }); // process
194
195 }); // Worker