| 
									
										
										
										
											2017-10-02 15:59:57 -07: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
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import {IdleScheduler} from '../src/idle'; | 
					
						
							|  |  |  | import {SwTestHarness, SwTestHarnessBuilder} from '../testing/scope'; | 
					
						
							|  |  |  | import {async_beforeEach, async_fit, async_it} from './async'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-17 15:10:54 -08:00
										 |  |  | (function() { | 
					
						
							| 
									
										
										
										
											2017-10-02 15:59:57 -07:00
										 |  |  |   // Skip environments that don't support the minimum APIs needed to run the SW tests.
 | 
					
						
							|  |  |  |   if (!SwTestHarness.envIsSupported()) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   describe('IdleScheduler', () => { | 
					
						
							|  |  |  |     let scope: SwTestHarness; | 
					
						
							|  |  |  |     let idle: IdleScheduler; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     beforeEach(() => { | 
					
						
							|  |  |  |       scope = new SwTestHarnessBuilder().build(); | 
					
						
							|  |  |  |       idle = new IdleScheduler(scope, 1000, { | 
					
						
							|  |  |  |         log: (v, context) => console.error(v, context), | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Validate that a single idle task executes when trigger()
 | 
					
						
							|  |  |  |     // is called and the idle timeout passes.
 | 
					
						
							|  |  |  |     async_it('executes scheduled work on time', async() => { | 
					
						
							|  |  |  |       // Set up a single idle task to set the completed flag to true when it runs.
 | 
					
						
							|  |  |  |       let completed: boolean = false; | 
					
						
							|  |  |  |       idle.schedule('work', async() => { completed = true; }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Simply scheduling the task should not cause it to execute.
 | 
					
						
							|  |  |  |       expect(completed).toEqual(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Trigger the idle mechanism. This returns a Promise that should resolve
 | 
					
						
							|  |  |  |       // once the idle timeout has passed.
 | 
					
						
							|  |  |  |       const trigger = idle.trigger(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Advance the clock beyond the idle timeout, causing the idle tasks to run.
 | 
					
						
							|  |  |  |       scope.advance(1100); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // It should now be possible to wait for the trigger, and for the idle queue
 | 
					
						
							|  |  |  |       // to be empty.
 | 
					
						
							|  |  |  |       await trigger; | 
					
						
							|  |  |  |       await idle.empty; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // The task should now have run.
 | 
					
						
							|  |  |  |       expect(completed).toEqual(true); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async_it('waits for multiple tasks to complete serially', async() => { | 
					
						
							|  |  |  |       // Schedule several tasks that will increase a counter according to its
 | 
					
						
							|  |  |  |       // current value. If these tasks execute in parallel, the writes to the counter
 | 
					
						
							|  |  |  |       // will race, and the test will fail.
 | 
					
						
							|  |  |  |       let counter: number = 2; | 
					
						
							|  |  |  |       idle.schedule('double counter', async() => { | 
					
						
							|  |  |  |         let local = counter; | 
					
						
							|  |  |  |         await Promise.resolve(); | 
					
						
							|  |  |  |         local *= 2; | 
					
						
							|  |  |  |         await Promise.resolve(); | 
					
						
							|  |  |  |         counter = local * 2; | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       idle.schedule('triple counter', async() => { | 
					
						
							|  |  |  |         // If this expect fails, it comes out of the 'await trigger' below.
 | 
					
						
							|  |  |  |         expect(counter).toEqual(8); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Multiply the counter by 3 twice.
 | 
					
						
							|  |  |  |         let local = counter; | 
					
						
							|  |  |  |         await Promise.resolve(); | 
					
						
							|  |  |  |         local *= 3; | 
					
						
							|  |  |  |         await Promise.resolve(); | 
					
						
							|  |  |  |         counter = local * 3; | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Trigger the idle mechanism once.
 | 
					
						
							|  |  |  |       const trigger = idle.trigger(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Advance the clock beyond the idle timeout, causing the idle tasks to run, and
 | 
					
						
							|  |  |  |       // wait for them to complete.
 | 
					
						
							|  |  |  |       scope.advance(1100); | 
					
						
							|  |  |  |       await trigger; | 
					
						
							|  |  |  |       await idle.empty; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Assert that both tasks executed in the correct serial sequence by validating
 | 
					
						
							|  |  |  |       // that the counter reached the correct value.
 | 
					
						
							|  |  |  |       expect(counter).toEqual(2 * 2 * 2 * 3 * 3); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Validate that a single idle task does not execute until trigger() has been called
 | 
					
						
							|  |  |  |     // and sufficient time passes without it being called again.
 | 
					
						
							|  |  |  |     async_it('does not execute work until timeout passes with no triggers', async() => { | 
					
						
							|  |  |  |       // Set up a single idle task to set the completed flag to true when it runs.
 | 
					
						
							|  |  |  |       let completed: boolean = false; | 
					
						
							|  |  |  |       idle.schedule('work', async() => { completed = true; }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Trigger the queue once. This trigger will start a timer for the idle timeout,
 | 
					
						
							|  |  |  |       // but another trigger() will be called before that timeout passes.
 | 
					
						
							|  |  |  |       const firstTrigger = idle.trigger(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Advance the clock a little, but not enough to actually cause tasks to execute.
 | 
					
						
							|  |  |  |       scope.advance(500); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Assert that the task has not yet run.
 | 
					
						
							|  |  |  |       expect(completed).toEqual(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Next, trigger the queue again.
 | 
					
						
							|  |  |  |       const secondTrigger = idle.trigger(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Advance the clock beyond the timeout for the first trigger, but not the second.
 | 
					
						
							|  |  |  |       // This should cause the first trigger to resolve, but without running the task.
 | 
					
						
							|  |  |  |       scope.advance(600); | 
					
						
							|  |  |  |       await firstTrigger; | 
					
						
							|  |  |  |       expect(completed).toEqual(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Schedule a third trigger. This is the one that will eventually resolve the task.
 | 
					
						
							|  |  |  |       const thirdTrigger = idle.trigger(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Again, advance beyond the second trigger and verify it didn't resolve the task.
 | 
					
						
							|  |  |  |       scope.advance(500); | 
					
						
							|  |  |  |       await secondTrigger; | 
					
						
							|  |  |  |       expect(completed).toEqual(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Finally, advance beyond the third trigger, which should cause the task to be
 | 
					
						
							|  |  |  |       // executed finally.
 | 
					
						
							|  |  |  |       scope.advance(600); | 
					
						
							|  |  |  |       await thirdTrigger; | 
					
						
							|  |  |  |       await idle.empty; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // The task should have executed.
 | 
					
						
							|  |  |  |       expect(completed).toEqual(true); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2017-12-16 14:42:55 -08:00
										 |  |  | })(); |