diff --git a/dom/cache/moz.build b/dom/cache/moz.build index 4655b6cad907..b8c055ba6d35 100644 --- a/dom/cache/moz.build +++ b/dom/cache/moz.build @@ -100,3 +100,7 @@ MOCHITEST_CHROME_MANIFESTS += [ BROWSER_CHROME_MANIFESTS += [ 'test/mochitest/browser.ini', ] + +XPCSHELL_TESTS_MANIFESTS += [ + 'test/xpcshell/xpcshell.ini', +] diff --git a/dom/cache/test/xpcshell/head.js b/dom/cache/test/xpcshell/head.js new file mode 100644 index 000000000000..3d51929b3514 --- /dev/null +++ b/dom/cache/test/xpcshell/head.js @@ -0,0 +1,77 @@ +/** + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * All images in schema_15_profile.zip are from https://github.com/mdn/sw-test/ + * and are CC licensed by https://www.flickr.com/photos/legofenris/. + */ + +var Cc = Components.classes; +var Ci = Components.interfaces; +var Cu = Components.utils; + +// services required be initialized in order to run CacheStorage +var ss = Cc['@mozilla.org/storage/service;1'] + .createInstance(Ci.mozIStorageService); +var sts = Cc['@mozilla.org/network/stream-transport-service;1'] + .getService(Ci.nsIStreamTransportService); +var hash = Cc['@mozilla.org/security/hash;1'] + .createInstance(Ci.nsICryptoHash); + +// Expose Cache and Fetch symbols on the global +Cu.importGlobalProperties(['caches', 'fetch']); + +// Extract a zip file into the profile +function create_test_profile(zipFileName) { + do_get_profile(); + + var directoryService = Cc['@mozilla.org/file/directory_service;1'] + .getService(Ci.nsIProperties); + var profileDir = directoryService.get('ProfD', Ci.nsIFile); + var currentDir = directoryService.get('CurWorkD', Ci.nsIFile); + + var packageFile = currentDir.clone(); + packageFile.append(zipFileName); + + var zipReader = Cc['@mozilla.org/libjar/zip-reader;1'] + .createInstance(Ci.nsIZipReader); + zipReader.open(packageFile); + + var entryNames = []; + var entries = zipReader.findEntries(null); + while (entries.hasMore()) { + var entry = entries.getNext(); + entryNames.push(entry); + } + entryNames.sort(); + + for (var entryName of entryNames) { + var zipentry = zipReader.getEntry(entryName); + + var file = profileDir.clone(); + entryName.split('/').forEach(function(part) { + file.append(part); + }); + + if (zipentry.isDirectory) { + file.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt('0755', 8)); + } else { + var istream = zipReader.getInputStream(entryName); + + var ostream = Cc['@mozilla.org/network/file-output-stream;1'] + .createInstance(Ci.nsIFileOutputStream); + ostream.init(file, -1, parseInt('0644', 8), 0); + + var bostream = Cc['@mozilla.org/network/buffered-output-stream;1'] + .createInstance(Ci.nsIBufferedOutputStream); + bostream.init(ostream, 32 * 1024); + + bostream.writeFrom(istream, istream.available()); + + istream.close(); + bostream.close(); + } + } + + zipReader.close(); +} diff --git a/dom/cache/test/xpcshell/make_profile.js b/dom/cache/test/xpcshell/make_profile.js new file mode 100644 index 000000000000..b50c7aeb7735 --- /dev/null +++ b/dom/cache/test/xpcshell/make_profile.js @@ -0,0 +1,142 @@ +/** + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * All images in schema_15_profile.zip are from https://github.com/mdn/sw-test/ + * and are CC licensed by https://www.flickr.com/photos/legofenris/. + */ + +var Cc = Components.classes; +var Ci = Components.interfaces; +var Cu = Components.utils; + +// Enumerate the directory tree and store results in entryList as +// +// { path: 'a/b/c', file: } +// +// The algorithm starts with the first entry already in entryList. +function enumerate_tree(entryList) { + for (var index = 0; index < entryList.length; ++index) { + var path = entryList[index].path; + var file = entryList[index].file; + + if (file.isDirectory()) { + var dirList = file.directoryEntries; + while (dirList.hasMoreElements()) { + var dirFile = dirList.getNext().QueryInterface(Ci.nsIFile); + entryList.push({ path: path + '/' + dirFile.leafName, file: dirFile }); + } + } + } +} + +function zip_profile(zipFile, profileDir) { + var zipWriter = Cc['@mozilla.org/zipwriter;1'] + .createInstance(Ci.nsIZipWriter); + zipWriter.open(zipFile, 0x04 | 0x08 | 0x20); + + var root = profileDir.clone(); + root.append('storage'); + root.append('default'); + root.append('chrome'); + + var entryList = [{path: 'storage/default/chrome', file: root}]; + enumerate_tree(entryList); + + entryList.forEach(function(entry) { + if (entry.file.isDirectory()) { + zipWriter.addEntryDirectory(entry.path, entry.file.lastModifiedTime, + false); + } else { + var istream = Cc['@mozilla.org/network/file-input-stream;1'] + .createInstance(Ci.nsIFileInputStream); + istream.init(entry.file, -1, -1, 0); + zipWriter.addEntryStream(entry.path, entry.file.lastModifiedTime, + Ci.nsIZipWriter.COMPRESSION_DEFAULT, istream, + false); + istream.close(); + } + }); + + zipWriter.close(); +} + +function exactGC() { + return new Promise(function(resolve) { + var count = 0; + function doPreciseGCandCC() { + function scheduleGCCallback() { + Cu.forceCC(); + + if (++count < 2) { + doPreciseGCandCC(); + } else { + resolve(); + } + } + Cu.schedulePreciseGC(scheduleGCCallback); + } + doPreciseGCandCC(); + }); +} + +function resetQuotaManager() { + return new Promise(function(resolve) { + var qm = Cc['@mozilla.org/dom/quota/manager;1'] + .getService(Ci.nsIQuotaManager); + + var prefService = Cc['@mozilla.org/preferences-service;1'] + .getService(Ci.nsIPrefService); + + // enable quota manager testing mode + var pref = 'dom.quotaManager.testing'; + prefService.getBranch(null).setBoolPref(pref, true); + + qm.reset(); + + // disable quota manager testing mode + //prefService.getBranch(null).setBoolPref(pref, false); + + var uri = Cc['@mozilla.org/network/io-service;1'] + .getService(Ci.nsIIOService) + .newURI('http://example.com', null, null); + var principal = Cc['@mozilla.org/scriptsecuritymanager;1'] + .getService(Ci.nsIScriptSecurityManager) + .getSystemPrincipal(); + + // use getUsageForPrincipal() to get a callback when the reset() is done + qm.getUsageForPrincipal(principal, function(principal, usage, fileUsage) { + resolve(usage); + }); + }); +} + +function run_test() { + do_test_pending(); + do_get_profile(); + + var directoryService = Cc['@mozilla.org/file/directory_service;1'] + .getService(Ci.nsIProperties); + var profileDir = directoryService.get('ProfD', Ci.nsIFile); + var currentDir = directoryService.get('CurWorkD', Ci.nsIFile); + + var zipFile = currentDir.clone(); + zipFile.append('new_profile.zip'); + if (zipFile.exists()) { + zipFile.remove(false); + } + ok(!zipFile.exists()); + + caches.open('xpcshell-test').then(function(c) { + var request = new Request('http://example.com/index.html'); + var response = new Response('hello world'); + return c.put(request, response); + }).then(exactGC).then(resetQuotaManager).then(function() { + zip_profile(zipFile, profileDir); + dump('### ### created zip at: ' + zipFile.path + '\n'); + do_test_finished(); + }).catch(function(e) { + do_test_finished(); + ok(false, e); + }); +} diff --git a/dom/cache/test/xpcshell/schema_15_profile.zip b/dom/cache/test/xpcshell/schema_15_profile.zip new file mode 100644 index 000000000000..6d742275b309 Binary files /dev/null and b/dom/cache/test/xpcshell/schema_15_profile.zip differ diff --git a/dom/cache/test/xpcshell/test_migration.js b/dom/cache/test/xpcshell/test_migration.js new file mode 100644 index 000000000000..3076f3f5903c --- /dev/null +++ b/dom/cache/test/xpcshell/test_migration.js @@ -0,0 +1,38 @@ +/** + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * All images in schema_15_profile.zip are from https://github.com/mdn/sw-test/ + * and are CC licensed by https://www.flickr.com/photos/legofenris/. + */ + +function run_test() { + do_test_pending(); + create_test_profile('schema_15_profile.zip'); + + var cache; + caches.open('xpcshell-test').then(function(c) { + cache = c; + ok(cache, 'cache exists'); + return cache.keys(); + }).then(function(requestList) { + ok(requestList.length > 0, 'should have at least one request in cache'); + requestList.forEach(function(request) { + ok(request, 'each request in list should be non-null'); + ok(request.redirect === 'follow', 'request.redirect should default to "follow"'); + }); + return Promise.all(requestList.map(function(request) { + return cache.match(request); + })); + }).then(function(responseList) { + ok(responseList.length > 0, 'should have at least one response in cache'); + responseList.forEach(function(response) { + ok(response, 'each request in list should be non-null'); + }); + }).then(function() { + do_test_finished(); + }).catch(function(e) { + ok(false, 'caught exception ' + e); + do_test_finished(); + }); +} diff --git a/dom/cache/test/xpcshell/xpcshell.ini b/dom/cache/test/xpcshell/xpcshell.ini new file mode 100644 index 000000000000..2bd3f90747fa --- /dev/null +++ b/dom/cache/test/xpcshell/xpcshell.ini @@ -0,0 +1,16 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +[DEFAULT] +head = head.js +tail = +skip-if = toolkit == 'gonk' +support-files = + schema_15_profile.zip + +# dummy test entry to generate profile zip files +[make_profile.js] + skip-if = true + +[test_migration.js]