-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Service worker: Tests for updateViaCache (previously useCache) #5515
Merged
jgraham
merged 9 commits into
web-platform-tests:master
from
jakearchibald:sw-updateviacache
Aug 2, 2017
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
fd2bd88
Tests for updateViaCache (previously useCache)
jakearchibald 512ae2a
Fixing trailing whitespace
jakearchibald 60db228
Was checking .installing on wrong object.
jakearchibald ad8943a
“never” to “none”
jakearchibald 572762c
Testing setting via link element & link header
jakearchibald 11d016c
Adding default & invalid val
jakearchibald 52c3bd9
Responding to feedback
jakearchibald 9786ea9
Improving comment wording
jakearchibald 3c2289d
Fixing 'all' case. Also testing reg.updateViaCache.
jakearchibald File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
222 changes: 222 additions & 0 deletions
222
service-workers/service-worker/registration-updateviacache.https.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
<!DOCTYPE html> | ||
<title>Service Worker: Registration-updateViaCache</title> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="resources/testharness-helpers.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="resources/test-helpers.sub.js"></script> | ||
<script> | ||
const UPDATE_VIA_CACHE_VALUES = [undefined, 'imports', 'all', 'none']; | ||
const SCRIPT_URL = 'resources/update-max-aged-worker.py'; | ||
const SCOPE = 'resources/blank.html'; | ||
|
||
async function cleanup() { | ||
const reg = await navigator.serviceWorker.getRegistration(SCOPE); | ||
if (!reg) return; | ||
if (reg.scope == new URL(SCOPE, location).href) { | ||
return reg.unregister(); | ||
}; | ||
} | ||
|
||
function getScriptTimes(sw, testName) { | ||
return new Promise(resolve => { | ||
navigator.serviceWorker.addEventListener('message', function listener(event) { | ||
if (event.data.test !== testName) return; | ||
navigator.serviceWorker.removeEventListener('message', listener); | ||
resolve({ | ||
mainTime: event.data.mainTime, | ||
importTime: event.data.importTime | ||
}); | ||
}); | ||
|
||
sw.postMessage(''); | ||
}); | ||
} | ||
|
||
function registerViaApi(scriptUrl, opts) { | ||
return navigator.serviceWorker.register(scriptUrl, opts); | ||
} | ||
|
||
function registerViaLinkElement(scriptUrl, opts) { | ||
return new Promise((resolve, reject) => { | ||
const link = document.createElement('link'); | ||
|
||
if (link.relList.supports('serviceworker') == false) throw Error("link rel=serviceworker not supported"); | ||
|
||
link.rel = 'serviceworker'; | ||
link.href = scriptUrl; | ||
link.scope = opts.scope; | ||
|
||
if (opts.updateViaCache) { | ||
link.updateViaCache = opts.updateViaCache; | ||
} | ||
|
||
link.onload = async () => { | ||
const fullScope = new URL(opts.scope, window.location).href; | ||
|
||
const regs = await navigator.serviceWorker.getRegistrations(); | ||
const reg = regs.find(r => r.scope == fullScope && (r.installing || r.waiting || r.active)); | ||
|
||
if (reg) { | ||
document.head.removeChild(link); | ||
resolve(reg); | ||
} | ||
else { | ||
reject(Error('Service worker not registered')); | ||
} | ||
}; | ||
|
||
document.head.appendChild(link); | ||
}); | ||
} | ||
|
||
async function registerViaLinkHeader(scriptUrl, opts) { | ||
const link = document.createElement('link'); | ||
|
||
const fullScope = new URL(opts.scope, window.location).href; | ||
scriptUrl = new URL(scriptUrl, location).href; | ||
|
||
// Assume that if the link element doesn't support serviceworker, the header doesn't either. | ||
if (link.relList.supports('serviceworker') == false) throw Error("link rel=serviceworker not supported"); | ||
|
||
let linkHeader = `<${scriptUrl}>; rel=serviceworker; scope="${fullScope}"`; | ||
|
||
if (opts.updateViaCache) { | ||
linkHeader += `; updateviacache="${opts.updateViaCache}"`; | ||
} | ||
|
||
const linkHeaderSenderURL = new URL('resources/link-header.py', location); | ||
linkHeaderSenderURL.searchParams.set('Link', linkHeader); | ||
|
||
await fetch(linkHeaderSenderURL); | ||
const frame = await with_iframe(fullScope); | ||
await frame.contentWindow.navigator.serviceWorker.ready; | ||
|
||
const regs = await navigator.serviceWorker.getRegistrations(); | ||
const reg = regs.find(r => r.scope == fullScope && (r.installing || r.waiting || r.active)); | ||
|
||
if (!reg) throw Error('Service worker not registered'); | ||
|
||
frame.parentNode.removeChild(frame); | ||
return reg; | ||
} | ||
|
||
const registrationMethods = [ | ||
[registerViaApi, 'via-api'], | ||
[registerViaLinkElement, 'via-link-element'], | ||
[registerViaLinkHeader, 'via-link-header'] | ||
]; | ||
|
||
// Test creating registrations & triggering an update. | ||
for (const [registrationMethod, registrationMethodName] of registrationMethods) { | ||
for (const updateViaCache of UPDATE_VIA_CACHE_VALUES) { | ||
const testName = `register-${registrationMethodName}-updateViaCache-${updateViaCache}`; | ||
|
||
promise_test(async t => { | ||
await cleanup(); | ||
|
||
const opts = {scope: SCOPE}; | ||
|
||
if (updateViaCache) opts.updateViaCache = updateViaCache; | ||
|
||
const reg = await registrationMethod( | ||
`${SCRIPT_URL}?test=${testName}`, | ||
opts | ||
); | ||
|
||
assert_equals(reg.updateViaCache, updateViaCache || 'imports', "reg.updateViaCache"); | ||
|
||
const sw = reg.installing || reg.waiting || reg.active; | ||
await wait_for_state(t, sw, 'activated'); | ||
const values = await getScriptTimes(sw, testName); | ||
await reg.update(); | ||
|
||
if (updateViaCache == 'all') { | ||
assert_equals(reg.installing, null, "No new service worker"); | ||
} | ||
else { | ||
const newWorker = reg.installing; | ||
assert_true(!!newWorker, "New worker installing"); | ||
const newValues = await getScriptTimes(newWorker, testName); | ||
|
||
if (!updateViaCache || updateViaCache == 'imports') { | ||
assert_not_equals(values.mainTime, newValues.mainTime, "Main script should have updated"); | ||
assert_equals(values.importTime, newValues.importTime, "Imported script should be the same"); | ||
} | ||
else if (updateViaCache == 'none') { | ||
assert_not_equals(values.mainTime, newValues.mainTime, "Main script should have updated"); | ||
assert_not_equals(values.importTime, newValues.importTime, "Imported script should have updated"); | ||
} | ||
else { | ||
// We should have handled all of the possible values for updateViaCache. | ||
// If this runs, something's gone very wrong. | ||
throw Error(`Unexpected updateViaCache value: ${updateViaCache}`); | ||
} | ||
} | ||
|
||
await cleanup(); | ||
}, testName); | ||
} | ||
} | ||
|
||
// Test changing the updateViaCache value of an existing registration. | ||
for (const updateViaCache1 of UPDATE_VIA_CACHE_VALUES) { | ||
for (const updateViaCache2 of UPDATE_VIA_CACHE_VALUES) { | ||
const testName = `register-with-updateViaCache-${updateViaCache1}-then-${updateViaCache2}`; | ||
|
||
promise_test(async t => { | ||
await cleanup(); | ||
|
||
const fullScriptUrl = `${SCRIPT_URL}?test=${testName}`; | ||
let opts = {scope: SCOPE}; | ||
if (updateViaCache1) opts.updateViaCache = updateViaCache1; | ||
|
||
const reg = await navigator.serviceWorker.register(fullScriptUrl, opts); | ||
|
||
const sw = reg.installing; | ||
await wait_for_state(t, sw, 'activated'); | ||
const values = await getScriptTimes(sw, testName); | ||
|
||
opts = {scope: SCOPE}; | ||
if (updateViaCache2) opts.updateViaCache = updateViaCache2; | ||
|
||
await navigator.serviceWorker.register(fullScriptUrl, opts); | ||
|
||
assert_equals(reg.updateViaCache, updateViaCache2 || 'imports', "reg.updateViaCache updated"); | ||
|
||
// If the update happens via the cache, the scripts will come back byte-identical. | ||
// We bypass the byte-identical check if the script URL has changed, but not if | ||
// only the updateViaCache value has changed. | ||
if (updateViaCache2 == 'all') { | ||
assert_equals(reg.installing, null, "No new service worker"); | ||
} | ||
// If there's no change to the updateViaCache value, register should be a no-op. | ||
// The default value should behave as 'imports'. | ||
else if ((updateViaCache1 || 'imports') == (updateViaCache2 || 'imports')) { | ||
assert_equals(reg.installing, null, "No new service worker"); | ||
} | ||
else { | ||
const newWorker = reg.installing; | ||
assert_true(!!newWorker, "New worker installing"); | ||
const newValues = await getScriptTimes(newWorker, testName); | ||
|
||
if (!updateViaCache2 || updateViaCache2 == 'imports') { | ||
assert_not_equals(values.mainTime, newValues.mainTime, "Main script should have updated"); | ||
assert_equals(values.importTime, newValues.importTime, "Imported script should be the same"); | ||
} | ||
else if (updateViaCache2 == 'none') { | ||
assert_not_equals(values.mainTime, newValues.mainTime, "Main script should have updated"); | ||
assert_not_equals(values.importTime, newValues.importTime, "Imported script should have updated"); | ||
} | ||
else { | ||
// We should have handled all of the possible values for updateViaCache2. | ||
// If this runs, something's gone very wrong. | ||
throw Error(`Unexpected updateViaCache value: ${updateViaCache}`); | ||
} | ||
} | ||
|
||
await cleanup(); | ||
}, testName); | ||
} | ||
} | ||
|
||
</script> |
12 changes: 12 additions & 0 deletions
12
service-workers/service-worker/resources/update-max-aged-worker-imported-script.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import time | ||
|
||
def main(request, response): | ||
headers = [('Content-Type', 'application/javascript'), | ||
('Cache-Control', 'max-age=86400'), | ||
('Last-Modified', time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()))] | ||
|
||
body = ''' | ||
const importTime = {time}; | ||
'''.format(time=time.time()) | ||
|
||
return headers, body |
28 changes: 28 additions & 0 deletions
28
service-workers/service-worker/resources/update-max-aged-worker.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import time | ||
import json | ||
|
||
def main(request, response): | ||
headers = [('Content-Type', 'application/javascript'), | ||
('Cache-Control', 'max-age=86400'), | ||
('Last-Modified', time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()))] | ||
|
||
test = request.GET['test'] | ||
|
||
body = ''' | ||
const mainTime = {time}; | ||
const testName = {test}; | ||
importScripts('update-max-aged-worker-imported-script.py'); | ||
|
||
addEventListener('message', event => {{ | ||
event.source.postMessage({{ | ||
mainTime, | ||
importTime, | ||
test: {test} | ||
}}); | ||
}}); | ||
'''.format( | ||
time=time.time(), | ||
test=json.dumps(test) | ||
) | ||
|
||
return headers, body |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A little confusing that this param is the same name as the global |scriptUrl|.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was fixed by renaming the global