head.js (8143B)
1 /** 2 * Any copyright is dedicated to the Public Domain. 3 * http://creativecommons.org/publicdomain/zero/1.0/ 4 */ 5 6 // Tests are expected to define testSteps. 7 /* globals testSteps */ 8 9 const NS_ERROR_DOM_QUOTA_EXCEEDED_ERR = 22; 10 11 function is(a, b, msg) { 12 Assert.equal(a, b, msg); 13 } 14 15 function ok(cond, msg) { 16 Assert.ok(!!cond, msg); 17 } 18 19 add_setup(function () { 20 do_get_profile(); 21 22 const { ProcessUtils } = ChromeUtils.importESModule( 23 "resource://testing-common/dom/quota/test/modules/ProcessUtils.sys.mjs" 24 ); 25 26 if (ProcessUtils.isInParentProcess()) { 27 enableTesting(); 28 29 registerCleanupFunction(resetTesting); 30 } 31 }); 32 33 function returnToEventLoop() { 34 return new Promise(function (resolve) { 35 executeSoon(resolve); 36 }); 37 } 38 39 function enableTesting() { 40 Services.prefs.setBoolPref("dom.simpleDB.enabled", true); 41 Services.prefs.setBoolPref("dom.storage.testing", true); 42 43 // xpcshell globals don't have associated clients in the Clients API sense, so 44 // we need to disable client validation so that the unit tests are allowed to 45 // use LocalStorage. 46 Services.prefs.setBoolPref("dom.storage.client_validation", false); 47 48 Services.prefs.setBoolPref("dom.quotaManager.testing", true); 49 } 50 51 function resetTesting() { 52 Services.prefs.clearUserPref("dom.quotaManager.testing"); 53 Services.prefs.clearUserPref("dom.storage.client_validation"); 54 Services.prefs.clearUserPref("dom.storage.testing"); 55 Services.prefs.clearUserPref("dom.simpleDB.enabled"); 56 } 57 58 function setGlobalLimit(globalLimit) { 59 Services.prefs.setIntPref( 60 "dom.quotaManager.temporaryStorage.fixedLimit", 61 globalLimit 62 ); 63 } 64 65 function resetGlobalLimit() { 66 Services.prefs.clearUserPref("dom.quotaManager.temporaryStorage.fixedLimit"); 67 } 68 69 function setOriginLimit(originLimit) { 70 Services.prefs.setIntPref("dom.storage.default_quota", originLimit); 71 } 72 73 function resetOriginLimit() { 74 Services.prefs.clearUserPref("dom.storage.default_quota"); 75 } 76 77 function setTimeout(callback, timeout) { 78 let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); 79 80 timer.initWithCallback( 81 { 82 notify() { 83 callback(); 84 }, 85 }, 86 timeout, 87 Ci.nsITimer.TYPE_ONE_SHOT 88 ); 89 90 return timer; 91 } 92 93 function initStorage() { 94 return Services.qms.init(); 95 } 96 97 function initTemporaryStorage() { 98 return Services.qms.initTemporaryStorage(); 99 } 100 101 function initPersistentOrigin(principal) { 102 return Services.qms.initializePersistentOrigin(principal); 103 } 104 105 function initTemporaryOrigin( 106 persistence, 107 principal, 108 createIfNonExistent = true 109 ) { 110 return Services.qms.initializeTemporaryOrigin( 111 persistence, 112 principal, 113 createIfNonExistent 114 ); 115 } 116 117 function getOriginUsage(principal) { 118 let request = Services.qms.getUsageForPrincipal(principal, function () {}); 119 120 return request; 121 } 122 123 function getCachedOriginUsage(principal) { 124 let request = Services.qms.getCachedUsageForPrincipal( 125 principal, 126 function () {} 127 ); 128 129 return request; 130 } 131 132 function clear() { 133 let request = Services.qms.clear(); 134 135 return request; 136 } 137 138 function clearOriginsByPattern(pattern) { 139 let request = Services.qms.clearStoragesForOriginAttributesPattern(pattern); 140 141 return request; 142 } 143 144 function clearOriginsByPrefix(principal, persistence) { 145 let request = Services.qms.clearStoragesForOriginPrefix( 146 principal, 147 persistence 148 ); 149 150 return request; 151 } 152 153 function clearOrigin(principal, persistence) { 154 let request = Services.qms.clearStoragesForPrincipal(principal, persistence); 155 156 return request; 157 } 158 159 function reset() { 160 let request = Services.qms.reset(); 161 162 return request; 163 } 164 165 function resetClient(principal) { 166 let request = Services.qms.resetStoragesForClient(principal, "ls", "default"); 167 168 return request; 169 } 170 171 function installPackage(packageName) { 172 let currentDir = Services.dirsvc.get("CurWorkD", Ci.nsIFile); 173 174 let packageFile = currentDir.clone(); 175 packageFile.append(packageName + ".zip"); 176 177 let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].createInstance( 178 Ci.nsIZipReader 179 ); 180 zipReader.open(packageFile); 181 182 let entryNames = []; 183 let entries = zipReader.findEntries(null); 184 while (entries.hasMore()) { 185 let entry = entries.getNext(); 186 entryNames.push(entry); 187 } 188 entryNames.sort(); 189 190 for (let entryName of entryNames) { 191 let zipentry = zipReader.getEntry(entryName); 192 193 let file = getRelativeFile(entryName); 194 195 if (zipentry.isDirectory) { 196 file.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0755", 8)); 197 } else { 198 let istream = zipReader.getInputStream(entryName); 199 200 var ostream = Cc[ 201 "@mozilla.org/network/file-output-stream;1" 202 ].createInstance(Ci.nsIFileOutputStream); 203 ostream.init(file, -1, parseInt("0644", 8), 0); 204 205 let bostream = Cc[ 206 "@mozilla.org/network/buffered-output-stream;1" 207 ].createInstance(Ci.nsIBufferedOutputStream); 208 bostream.init(ostream, 32768); 209 210 bostream.writeFrom(istream, istream.available()); 211 212 istream.close(); 213 bostream.close(); 214 } 215 } 216 217 zipReader.close(); 218 } 219 220 function getProfileDir() { 221 return Services.dirsvc.get("ProfD", Ci.nsIFile); 222 } 223 224 // Given a "/"-delimited path relative to the profile directory, 225 // return an nsIFile representing the path. This does not test 226 // for the existence of the file or parent directories. 227 // It is safe even on Windows where the directory separator is not "/", 228 // but make sure you're not passing in a "\"-delimited path. 229 function getRelativeFile(relativePath) { 230 let profileDir = getProfileDir(); 231 232 let file = profileDir.clone(); 233 relativePath.split("/").forEach(function (component) { 234 file.append(component); 235 }); 236 237 return file; 238 } 239 240 function repeatChar(count, ch) { 241 if (count == 0) { 242 return ""; 243 } 244 245 let result = ch; 246 let count2 = count / 2; 247 248 // Double the input until it is long enough. 249 while (result.length <= count2) { 250 result += result; 251 } 252 253 // Use substring to hit the precise length target without using extra memory. 254 return result + result.substring(0, count - result.length); 255 } 256 257 function getPrincipal(url, attrs) { 258 let uri = Services.io.newURI(url); 259 if (!attrs) { 260 attrs = {}; 261 } 262 return Services.scriptSecurityManager.createContentPrincipal(uri, attrs); 263 } 264 265 function getCurrentPrincipal() { 266 return Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal); 267 } 268 269 function getDefaultPrincipal() { 270 return getPrincipal("http://example.com"); 271 } 272 273 function getSimpleDatabase(principal, persistence) { 274 let connection = Cc["@mozilla.org/dom/sdb-connection;1"].createInstance( 275 Ci.nsISDBConnection 276 ); 277 278 if (!principal) { 279 principal = getDefaultPrincipal(); 280 } 281 282 connection.init(principal, persistence); 283 284 return connection; 285 } 286 287 function getLocalStorage(principal) { 288 if (!principal) { 289 principal = getDefaultPrincipal(); 290 } 291 292 return Services.domStorageManager.createStorage( 293 null, 294 principal, 295 principal, 296 "" 297 ); 298 } 299 300 class RequestError extends Error { 301 constructor(resultCode, resultName) { 302 super(`Request failed (code: ${resultCode}, name: ${resultName})`); 303 this.name = "RequestError"; 304 this.resultCode = resultCode; 305 this.resultName = resultName; 306 } 307 } 308 309 async function requestFinished(request) { 310 await new Promise(function (resolve) { 311 request.callback = function () { 312 resolve(); 313 }; 314 }); 315 316 if (request.resultCode !== Cr.NS_OK) { 317 throw new RequestError(request.resultCode, request.resultName); 318 } 319 320 return request.result; 321 } 322 323 function loadSubscript(path) { 324 let file = do_get_file(path, false); 325 let uri = Services.io.newFileURI(file); 326 Services.scriptloader.loadSubScript(uri.spec); 327 } 328 329 async function readUsageFromUsageFile(usageFile) { 330 let file = await File.createFromNsIFile(usageFile); 331 332 let buffer = await new Promise(resolve => { 333 let reader = new FileReader(); 334 reader.onloadend = () => resolve(reader.result); 335 reader.readAsArrayBuffer(file); 336 }); 337 338 // Manually getting the lower 32-bits because of the lack of support for 339 // 64-bit values currently from DataView/JS (other than the BigInt support 340 // that's currently behind a flag). 341 let view = new DataView(buffer, 8, 4); 342 return view.getUint32(); 343 }