parallel-es
Version:
Simple parallelization for EcmaScript
285 lines (227 loc) • 10.6 kB
text/typescript
import {IParallelGenerator} from "../../../../src/common/parallel/generator/parallel-generator";
import {FunctionCall} from "../../../../src/common/function/function-call";
import {IDefaultInitializedParallelOptions} from "../../../../src/common/parallel";
import {ParallelCollectionGenerator} from "../../../../src/common/parallel/generator/parallel-collection-generator";
import {IParallelChainState} from "../../../../src/common/parallel/chain/parallel-chain-state";
import {ParallelChainImpl} from "../../../../src/common/parallel/chain/parallel-chain-impl";
import {IParallelChain} from "../../../../src/common/parallel/chain/parallel-chain";
import {ParallelStream} from "../../../../src/common/parallel/stream/parallel-stream-impl";
import {ParallelWorkerFunctionIds} from "../../../../src/common/parallel/slave/parallel-worker-functions";
describe("ParallelChainImpl", function () {
let generator: IParallelGenerator;
let options: IDefaultInitializedParallelOptions;
let state: IParallelChainState<number>;
let stateResolveSpy: jasmine.Spy;
let chainOperationSpy: jasmine.Spy;
let addEnvironmentSpy: jasmine.Spy;
beforeEach(function () {
generator = new ParallelCollectionGenerator([1, 2, 3, 4, 5]);
stateResolveSpy = jasmine.createSpy("state.resolve");
chainOperationSpy = jasmine.createSpy("state.chainOperation");
addEnvironmentSpy = jasmine.createSpy("state.addEnvironment");
state = {
addEnvironment: addEnvironmentSpy,
chainOperation: chainOperationSpy,
resolve: stateResolveSpy
} as any;
options = {
functionCallSerializer: undefined as any,
scheduler: undefined as any,
threadPool: undefined as any
};
});
describe("inEnvironment", function () {
it("adds the given object hash to the existing environment", function () {
// arrange
const chain = new ParallelChainImpl(state);
// act
chain.inEnvironment({ test: 10 });
// assert
expect(addEnvironmentSpy).toHaveBeenCalledWith({ test: 10 });
});
it("adds the given environment provider to the existing environment", function () {
// arrange
const chain = new ParallelChainImpl(state);
const environmentProvider = (value: number) => ({ value });
// act
chain.inEnvironment(environmentProvider, 10);
// assert
expect(addEnvironmentSpy).toHaveBeenCalledWith(FunctionCall.create(environmentProvider, 10));
});
});
describe("map", function () {
it("adds the map operation to the operations to perform", function () {
// arrange
const mapper = (value: number) => value * 2;
const chain = new ParallelChainImpl(state);
// act
chain.map(mapper);
// assert
expect(chainOperationSpy).toHaveBeenCalledWith({
iteratee: FunctionCall.createUnchecked(mapper),
iterator: FunctionCall.create(ParallelWorkerFunctionIds.MAP)
});
});
it("changes the state of the chain to the state returned by chainOperation", function () {
// arrange
const newState = {};
const chain = new ParallelChainImpl(state);
chainOperationSpy.and.returnValue(newState);
// act, assert
const mappedChain = chain.map(value => value * 2);
// assert
expect(getChainState(mappedChain)).toEqual(newState);
});
});
describe("filter", function () {
it("adds the filter operation to the operations to perform", function () {
// arrange
const filter = (value: number) => value % 2 === 0;
const chain = new ParallelChainImpl(state);
// act
chain.filter(filter);
// assert
expect(chainOperationSpy).toHaveBeenCalledWith({
iteratee: FunctionCall.createUnchecked(filter),
iterator: FunctionCall.create(ParallelWorkerFunctionIds.FILTER)
});
});
it("changes the state of the chain to the state returned by chainOperation", function () {
// arrange
const newState = {};
const chain = new ParallelChainImpl(state);
chainOperationSpy.and.returnValue(newState);
// act, assert
const filteredChain = chain.filter(value => value % 2 === 0);
// assert
expect(getChainState(filteredChain)).toEqual(newState);
});
});
describe("reduce", function () {
it("adds the reduce operation to the operations to perform", function () {
// arrange
const add = (memo: number, value: number) => memo + value;
const chain = new ParallelChainImpl(state);
const reducedStream = jasmine.createSpyObj("reducedStream", [ "then" ]);
const resolvedState = { stream: reducedStream };
const reducedState = { resolve: jasmine.createSpy("resolve").and.returnValue(resolvedState) };
chainOperationSpy.and.returnValue(reducedState);
spyOn(ParallelStream, "transform");
// act
chain.reduce(0, add);
// assert
expect(chainOperationSpy).toHaveBeenCalledWith({
iteratee: FunctionCall.createUnchecked(add),
iterator: FunctionCall.create(ParallelWorkerFunctionIds.REDUCE, 0)
});
});
it("returns the default value if the tasks returned an empty array", function (done) {
// arrange
const add = (memo: number, value: number) => memo + value;
const chain = new ParallelChainImpl(state);
const reducedStream = jasmine.createSpyObj("reducedStream", [ "subscribe" ]);
const resolvedState = { stream: reducedStream };
const reducedState = { resolve: jasmine.createSpy("resolve").and.returnValue(resolvedState) };
chainOperationSpy.and.returnValue(reducedState);
// act, assert
chain.reduce(55, add).then(result => {
expect(result).toEqual(55);
done();
}, done.fail);
// call then callback
reducedStream.subscribe.calls.argsFor(0)[2].apply(undefined, [[]]);
});
it("returns the summed up value if the task returns values", function (done) {
// arrange
const add = (memo: number, value: number) => memo + value;
const chain = new ParallelChainImpl(state);
const reducedStream = jasmine.createSpyObj("reducedStream", [ "subscribe" ]);
const resolvedState = { stream: reducedStream };
const reducedState = { resolve: jasmine.createSpy("resolve").and.returnValue(resolvedState) };
chainOperationSpy.and.returnValue(reducedState);
// act, assert
chain.reduce(55, add).then(result => {
expect(result).toEqual(10 + 15);
done();
}, done.fail);
// call then callback
reducedStream.subscribe.calls.argsFor(0)[2].apply(undefined, [[10, 15]]);
});
});
describe("then", function () {
it("resolves the state", function () {
// arrange
const chain = new ParallelChainImpl(state);
const stream = jasmine.createSpyObj("stream", ["then"]);
stateResolveSpy.and.returnValue({ stream });
// act
chain.then(() => undefined);
// assert
expect(stateResolveSpy).toHaveBeenCalled();
});
it("registers the callbacks", function () {
// arrange
const chain = new ParallelChainImpl(state);
const stream = jasmine.createSpyObj("stream", ["then"]);
stateResolveSpy.and.returnValue({ stream });
const success = () => undefined;
const reject = () => undefined;
// act
chain.then(success, reject);
// assert
expect(stream.then).toHaveBeenCalledWith(success, reject);
});
});
describe("catch", function () {
it("resolves the state", function () {
// arrange
const chain = new ParallelChainImpl(state);
const stream = jasmine.createSpyObj("stream", ["catch"]);
stateResolveSpy.and.returnValue({ stream });
// act
chain.catch(() => undefined);
// assert
expect(stateResolveSpy).toHaveBeenCalled();
});
it("registers the callback", function () {
// arrange
const chain = new ParallelChainImpl(state);
const stream = jasmine.createSpyObj("stream", ["catch"]);
stateResolveSpy.and.returnValue({ stream });
const reject = () => undefined;
// act
chain.catch(reject);
// assert
expect(stream.catch).toHaveBeenCalledWith(reject);
});
});
describe("subscribe", function () {
it("resolves the state", function () {
// arrange
const chain = new ParallelChainImpl(state);
const stream = jasmine.createSpyObj("stream", ["subscribe"]);
stateResolveSpy.and.returnValue({ stream });
// act
chain.subscribe(() => undefined);
// assert
expect(stateResolveSpy).toHaveBeenCalled();
});
it("registers the next, error and complete callbacks", function () {
// arrange
const chain = new ParallelChainImpl(state);
const stream = jasmine.createSpyObj("stream", ["subscribe"]);
stateResolveSpy.and.returnValue({ stream });
const next = () => undefined;
const error = () => undefined;
const complete = () => undefined;
// act
chain.subscribe(next, error, complete);
// assert
expect(stream.subscribe).toHaveBeenCalledWith(next, error, complete);
});
});
});
function getChainState<TIn, TEnv, TOut>(chain: IParallelChain<TIn, TEnv, TOut>): IParallelChainState<TOut> {
expect(chain).toEqual(jasmine.any(ParallelChainImpl));
return (chain as ParallelChainImpl<TIn, TEnv, TOut>).state;
}