| <!DOCTYPE html> |
| <script src="/js-test-resources/js-test.js"></script> |
| <script src="resources/test-helpers.js"></script> |
| <script> |
| window.jsTestIsAsync = true; |
| description('Test that ServiceWorker and ServiceWorkerRegistration are not garbage collected prematurely'); |
| var registrationObservation = null; |
| var swObservation = null; |
| var scope = base_path() + 'resources/gc'; |
| |
| if (!window.internals) { |
| testFailed('This test requires internals.observeGC'); |
| finishJSTest(); |
| } else { |
| setup(); |
| } |
| |
| function setup() { |
| var worker = 'resources/empty-worker.js'; |
| unregisterAndRegister(worker, scope).then(onRegister); |
| } |
| |
| function unregisterAndRegister(url, scope) { |
| return navigator.serviceWorker.getRegistration(scope) |
| .then(function(registration) { |
| if (registration) |
| return registration.unregister(); |
| }) |
| .then(function() { |
| return navigator.serviceWorker.register(url, { scope: scope }); |
| }) |
| .catch(function(error) { |
| testFailed('Could not register worker: ' + error); |
| finishJSTest(); |
| }); |
| } |
| |
| function onRegister(registration) { |
| registrationObservation = internals.observeGC(registration); |
| registration.addEventListener('updatefound', (function() { |
| onUpdate(registration.installing); |
| })); |
| } |
| |
| function onUpdate(sw) { |
| swObservation = internals.observeGC(sw); |
| sw.addEventListener('statechange', onStateChange); |
| } |
| |
| function onStateChange(event) { |
| // Use setTimeout to ensure a fresh stack with no references to the worker. |
| switch (event.target.state) { |
| case 'activated': |
| setTimeout(unregister, 0); |
| break; |
| case 'redundant': |
| setTimeout(finish, 0); |
| break; |
| } |
| } |
| |
| function unregister() { |
| // The worker has an event handler that can still receive the state change |
| // to 'redundant', so it shouldn't be collected yet. |
| gc(); |
| shouldBeFalse('registrationObservation.wasCollected'); |
| shouldBeFalse('swObservation.wasCollected'); |
| navigator.serviceWorker.getRegistration(scope) |
| .then(function(registration) { |
| registration.unregister(); |
| }) |
| .catch(function(error) { |
| testFailed('Could not unregister worker: ' + error); |
| finishJSTest(); |
| }); |
| } |
| |
| function finish() |
| { |
| // The worker is 'redundant' but the registration holds a reference to it, |
| // so it shouldn't be collected yet. |
| // FIXME: When crbug.com/398355 is fixed, register a new script URL and |
| // once the new worker is activated, check that the old worker is gc'd. |
| gc(); |
| shouldBeFalse('registrationObservation.wasCollected'); |
| shouldBeFalse('swObservation.wasCollected'); |
| finishJSTest(); |
| } |
| </script> |