UNPKG

parallel.es

Version:
151 lines (118 loc) 6.18 kB
import {DefaultThreadPool} from "../../../src/common/thread-pool/default-thread-pool"; import {WorkerTask} from "../../../src/common/task/worker-task"; import {FunctionCall} from "../../../src/common/function/function-call"; describe("DefaultThreadPool", function () { let spawn: jasmine.Spy; let serializeCallSpy: jasmine.Spy; let threadPool: DefaultThreadPool; beforeEach(function () { spawn = jasmine.createSpy("spawn"); const workerThreadFactory = { spawn }; serializeCallSpy = jasmine.createSpy("serializeCall"); threadPool = new DefaultThreadPool(workerThreadFactory, { serializeFunctionCall: serializeCallSpy } as any, { maxConcurrencyLevel: 2 }); }); describe("schedule", function () { it("registers the function in the function lookup table", function () { // arrange const func = function () { /* ignore */ }; serializeCallSpy.and.returnValue({ functionId: "test-1" }); // act threadPool.schedule(func); // assert expect(serializeCallSpy).toHaveBeenCalledWith(FunctionCall.create(func)); }); it("spawns a new worker until the concurrency limit is reached", function () { // arrange const func = function () { /* ignore */ }; serializeCallSpy.and.returnValue({ functionId: "test-1" }); // act threadPool.schedule(func); threadPool.schedule(func); threadPool.schedule(func); // assert expect(spawn).toHaveBeenCalledTimes(2); }); it("executes the task in a worker thread", function () { // arrange const func = function (value: number) { return value; }; const runOnSpy = spyOn(WorkerTask.prototype, "runOn"); serializeCallSpy.and.returnValue({ functionId: "test-1" }); const worker = { run: jasmine.createSpy("run") }; spawn.and.returnValue(worker); // act threadPool.schedule(func, 10); // assert expect(runOnSpy).toHaveBeenCalledWith(worker); }); it("enqueues the task if no worker thread is available", function () { // arrange const func = function () { /* ignore */ }; serializeCallSpy.and.returnValue({ functionId: "test-1" }); const worker1 = { run: jasmine.createSpy("run1"), stop: jasmine.createSpy("stop") }; const worker2 = { run: jasmine.createSpy("run2"), stop: jasmine.createSpy("stop") }; spawn.and.returnValues(worker1, worker2); // schedule worker until no worker is available... threadPool.schedule(func); threadPool.schedule(func); // act, should be queued. threadPool.schedule(func); // assert expect(worker1.run).toHaveBeenCalled(); expect(worker2.run).toHaveBeenCalled(); }); it("schedules queued tasks when a worker gets available", function () { // arrange const func = function () { /* ignore */ }; const func2 = function add(x: number, y: number): number { return x + y; }; serializeCallSpy.and.returnValues({ functionId: "test-1" }, { functionId: "test-1" }, { functionId: "test-2" }); const worker1 = { run: jasmine.createSpy("run1"), stop: jasmine.createSpy("stop") }; const worker2 = { run: jasmine.createSpy("run2"), stop: jasmine.createSpy("stop") }; const runOnSpy = spyOn(WorkerTask.prototype, "runOn"); const alwaysSpy = spyOn(WorkerTask.prototype, "always"); spyOn(WorkerTask.prototype, "releaseWorker").and.returnValue(worker1); spawn.and.returnValues(worker1, worker2); // schedule worker until no worker is available... threadPool.schedule(func); threadPool.schedule(func); threadPool.schedule(func2); // queue third function // act // complete task of first worker so that the third task is scheduled on worker 1 alwaysSpy.calls.argsFor(0)[0].call(undefined, 10); // assert expect(runOnSpy.calls.count()).toEqual(3); expect(runOnSpy.calls.argsFor(0)).toEqual([worker1]); expect(runOnSpy.calls.argsFor(1)).toEqual([worker2]); expect(runOnSpy.calls.argsFor(2)).toEqual([worker1]); }); it("reuses an idle worker if available", function () { // arrange const worker1 = { run: jasmine.createSpy("run1"), stop: jasmine.createSpy("stop") }; const worker2 = { run: jasmine.createSpy("run2"), stop: jasmine.createSpy("stop") }; serializeCallSpy.and.returnValue({ functionId: "test-1" }); spawn.and.returnValues(worker1, worker2); const runOnSpy = spyOn(WorkerTask.prototype, "runOn"); const alwaysSpy = spyOn(WorkerTask.prototype, "always"); spyOn(WorkerTask.prototype, "releaseWorker").and.returnValues(worker1, worker2); // spawn all workers by scheduling tasks up to concurrency limit const func = function () { /* ignore */ }; threadPool.schedule(func); threadPool.schedule(func); // complete first task, third task can now be scheduled on worker1 as this worker is idle alwaysSpy.calls.argsFor(0)[0].call(undefined, 10); // act threadPool.schedule(func); expect(runOnSpy).toHaveBeenCalledTimes(3); expect(runOnSpy.calls.argsFor(0)).toEqual([ worker1 ]); expect(runOnSpy.calls.argsFor(1)).toEqual([ worker2]); expect(runOnSpy.calls.argsFor(0)).toEqual([ worker1 ]); }); }); describe("createFunctionSerializer", function () { it("returns the instance", function () { // arrange const serializer = threadPool.getFunctionSerializer(); // assert expect(serializer).not.toBeUndefined(); }); }); });