f10f8db5fb
This commit fixes several issues discovered through use in real apps. * The sha1() function operated on text content, causing issues for binary-format files. A sha1Binary() function which operates on unparsed data now avoids any encoding issues. * The characters '?' and '+' were not escaped in Glob-to-regex conversion previously, but are now. * URLs from the browser contain the full origin, but were checked against the table of hashes from the manifest which only has the path for URLs from the same origin. Now the origin is checked and URLs are relativized to the domain root before comparison if appropriate. * ngsw: prefix was missing from data groups, is now added. * Occasionally servers will return a redirected response for an asset, and caching it could cause errors for navigation requests. The SW now handles this by detecting such responses and following the redirect manually, to avoid caching a redirected response. * The request for known assets is now created from scratch from the URL before fetching from the network, in order to sanitize it and avoid carrying any special modes or headers that might result in opaque responses. * Debugging log for troubleshooting. * Avoid creating errors by returning 504 responses on error. * Fix bug where idle queue doesn't run in some circumstances. * Add tests for the above.
137 lines
4.8 KiB
TypeScript
137 lines
4.8 KiB
TypeScript
/**
|
|
* @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';
|
|
|
|
export function main() {
|
|
// 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);
|
|
});
|
|
});
|
|
} |