| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							|  |  |  |  * Copyright Google Inc. All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 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
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /// <reference types="node" />
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import * as cluster from 'cluster'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-04 12:35:52 +00:00
										 |  |  | import {MockFileSystemNative} from '../../../../src/ngtsc/file_system/testing'; | 
					
						
							| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  | import {ClusterExecutor} from '../../../src/execution/cluster/executor'; | 
					
						
							|  |  |  | import {ClusterMaster} from '../../../src/execution/cluster/master'; | 
					
						
							|  |  |  | import {ClusterWorker} from '../../../src/execution/cluster/worker'; | 
					
						
							| 
									
										
										
										
											2020-03-04 12:49:36 +00:00
										 |  |  | import {AsyncLocker} from '../../../src/locking/async_locker'; | 
					
						
							| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  | import {PackageJsonUpdater} from '../../../src/writing/package_json_updater'; | 
					
						
							| 
									
										
										
										
											2020-03-04 12:35:52 +00:00
										 |  |  | import {MockLockFile} from '../../helpers/mock_lock_file'; | 
					
						
							| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  | import {MockLogger} from '../../helpers/mock_logger'; | 
					
						
							|  |  |  | import {mockProperty} from '../../helpers/spy_utils'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | describe('ClusterExecutor', () => { | 
					
						
							|  |  |  |   const runAsClusterMaster = mockProperty(cluster, 'isMaster'); | 
					
						
							|  |  |  |   let masterRunSpy: jasmine.Spy; | 
					
						
							|  |  |  |   let workerRunSpy: jasmine.Spy; | 
					
						
							|  |  |  |   let mockLogger: MockLogger; | 
					
						
							| 
									
										
										
										
											2020-03-04 12:35:52 +00:00
										 |  |  |   let lockFileLog: string[]; | 
					
						
							|  |  |  |   let mockLockFile: MockLockFile; | 
					
						
							|  |  |  |   let locker: AsyncLocker; | 
					
						
							| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  |   let executor: ClusterExecutor; | 
					
						
							| 
									
										
										
										
											2020-03-14 13:38:27 +00:00
										 |  |  |   let createTaskCompletedCallback: jasmine.Spy; | 
					
						
							| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |   beforeEach(() => { | 
					
						
							| 
									
										
										
										
											2020-01-10 09:54:58 +00:00
										 |  |  |     masterRunSpy = spyOn(ClusterMaster.prototype, 'run') | 
					
						
							|  |  |  |                        .and.returnValue(Promise.resolve('CusterMaster#run()')); | 
					
						
							|  |  |  |     workerRunSpy = spyOn(ClusterWorker.prototype, 'run') | 
					
						
							|  |  |  |                        .and.returnValue(Promise.resolve('CusterWorker#run()')); | 
					
						
							| 
									
										
										
										
											2020-03-14 13:38:27 +00:00
										 |  |  |     createTaskCompletedCallback = jasmine.createSpy('createTaskCompletedCallback'); | 
					
						
							| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     mockLogger = new MockLogger(); | 
					
						
							| 
									
										
										
										
											2020-03-04 12:35:52 +00:00
										 |  |  |     lockFileLog = []; | 
					
						
							|  |  |  |     mockLockFile = new MockLockFile(new MockFileSystemNative(), lockFileLog); | 
					
						
							|  |  |  |     locker = new AsyncLocker(mockLockFile, mockLogger, 200, 2); | 
					
						
							| 
									
										
										
										
											2020-03-14 13:38:27 +00:00
										 |  |  |     executor = new ClusterExecutor( | 
					
						
							|  |  |  |         42, mockLogger, null as unknown as PackageJsonUpdater, locker, createTaskCompletedCallback); | 
					
						
							| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('execute()', () => { | 
					
						
							|  |  |  |     describe('(on cluster master)', () => { | 
					
						
							|  |  |  |       beforeEach(() => runAsClusterMaster(true)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-03 20:25:15 +00:00
										 |  |  |       it('should log debug info about the executor', async() => { | 
					
						
							| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  |         const anyFn: () => any = () => undefined; | 
					
						
							| 
									
										
										
										
											2020-02-03 20:25:15 +00:00
										 |  |  |         await executor.execute(anyFn, anyFn); | 
					
						
							| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |         expect(mockLogger.logs.debug).toEqual([ | 
					
						
							|  |  |  |           ['Running ngcc on ClusterExecutor (using 42 worker processes).'], | 
					
						
							|  |  |  |         ]); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should delegate to `ClusterMaster#run()`', async() => { | 
					
						
							|  |  |  |         const analyzeEntryPointsSpy = jasmine.createSpy('analyzeEntryPoints'); | 
					
						
							|  |  |  |         const createCompilerFnSpy = jasmine.createSpy('createCompilerFn'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(await executor.execute(analyzeEntryPointsSpy, createCompilerFnSpy)) | 
					
						
							|  |  |  |             .toBe('CusterMaster#run()' as any); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(masterRunSpy).toHaveBeenCalledWith(); | 
					
						
							|  |  |  |         expect(workerRunSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(analyzeEntryPointsSpy).toHaveBeenCalledWith(); | 
					
						
							|  |  |  |         expect(createCompilerFnSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2020-01-10 09:54:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-04 12:35:52 +00:00
										 |  |  |       it('should call LockFile.write() and LockFile.remove() if master runner completes successfully', | 
					
						
							| 
									
										
										
										
											2020-01-10 09:54:58 +00:00
										 |  |  |          async() => { | 
					
						
							|  |  |  |            const anyFn: () => any = () => undefined; | 
					
						
							|  |  |  |            await executor.execute(anyFn, anyFn); | 
					
						
							| 
									
										
										
										
											2020-03-04 12:35:52 +00:00
										 |  |  |            expect(lockFileLog).toEqual(['write()', 'remove()']); | 
					
						
							| 
									
										
										
										
											2020-01-10 09:54:58 +00:00
										 |  |  |          }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-04 12:35:52 +00:00
										 |  |  |       it('should call LockFile.write() and LockFile.remove() if master runner fails', async() => { | 
					
						
							| 
									
										
										
										
											2020-01-10 09:54:58 +00:00
										 |  |  |         const anyFn: () => any = () => undefined; | 
					
						
							|  |  |  |         masterRunSpy.and.returnValue(Promise.reject(new Error('master runner error'))); | 
					
						
							|  |  |  |         let error = ''; | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |           await executor.execute(anyFn, anyFn); | 
					
						
							|  |  |  |         } catch (e) { | 
					
						
							|  |  |  |           error = e.message; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         expect(error).toEqual('master runner error'); | 
					
						
							| 
									
										
										
										
											2020-03-04 12:35:52 +00:00
										 |  |  |         expect(lockFileLog).toEqual(['write()', 'remove()']); | 
					
						
							| 
									
										
										
										
											2020-01-10 09:54:58 +00:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-04 12:35:52 +00:00
										 |  |  |       it('should not call master runner if LockFile.write() fails', async() => { | 
					
						
							| 
									
										
										
										
											2020-01-10 09:54:58 +00:00
										 |  |  |         const anyFn: () => any = () => undefined; | 
					
						
							| 
									
										
										
										
											2020-03-04 12:35:52 +00:00
										 |  |  |         spyOn(mockLockFile, 'write').and.callFake(() => { | 
					
						
							|  |  |  |           lockFileLog.push('write()'); | 
					
						
							|  |  |  |           throw new Error('LockFile.write() error'); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-14 13:38:27 +00:00
										 |  |  |         executor = new ClusterExecutor( | 
					
						
							|  |  |  |             42, mockLogger, null as unknown as PackageJsonUpdater, locker, | 
					
						
							|  |  |  |             createTaskCompletedCallback); | 
					
						
							| 
									
										
										
										
											2020-01-10 09:54:58 +00:00
										 |  |  |         let error = ''; | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |           await executor.execute(anyFn, anyFn); | 
					
						
							|  |  |  |         } catch (e) { | 
					
						
							|  |  |  |           error = e.message; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-03-04 12:35:52 +00:00
										 |  |  |         expect(error).toEqual('LockFile.write() error'); | 
					
						
							| 
									
										
										
										
											2020-01-10 09:54:58 +00:00
										 |  |  |         expect(masterRunSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-04 12:35:52 +00:00
										 |  |  |       it('should fail if LockFile.remove() fails', async() => { | 
					
						
							| 
									
										
										
										
											2020-01-10 09:54:58 +00:00
										 |  |  |         const anyFn: () => any = () => undefined; | 
					
						
							| 
									
										
										
										
											2020-03-04 12:35:52 +00:00
										 |  |  |         spyOn(mockLockFile, 'remove').and.callFake(() => { | 
					
						
							|  |  |  |           lockFileLog.push('remove()'); | 
					
						
							|  |  |  |           throw new Error('LockFile.remove() error'); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-14 13:38:27 +00:00
										 |  |  |         executor = new ClusterExecutor( | 
					
						
							|  |  |  |             42, mockLogger, null as unknown as PackageJsonUpdater, locker, | 
					
						
							|  |  |  |             createTaskCompletedCallback); | 
					
						
							| 
									
										
										
										
											2020-01-10 09:54:58 +00:00
										 |  |  |         let error = ''; | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |           await executor.execute(anyFn, anyFn); | 
					
						
							|  |  |  |         } catch (e) { | 
					
						
							|  |  |  |           error = e.message; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         expect(error).toEqual('LockFile.remove() error'); | 
					
						
							| 
									
										
										
										
											2020-03-04 12:35:52 +00:00
										 |  |  |         expect(lockFileLog).toEqual(['write()', 'remove()']); | 
					
						
							| 
									
										
										
										
											2020-01-10 09:54:58 +00:00
										 |  |  |         expect(masterRunSpy).toHaveBeenCalled(); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe('(on cluster worker)', () => { | 
					
						
							|  |  |  |       beforeEach(() => runAsClusterMaster(false)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-03 20:25:15 +00:00
										 |  |  |       it('should not log debug info about the executor', async() => { | 
					
						
							| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  |         const anyFn: () => any = () => undefined; | 
					
						
							| 
									
										
										
										
											2020-02-03 20:25:15 +00:00
										 |  |  |         await executor.execute(anyFn, anyFn); | 
					
						
							| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |         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)); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2020-01-10 09:54:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-04 12:35:52 +00:00
										 |  |  |       it('should not call LockFile.write() or LockFile.remove()', async() => { | 
					
						
							| 
									
										
										
										
											2020-01-10 09:54:58 +00:00
										 |  |  |         const anyFn: () => any = () => undefined; | 
					
						
							|  |  |  |         await executor.execute(anyFn, anyFn); | 
					
						
							| 
									
										
										
										
											2020-03-04 12:35:52 +00:00
										 |  |  |         expect(lockFileLog).toEqual([]); | 
					
						
							| 
									
										
										
										
											2020-01-10 09:54:58 +00:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }); |