| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							| 
									
										
										
										
											2020-05-19 12:08:49 -07:00
										 |  |  |  * Copyright Google LLC All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  |  * | 
					
						
							|  |  |  |  * 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" />
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-15 16:35:09 +01:00
										 |  |  | import {getFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system'; | 
					
						
							| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  | import * as cluster from 'cluster'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-15 16:35:09 +01:00
										 |  |  | import {MockFileSystemNative, runInEachFileSystem} from '../../../../src/ngtsc/file_system/testing'; | 
					
						
							| 
									
										
										
										
											2020-05-14 20:06:12 +01:00
										 |  |  | import {MockLogger} from '../../../../src/ngtsc/logging/testing'; | 
					
						
							| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  | import {ClusterExecutor} from '../../../src/execution/cluster/executor'; | 
					
						
							|  |  |  | import {ClusterMaster} from '../../../src/execution/cluster/master'; | 
					
						
							| 
									
										
										
										
											2020-03-04 12:49:36 +00:00
										 |  |  | import {AsyncLocker} from '../../../src/locking/async_locker'; | 
					
						
							| 
									
										
										
										
											2020-04-29 21:28:22 +03:00
										 |  |  | import {FileWriter} from '../../../src/writing/file_writer'; | 
					
						
							| 
									
										
										
										
											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 {mockProperty} from '../../helpers/spy_utils'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-15 16:35:09 +01:00
										 |  |  | 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; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     beforeEach(() => { | 
					
						
							|  |  |  |       masterRunSpy = spyOn(ClusterMaster.prototype, 'run') | 
					
						
							| 
									
										
										
										
											2020-06-25 16:43:05 +01:00
										 |  |  |                          .and.returnValue(Promise.resolve('ClusterMaster#run()' as any)); | 
					
						
							| 
									
										
										
										
											2020-04-15 16:35:09 +01:00
										 |  |  |       createTaskCompletedCallback = jasmine.createSpy('createTaskCompletedCallback'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       mockLogger = new MockLogger(); | 
					
						
							|  |  |  |       lockFileLog = []; | 
					
						
							|  |  |  |       mockLockFile = new MockLockFile(new MockFileSystemNative(), lockFileLog); | 
					
						
							|  |  |  |       locker = new AsyncLocker(mockLockFile, mockLogger, 200, 2); | 
					
						
							|  |  |  |       executor = new ClusterExecutor( | 
					
						
							| 
									
										
										
										
											2020-04-29 21:28:22 +03:00
										 |  |  |           42, getFileSystem(), mockLogger, null as unknown as FileWriter, | 
					
						
							|  |  |  |           null as unknown as PackageJsonUpdater, locker, createTaskCompletedCallback); | 
					
						
							| 
									
										
										
										
											2020-04-15 16:35:09 +01:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-15 16:35:09 +01:00
										 |  |  |     describe('execute()', () => { | 
					
						
							| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  |       beforeEach(() => runAsClusterMaster(true)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-06 08:30:08 +01: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).'], | 
					
						
							|  |  |  |         ]); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-06 08:30:08 +01:00
										 |  |  |       it('should delegate to `ClusterMaster#run()`', async () => { | 
					
						
							| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  |         const analyzeEntryPointsSpy = jasmine.createSpy('analyzeEntryPoints'); | 
					
						
							|  |  |  |         const createCompilerFnSpy = jasmine.createSpy('createCompilerFn'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(await executor.execute(analyzeEntryPointsSpy, createCompilerFnSpy)) | 
					
						
							| 
									
										
										
										
											2020-06-25 16:43:05 +01:00
										 |  |  |             .toBe('ClusterMaster#run()' as any); | 
					
						
							| 
									
										
										
										
											2019-08-29 18:47:54 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |         expect(masterRunSpy).toHaveBeenCalledWith(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         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-04-06 08:30:08 +01:00
										 |  |  |          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(['write()', 'remove()']); | 
					
						
							| 
									
										
										
										
											2020-01-10 09:54:58 +00:00
										 |  |  |          }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-25 16:43:05 +01:00
										 |  |  |       it('should call LockFile.write() and LockFile.remove() if analyzeFn fails', async () => { | 
					
						
							|  |  |  |         const analyzeEntryPointsSpy = | 
					
						
							|  |  |  |             jasmine.createSpy('analyzeEntryPoints').and.throwError('analyze error'); | 
					
						
							|  |  |  |         const createCompilerFnSpy = jasmine.createSpy('createCompilerFn'); | 
					
						
							|  |  |  |         let error = ''; | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |           await executor.execute(analyzeEntryPointsSpy, createCompilerFnSpy); | 
					
						
							|  |  |  |         } catch (e) { | 
					
						
							|  |  |  |           error = e.message; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         expect(analyzeEntryPointsSpy).toHaveBeenCalledWith(); | 
					
						
							|  |  |  |         expect(createCompilerFnSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |         expect(error).toEqual('analyze error'); | 
					
						
							|  |  |  |         expect(lockFileLog).toEqual(['write()', 'remove()']); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-06 08:30:08 +01: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-04-06 08:30:08 +01: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( | 
					
						
							| 
									
										
										
										
											2020-04-29 21:28:22 +03:00
										 |  |  |             42, getFileSystem(), mockLogger, null as unknown as FileWriter, | 
					
						
							|  |  |  |             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-04-06 08:30:08 +01: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( | 
					
						
							| 
									
										
										
										
											2020-04-29 21:28:22 +03:00
										 |  |  |             42, getFileSystem(), mockLogger, null as unknown as FileWriter, | 
					
						
							|  |  |  |             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
										 |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }); |