diff --git a/packages/compiler-cli/ngcc/src/execution/cluster/executor.ts b/packages/compiler-cli/ngcc/src/execution/cluster/executor.ts
index 333a8e4e72..b595b07781 100644
--- a/packages/compiler-cli/ngcc/src/execution/cluster/executor.ts
+++ b/packages/compiler-cli/ngcc/src/execution/cluster/executor.ts
@@ -5,11 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
-
-///
-
-import * as cluster from 'cluster';
-
+import {FileSystem} from '../../../../src/ngtsc/file_system';
import {AsyncLocker} from '../../locking/async_locker';
import {Logger} from '../../logging/logger';
import {PackageJsonUpdater} from '../../writing/package_json_updater';
@@ -17,8 +13,6 @@ import {AnalyzeEntryPointsFn, CreateCompileFn, Executor} from '../api';
import {CreateTaskCompletedCallback} from '../tasks/api';
import {ClusterMaster} from './master';
-import {ClusterWorker} from './worker';
-
/**
* An `Executor` that processes tasks in parallel (on multiple processes) and completes
@@ -26,26 +20,19 @@ import {ClusterWorker} from './worker';
*/
export class ClusterExecutor implements Executor {
constructor(
- private workerCount: number, private logger: Logger,
+ private workerCount: number, private fileSystem: FileSystem, private logger: Logger,
private pkgJsonUpdater: PackageJsonUpdater, private lockFile: AsyncLocker,
private createTaskCompletedCallback: CreateTaskCompletedCallback) {}
- async execute(analyzeEntryPoints: AnalyzeEntryPointsFn, createCompileFn: CreateCompileFn):
+ async execute(analyzeEntryPoints: AnalyzeEntryPointsFn, _createCompileFn: CreateCompileFn):
Promise {
- if (cluster.isMaster) {
- // This process is the cluster master.
- return this.lockFile.lock(() => {
- this.logger.debug(`Running ngcc on ${this.constructor.name} (using ${
- this.workerCount} worker processes).`);
- const master = new ClusterMaster(
- this.workerCount, this.logger, this.pkgJsonUpdater, analyzeEntryPoints,
- this.createTaskCompletedCallback);
- return master.run();
- });
- } else {
- // This process is a cluster worker.
- const worker = new ClusterWorker(this.logger, createCompileFn);
- return worker.run();
- }
+ return this.lockFile.lock(() => {
+ this.logger.debug(
+ `Running ngcc on ${this.constructor.name} (using ${this.workerCount} worker processes).`);
+ const master = new ClusterMaster(
+ this.workerCount, this.fileSystem, this.logger, this.pkgJsonUpdater, analyzeEntryPoints,
+ this.createTaskCompletedCallback);
+ return master.run();
+ });
}
}
diff --git a/packages/compiler-cli/ngcc/src/execution/cluster/master.ts b/packages/compiler-cli/ngcc/src/execution/cluster/master.ts
index e40e42009a..669960612e 100644
--- a/packages/compiler-cli/ngcc/src/execution/cluster/master.ts
+++ b/packages/compiler-cli/ngcc/src/execution/cluster/master.ts
@@ -10,7 +10,7 @@
import * as cluster from 'cluster';
-import {resolve} from '../../../../src/ngtsc/file_system';
+import {FileSystem} from '../../../../src/ngtsc/file_system';
import {Logger} from '../../logging/logger';
import {PackageJsonUpdater} from '../../writing/package_json_updater';
import {AnalyzeEntryPointsFn} from '../api';
@@ -33,13 +33,16 @@ export class ClusterMaster {
private onTaskCompleted: TaskCompletedCallback;
constructor(
- private maxWorkerCount: number, private logger: Logger,
+ private maxWorkerCount: number, private fileSystem: FileSystem, private logger: Logger,
private pkgJsonUpdater: PackageJsonUpdater, analyzeEntryPoints: AnalyzeEntryPointsFn,
createTaskCompletedCallback: CreateTaskCompletedCallback) {
if (!cluster.isMaster) {
throw new Error('Tried to instantiate `ClusterMaster` on a worker process.');
}
+ // Set the worker entry-point
+ cluster.setupMaster({exec: this.fileSystem.resolve(__dirname, 'worker.js')});
+
this.taskQueue = analyzeEntryPoints();
this.onTaskCompleted = createTaskCompletedCallback(this.taskQueue);
}
@@ -227,7 +230,7 @@ export class ClusterMaster {
JSON.stringify(msg));
}
- const expectedPackageJsonPath = resolve(task.entryPoint.path, 'package.json');
+ const expectedPackageJsonPath = this.fileSystem.resolve(task.entryPoint.path, 'package.json');
const parsedPackageJson = task.entryPoint.packageJson;
if (expectedPackageJsonPath !== msg.packageJsonPath) {
diff --git a/packages/compiler-cli/ngcc/src/execution/cluster/worker.ts b/packages/compiler-cli/ngcc/src/execution/cluster/worker.ts
index 24b6a3745c..e58a5326d1 100644
--- a/packages/compiler-cli/ngcc/src/execution/cluster/worker.ts
+++ b/packages/compiler-cli/ngcc/src/execution/cluster/worker.ts
@@ -5,58 +5,102 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
-
///
import * as cluster from 'cluster';
-import {Logger} from '../../logging/logger';
-import {CompileFn, CreateCompileFn} from '../api';
+import {absoluteFrom, CachedFileSystem, getFileSystem, NodeJSFileSystem, setFileSystem} from '../../../../src/ngtsc/file_system';
+import {readConfiguration} from '../../../../src/perform_compile';
+import {parseCommandLineOptions} from '../../command_line_options';
+import {ConsoleLogger} from '../../logging/console_logger';
+import {Logger, LogLevel} from '../../logging/logger';
+import {getPathMappingsFromTsConfig} from '../../utils';
+import {DirectPackageJsonUpdater} from '../../writing/package_json_updater';
+import {CreateCompileFn} from '../api';
+import {getCreateCompileFn} from '../create_compile_function';
import {stringifyTask} from '../tasks/utils';
import {MessageToWorker} from './api';
+import {ClusterPackageJsonUpdater} from './package_json_updater';
import {sendMessageToMaster} from './utils';
-
-/**
- * A cluster worker is responsible for processing one task (i.e. one format property for a specific
- * entry-point) at a time and reporting results back to the cluster master.
- */
-export class ClusterWorker {
- private compile: CompileFn;
-
- constructor(private logger: Logger, createCompileFn: CreateCompileFn) {
- if (cluster.isMaster) {
- throw new Error('Tried to instantiate `ClusterWorker` on the master process.');
- }
-
- this.compile = createCompileFn(
- (_task, outcome, message) =>
- sendMessageToMaster({type: 'task-completed', outcome, message}));
- }
-
- run(): Promise {
- // Listen for `ProcessTaskMessage`s and process tasks.
- cluster.worker.on('message', (msg: MessageToWorker) => {
- try {
- switch (msg.type) {
- case 'process-task':
- this.logger.debug(
- `[Worker #${cluster.worker.id}] Processing task: ${stringifyTask(msg.task)}`);
- return this.compile(msg.task);
- default:
- throw new Error(
- `[Worker #${cluster.worker.id}] Invalid message received: ${JSON.stringify(msg)}`);
- }
- } catch (err) {
- sendMessageToMaster({
- type: 'error',
- error: (err instanceof Error) ? (err.stack || err.message) : err,
- });
+// Cluster worker entry point
+if (require.main === module) {
+ process.title = 'ngcc (worker)';
+ setFileSystem(new CachedFileSystem(new NodeJSFileSystem()));
+ let {
+ basePath,
+ targetEntryPointPath,
+ createNewEntryPointFormats = false,
+ logger = new ConsoleLogger(LogLevel.info),
+ pathMappings,
+ errorOnFailedEntryPoint = false,
+ enableI18nLegacyMessageIdFormat = true,
+ tsConfigPath
+ } = parseCommandLineOptions(process.argv.slice(2));
+ (async () => {
+ try {
+ if (!!targetEntryPointPath) {
+ // targetEntryPointPath forces us to error if an entry-point fails.
+ errorOnFailedEntryPoint = true;
}
- });
- // Return a promise that is never resolved.
- return new Promise(() => undefined);
- }
+ const fileSystem = getFileSystem();
+ const absBasePath = absoluteFrom(basePath);
+ const projectPath = fileSystem.dirname(absBasePath);
+ const tsConfig =
+ tsConfigPath !== null ? readConfiguration(tsConfigPath || projectPath) : null;
+
+ if (pathMappings === undefined) {
+ pathMappings = getPathMappingsFromTsConfig(tsConfig, projectPath);
+ }
+
+ const pkgJsonUpdater =
+ new ClusterPackageJsonUpdater(new DirectPackageJsonUpdater(fileSystem));
+
+ // The function for creating the `compile()` function.
+ const createCompileFn = getCreateCompileFn(
+ fileSystem, logger, pkgJsonUpdater, createNewEntryPointFormats, errorOnFailedEntryPoint,
+ enableI18nLegacyMessageIdFormat, tsConfig, pathMappings);
+
+ await startWorker(logger, createCompileFn);
+ process.exitCode = 0;
+ } catch (e) {
+ console.error(e.stack || e.message);
+ process.exitCode = 1;
+ }
+ })();
}
+
+export async function startWorker(logger: Logger, createCompileFn: CreateCompileFn): Promise {
+ if (cluster.isMaster) {
+ throw new Error('Tried to run cluster worker on the master process.');
+ }
+
+ const compile = createCompileFn(
+ (_task, outcome, message) => sendMessageToMaster({type: 'task-completed', outcome, message}));
+
+
+ // Listen for `ProcessTaskMessage`s and process tasks.
+ cluster.worker.on('message', (msg: MessageToWorker) => {
+ try {
+ switch (msg.type) {
+ case 'process-task':
+ logger.debug(
+ `[Worker #${cluster.worker.id}] Processing task: ${stringifyTask(msg.task)}`);
+ return compile(msg.task);
+ default:
+ throw new Error(
+ `[Worker #${cluster.worker.id}] Invalid message received: ${JSON.stringify(msg)}`);
+ }
+ } catch (err) {
+ sendMessageToMaster({
+ type: 'error',
+ error: (err instanceof Error) ? (err.stack || err.message) : err,
+ });
+ }
+ });
+
+ // Return a promise that is never resolved.
+ return new Promise(() => undefined);
+}
\ No newline at end of file
diff --git a/packages/compiler-cli/ngcc/src/main.ts b/packages/compiler-cli/ngcc/src/main.ts
index bdcaa2a19e..33fff60680 100644
--- a/packages/compiler-cli/ngcc/src/main.ts
+++ b/packages/compiler-cli/ngcc/src/main.ts
@@ -178,7 +178,7 @@ function getExecutor(
// Execute in parallel. Use up to 8 CPU cores for workers, always reserving one for master.
const workerCount = Math.min(8, os.cpus().length - 1);
return new ClusterExecutor(
- workerCount, logger, pkgJsonUpdater, locker, createTaskCompletedCallback);
+ workerCount, fileSystem, logger, pkgJsonUpdater, locker, createTaskCompletedCallback);
} else {
// Execute serially, on a single thread (async).
return new SingleProcessExecutorAsync(logger, locker, createTaskCompletedCallback);
diff --git a/packages/compiler-cli/ngcc/test/BUILD.bazel b/packages/compiler-cli/ngcc/test/BUILD.bazel
index ccafbae4fd..320d64646a 100644
--- a/packages/compiler-cli/ngcc/test/BUILD.bazel
+++ b/packages/compiler-cli/ngcc/test/BUILD.bazel
@@ -29,6 +29,7 @@ ts_library(
"@npm//magic-string",
"@npm//sourcemap-codec",
"@npm//typescript",
+ "@npm//yargs",
],
)
diff --git a/packages/compiler-cli/ngcc/test/execution/cluster/executor_spec.ts b/packages/compiler-cli/ngcc/test/execution/cluster/executor_spec.ts
index c5f7f64fe7..1def235e51 100644
--- a/packages/compiler-cli/ngcc/test/execution/cluster/executor_spec.ts
+++ b/packages/compiler-cli/ngcc/test/execution/cluster/executor_spec.ts
@@ -8,47 +8,44 @@
///
+import {getFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system';
import * as cluster from 'cluster';
-import {MockFileSystemNative} from '../../../../src/ngtsc/file_system/testing';
+import {MockFileSystemNative, runInEachFileSystem} from '../../../../src/ngtsc/file_system/testing';
import {ClusterExecutor} from '../../../src/execution/cluster/executor';
import {ClusterMaster} from '../../../src/execution/cluster/master';
-import {ClusterWorker} from '../../../src/execution/cluster/worker';
import {AsyncLocker} from '../../../src/locking/async_locker';
import {PackageJsonUpdater} from '../../../src/writing/package_json_updater';
import {MockLockFile} from '../../helpers/mock_lock_file';
import {MockLogger} from '../../helpers/mock_logger';
import {mockProperty} from '../../helpers/spy_utils';
+runInEachFileSystem(() => {
+ describe('ClusterExecutor', () => {
+ const runAsClusterMaster = mockProperty(cluster, 'isMaster');
+ let masterRunSpy: jasmine.Spy;
+ let mockLogger: MockLogger;
+ let lockFileLog: string[];
+ let mockLockFile: MockLockFile;
+ let locker: AsyncLocker;
+ let executor: ClusterExecutor;
+ let createTaskCompletedCallback: jasmine.Spy;
-describe('ClusterExecutor', () => {
- const runAsClusterMaster = mockProperty(cluster, 'isMaster');
- let masterRunSpy: jasmine.Spy;
- let workerRunSpy: jasmine.Spy;
- let mockLogger: MockLogger;
- let lockFileLog: string[];
- let mockLockFile: MockLockFile;
- let locker: AsyncLocker;
- let executor: ClusterExecutor;
- let createTaskCompletedCallback: jasmine.Spy;
+ beforeEach(() => {
+ masterRunSpy = spyOn(ClusterMaster.prototype, 'run')
+ .and.returnValue(Promise.resolve('CusterMaster#run()' as any));
+ createTaskCompletedCallback = jasmine.createSpy('createTaskCompletedCallback');
- beforeEach(() => {
- masterRunSpy = spyOn(ClusterMaster.prototype, 'run')
- .and.returnValue(Promise.resolve('CusterMaster#run()' as any));
- workerRunSpy = spyOn(ClusterWorker.prototype, 'run')
- .and.returnValue(Promise.resolve('CusterWorker#run()' as any));
- createTaskCompletedCallback = jasmine.createSpy('createTaskCompletedCallback');
+ mockLogger = new MockLogger();
+ lockFileLog = [];
+ mockLockFile = new MockLockFile(new MockFileSystemNative(), lockFileLog);
+ locker = new AsyncLocker(mockLockFile, mockLogger, 200, 2);
+ executor = new ClusterExecutor(
+ 42, getFileSystem(), mockLogger, null as unknown as PackageJsonUpdater, locker,
+ createTaskCompletedCallback);
+ });
- mockLogger = new MockLogger();
- lockFileLog = [];
- mockLockFile = new MockLockFile(new MockFileSystemNative(), lockFileLog);
- locker = new AsyncLocker(mockLockFile, mockLogger, 200, 2);
- executor = new ClusterExecutor(
- 42, mockLogger, null as unknown as PackageJsonUpdater, locker, createTaskCompletedCallback);
- });
-
- describe('execute()', () => {
- describe('(on cluster master)', () => {
+ describe('execute()', () => {
beforeEach(() => runAsClusterMaster(true));
it('should log debug info about the executor', async () => {
@@ -68,7 +65,6 @@ describe('ClusterExecutor', () => {
.toBe('CusterMaster#run()' as any);
expect(masterRunSpy).toHaveBeenCalledWith();
- expect(workerRunSpy).not.toHaveBeenCalled();
expect(analyzeEntryPointsSpy).toHaveBeenCalledWith();
expect(createCompilerFnSpy).not.toHaveBeenCalled();
@@ -102,7 +98,7 @@ describe('ClusterExecutor', () => {
});
executor = new ClusterExecutor(
- 42, mockLogger, null as unknown as PackageJsonUpdater, locker,
+ 42, getFileSystem(), mockLogger, null as unknown as PackageJsonUpdater, locker,
createTaskCompletedCallback);
let error = '';
try {
@@ -122,7 +118,7 @@ describe('ClusterExecutor', () => {
});
executor = new ClusterExecutor(
- 42, mockLogger, null as unknown as PackageJsonUpdater, locker,
+ 42, getFileSystem(), mockLogger, null as unknown as PackageJsonUpdater, locker,
createTaskCompletedCallback);
let error = '';
try {
@@ -135,36 +131,5 @@ describe('ClusterExecutor', () => {
expect(masterRunSpy).toHaveBeenCalled();
});
});
-
- describe('(on cluster worker)', () => {
- beforeEach(() => runAsClusterMaster(false));
-
- it('should not log debug info about the executor', async () => {
- const anyFn: () => any = () => undefined;
- await executor.execute(anyFn, anyFn);
-
- expect(mockLogger.logs.debug).toEqual([]);
- });
-
- it('should delegate to `ClusterWorker#run()`', async () => {
- const analyzeEntryPointsSpy = jasmine.createSpy('analyzeEntryPoints');
- const createCompilerFnSpy = jasmine.createSpy('createCompilerFn');
-
- expect(await executor.execute(analyzeEntryPointsSpy, createCompilerFnSpy))
- .toBe('CusterWorker#run()' as any);
-
- expect(masterRunSpy).not.toHaveBeenCalledWith();
- expect(workerRunSpy).toHaveBeenCalled();
-
- expect(analyzeEntryPointsSpy).not.toHaveBeenCalled();
- expect(createCompilerFnSpy).toHaveBeenCalledWith(jasmine.any(Function));
- });
-
- it('should not call LockFile.write() or LockFile.remove()', async () => {
- const anyFn: () => any = () => undefined;
- await executor.execute(anyFn, anyFn);
- expect(lockFileLog).toEqual([]);
- });
- });
});
});
diff --git a/packages/compiler-cli/ngcc/test/execution/cluster/worker_spec.ts b/packages/compiler-cli/ngcc/test/execution/cluster/worker_spec.ts
index b9d92e47d9..8cc9370b3c 100644
--- a/packages/compiler-cli/ngcc/test/execution/cluster/worker_spec.ts
+++ b/packages/compiler-cli/ngcc/test/execution/cluster/worker_spec.ts
@@ -11,13 +11,13 @@
import * as cluster from 'cluster';
import {EventEmitter} from 'events';
-import {ClusterWorker} from '../../../src/execution/cluster/worker';
+import {startWorker} from '../../../src/execution/cluster/worker';
import {Task, TaskCompletedCallback, TaskProcessingOutcome} from '../../../src/execution/tasks/api';
import {MockLogger} from '../../helpers/mock_logger';
import {mockProperty} from '../../helpers/spy_utils';
-describe('ClusterWorker', () => {
+describe('startWorker()', () => {
const runAsClusterMaster = mockProperty(cluster, 'isMaster');
const mockProcessSend = mockProperty(process, 'send');
let processSendSpy: jasmine.Spy;
@@ -35,131 +35,116 @@ describe('ClusterWorker', () => {
mockLogger = new MockLogger();
});
- describe('constructor()', () => {
- describe('(on cluster master)', () => {
- beforeEach(() => runAsClusterMaster(true));
+ describe('(on cluster master)', () => {
+ beforeEach(() => runAsClusterMaster(true));
- it('should throw an error', () => {
- expect(() => new ClusterWorker(mockLogger, createCompileFnSpy))
- .toThrowError('Tried to instantiate `ClusterWorker` on the master process.');
- expect(createCompileFnSpy).not.toHaveBeenCalled();
- });
- });
-
- describe('(on cluster worker)', () => {
- beforeEach(() => runAsClusterMaster(false));
-
- it('should create the `compileFn()`', () => {
- new ClusterWorker(mockLogger, createCompileFnSpy);
- expect(createCompileFnSpy).toHaveBeenCalledWith(jasmine.any(Function));
- });
-
- it('should set up `compileFn()` to send `task-completed` messages to master', () => {
- new ClusterWorker(mockLogger, createCompileFnSpy);
- const onTaskCompleted: TaskCompletedCallback = createCompileFnSpy.calls.argsFor(0)[0];
-
- onTaskCompleted(null as any, TaskProcessingOutcome.Processed, null);
- expect(processSendSpy).toHaveBeenCalledTimes(1);
- expect(processSendSpy)
- .toHaveBeenCalledWith(
- {type: 'task-completed', outcome: TaskProcessingOutcome.Processed, message: null});
-
- processSendSpy.calls.reset();
-
- onTaskCompleted(null as any, TaskProcessingOutcome.Failed, 'error message');
- expect(processSendSpy).toHaveBeenCalledTimes(1);
- expect(processSendSpy).toHaveBeenCalledWith({
- type: 'task-completed',
- outcome: TaskProcessingOutcome.Failed,
- message: 'error message',
- });
- });
+ it('should throw an error', async () => {
+ await expectAsync(startWorker(mockLogger, createCompileFnSpy))
+ .toBeRejectedWithError('Tried to run cluster worker on the master process.');
+ expect(createCompileFnSpy).not.toHaveBeenCalled();
});
});
- describe('run()', () => {
- describe(
- '(on cluster master)',
- () => {/* No tests needed, becasue the constructor would have thrown. */});
+ describe('(on cluster worker)', () => {
+ // The `cluster.worker` property is normally `undefined` on the master process and set to the
+ // current `cluster.worker` on worker processes.
+ const mockClusterWorker = mockProperty(cluster, 'worker');
- describe('(on cluster worker)', () => {
- // The `cluster.worker` property is normally `undefined` on the master process and set to the
- // current `cluster.Worker` on worker processes.
- const mockClusterWorker = mockProperty(cluster, 'worker');
- let worker: ClusterWorker;
+ beforeEach(() => {
+ runAsClusterMaster(false);
+ mockClusterWorker(Object.assign(new EventEmitter(), {id: 42}) as cluster.Worker);
+ });
- beforeEach(() => {
- runAsClusterMaster(false);
- mockClusterWorker(Object.assign(new EventEmitter(), {id: 42}) as cluster.Worker);
+ it('should create the `compileFn()`', () => {
+ startWorker(mockLogger, createCompileFnSpy);
+ expect(createCompileFnSpy).toHaveBeenCalledWith(jasmine.any(Function));
+ });
- worker = new ClusterWorker(mockLogger, createCompileFnSpy);
+ it('should set up `compileFn()` to send `task-completed` messages to master', () => {
+ startWorker(mockLogger, createCompileFnSpy);
+ const onTaskCompleted: TaskCompletedCallback = createCompileFnSpy.calls.argsFor(0)[0];
+
+ onTaskCompleted(null as any, TaskProcessingOutcome.Processed, null);
+ expect(processSendSpy).toHaveBeenCalledTimes(1);
+ expect(processSendSpy)
+ .toHaveBeenCalledWith(
+ {type: 'task-completed', outcome: TaskProcessingOutcome.Processed, message: null});
+
+ processSendSpy.calls.reset();
+
+ onTaskCompleted(null as any, TaskProcessingOutcome.Failed, 'error message');
+ expect(processSendSpy).toHaveBeenCalledTimes(1);
+ expect(processSendSpy).toHaveBeenCalledWith({
+ type: 'task-completed',
+ outcome: TaskProcessingOutcome.Failed,
+ message: 'error message',
+ });
+ });
+
+ it('should return a promise (that is never resolved)', done => {
+ const promise = startWorker(mockLogger, createCompileFnSpy);
+
+ expect(promise).toEqual(jasmine.any(Promise));
+
+ promise.then(
+ () => done.fail('Expected promise not to resolve'),
+ () => done.fail('Expected promise not to reject'));
+
+ // We can't wait forever to verify that the promise is not resolved, but at least verify
+ // that it is not resolved immediately.
+ setTimeout(done, 100);
+ });
+
+ it('should handle `process-task` messages', () => {
+ const mockTask = {
+ entryPoint: {name: 'foo'},
+ formatProperty: 'es2015',
+ processDts: true,
+ } as unknown as Task;
+
+ startWorker(mockLogger, createCompileFnSpy);
+ cluster.worker.emit('message', {type: 'process-task', task: mockTask});
+
+ expect(compileFnSpy).toHaveBeenCalledWith(mockTask);
+ expect(processSendSpy).not.toHaveBeenCalled();
+
+ expect(mockLogger.logs.debug[0]).toEqual([
+ '[Worker #42] Processing task: {entryPoint: foo, formatProperty: es2015, processDts: true}',
+ ]);
+ });
+
+ it('should send errors during task processing back to the master process', () => {
+ const mockTask = {
+ entryPoint: {name: 'foo'},
+ formatProperty: 'es2015',
+ processDts: true,
+ } as unknown as Task;
+
+ let err: string|Error;
+ compileFnSpy.and.callFake(() => {
+ throw err;
});
- it('should return a promise (that is never resolved)', done => {
- const promise = worker.run();
+ startWorker(mockLogger, createCompileFnSpy);
- expect(promise).toEqual(jasmine.any(Promise));
+ err = 'Error string.';
+ cluster.worker.emit('message', {type: 'process-task', task: mockTask});
+ expect(processSendSpy).toHaveBeenCalledWith({type: 'error', error: err});
- promise.then(
- () => done.fail('Expected promise not to resolve'),
- () => done.fail('Expected promise not to reject'));
+ err = new Error('Error object.');
+ cluster.worker.emit('message', {type: 'process-task', task: mockTask});
+ expect(processSendSpy).toHaveBeenCalledWith({type: 'error', error: err.stack});
+ });
- // We can't wait forever to verify that the promise is not resolved, but at least verify
- // that it is not resolved immediately.
- setTimeout(done, 100);
- });
+ it('should throw, when an unknown message type is received', () => {
+ startWorker(mockLogger, createCompileFnSpy);
+ cluster.worker.emit('message', {type: 'unknown', foo: 'bar'});
- it('should handle `process-task` messages', () => {
- const mockTask = {
- entryPoint: {name: 'foo'},
- formatProperty: 'es2015',
- processDts: true,
- } as unknown as Task;
-
- worker.run();
- cluster.worker.emit('message', {type: 'process-task', task: mockTask});
-
- expect(compileFnSpy).toHaveBeenCalledWith(mockTask);
- expect(processSendSpy).not.toHaveBeenCalled();
-
- expect(mockLogger.logs.debug[0]).toEqual([
- '[Worker #42] Processing task: {entryPoint: foo, formatProperty: es2015, processDts: true}',
- ]);
- });
-
- it('should send errors during task processing back to the master process', () => {
- const mockTask = {
- entryPoint: {name: 'foo'},
- formatProperty: 'es2015',
- processDts: true,
- } as unknown as Task;
-
- let err: string|Error;
- compileFnSpy.and.callFake(() => {
- throw err;
- });
-
- worker.run();
-
- err = 'Error string.';
- cluster.worker.emit('message', {type: 'process-task', task: mockTask});
- expect(processSendSpy).toHaveBeenCalledWith({type: 'error', error: err});
-
- err = new Error('Error object.');
- cluster.worker.emit('message', {type: 'process-task', task: mockTask});
- expect(processSendSpy).toHaveBeenCalledWith({type: 'error', error: err.stack});
- });
-
- it('should throw, when an unknown message type is received', () => {
- worker.run();
- cluster.worker.emit('message', {type: 'unknown', foo: 'bar'});
-
- expect(compileFnSpy).not.toHaveBeenCalled();
- expect(processSendSpy).toHaveBeenCalledWith({
- type: 'error',
- error: jasmine.stringMatching(
- 'Error: \\[Worker #42\\] Invalid message received: {"type":"unknown","foo":"bar"}'),
- });
+ expect(compileFnSpy).not.toHaveBeenCalled();
+ expect(processSendSpy).toHaveBeenCalledWith({
+ type: 'error',
+ error: jasmine.stringMatching(
+ 'Error: \\[Worker #42\\] Invalid message received: {"type":"unknown","foo":"bar"}'),
});
});
});