|
|
22 |
var TestUtils = {}; |
22 |
var TestUtils = {}; |
23 |
|
23 |
|
24 |
/** |
24 |
/** |
25 |
* Various storage backends that are part of the 'storage' datatype. |
25 |
* Various storage backends that are part of the 'storage' datatype. |
26 |
* @param{Array.<Datatype>} |
26 |
* @param{Array.<Datatype>} |
27 |
*/ |
27 |
*/ |
28 |
TestUtils.STORAGE = [ |
28 |
TestUtils.STORAGE = [ |
29 |
{ |
29 |
{ |
30 |
"name": "local storage", |
30 |
"name": "Cache API", |
31 |
"supported": function() { !!window.localStorage; }, |
31 |
"supported": function() { return true; }, |
32 |
"add": function() { |
32 |
"add": async function() { |
33 |
return new Promise(function(resolve, reject) { |
33 |
let FILES_TO_CACHE = [ |
34 |
localStorage.setItem(randomString(), randomString()); |
34 |
"navigation-insecure.html", |
35 |
resolve(); |
35 |
"navigation.https.html", |
36 |
}); |
36 |
"resource.html", |
37 |
}, |
37 |
"storage.https.html", |
38 |
"isEmpty": function() { |
38 |
"support/iframe_executionContexts.html", |
39 |
return new Promise(function(resolve, reject) { |
39 |
"support/page_using_service_worker.html", |
40 |
resolve(!localStorage.length); |
40 |
"support/send_report.html", |
41 |
}); |
41 |
]; |
42 |
} |
42 |
|
43 |
}, |
43 |
const REPEAT_COUNT = 100; |
44 |
{ |
44 |
REQUESTS_TO_CACHE = []; |
45 |
"name": "Indexed DB", |
45 |
for (let i = 0; i < REPEAT_COUNT; i++) { |
46 |
"supported": function() { return !!window.indexedDB; }, |
46 |
for (const filename of FILES_TO_CACHE) { |
47 |
"add": function() { |
47 |
REQUESTS_TO_CACHE.push(`${filename}?foo=${i}`); |
48 |
return new Promise(function(resolve, reject) { |
48 |
} |
49 |
var request = window.indexedDB.open("database"); |
49 |
} |
50 |
request.onupgradeneeded = function() { |
50 |
|
51 |
request.result.createObjectStore("store"); |
51 |
const cache = await caches.open("foo"); |
52 |
}; |
52 |
|
53 |
request.onsuccess = function() { |
53 |
// try sticking a thing in that will never complete; |
54 |
request.result.close(); |
54 |
/* |
55 |
resolve(); |
55 |
dump("creating stream\n"); |
|
|
56 |
const myStream = window.MY_STREAM = new ReadableStream({ |
57 |
start(controller) { |
58 |
this.controller = controller; |
59 |
controller.enqueue("foo"); |
56 |
} |
60 |
} |
57 |
}); |
61 |
}); |
|
|
62 |
dump("stream instantiated\n"); |
63 |
const myStreamResp = window.MY_RESP = new Response(myStream, { status : 200 }); |
64 |
dump("putting stream\n"); |
65 |
cache.put("/foo", myStreamResp); |
66 |
dump("stream put is running\n"); |
67 |
*/ |
68 |
|
69 |
await cache.addAll(REQUESTS_TO_CACHE); |
70 |
const pendingResponses = Promise.all(REQUESTS_TO_CACHE.map((url) => { |
71 |
return cache.match(url); |
72 |
})); |
73 |
const responses = await pendingResponses; |
74 |
let iNext = 0; |
75 |
|
76 |
const tarpit = window.STREAM_TARPIT = []; |
77 |
const kickNext = () => { |
78 |
const resp = responses[iNext++]; |
79 |
|
80 |
dump(`starting stream of ${resp.url}\n`); |
81 |
const reader = resp.body.getReader(); |
82 |
const firstDataPromise = reader.read().then(() => { |
83 |
dump(` got some data for ${resp.url}\n`); |
84 |
if (iNext < responses.length) { |
85 |
kickNext(); |
86 |
} |
87 |
}); |
88 |
tarpit.push({ reader, firstDataPromise }); |
89 |
return firstDataPromise; |
90 |
}; |
91 |
const PRE_WAIT_COUNT = 10; |
92 |
const POST_WAIT_COUNT = 10; |
93 |
let sampleAt = 4; |
94 |
let samplePromise; |
95 |
for (let z = 0; z < PRE_WAIT_COUNT; z++) { |
96 |
let prom = kickNext(); |
97 |
if (--sampleAt === 0) { |
98 |
samplePromise = prom; |
99 |
} |
100 |
} |
101 |
// wait for the pipeline to have been primed |
102 |
await samplePromise; |
103 |
dump("~~~~~DONE WAITING FOR SAMPLE\n"); |
104 |
for (let z = 0; z < POST_WAIT_COUNT; z++) { |
105 |
kickNext(); |
106 |
} |
58 |
}, |
107 |
}, |
59 |
"isEmpty": function() { |
108 |
"isEmpty": async function() { |
60 |
return new Promise(function(resolve, reject) { |
109 |
const hasCache = await caches.has("foo"); |
61 |
var request = window.indexedDB.open("database"); |
110 |
const knownCaches = await caches.keys(); |
62 |
request.onsuccess = function() { |
111 |
return !hasCache && knownCaches.length === 0; |
63 |
var database = request.result; |
|
|
64 |
try { |
65 |
var transaction = database.transaction(["store"]); |
66 |
resolve(false); |
67 |
} catch(error) { |
68 |
// The database is empty. However, by testing that, we have also |
69 |
// created it, which means that |onupgradeneeded| in the "add" |
70 |
// method will not run the next time. Delete the database before |
71 |
// reporting that it was empty. |
72 |
var deletion = window.indexedDB.deleteDatabase("database"); |
73 |
deletion.onsuccess = resolve.bind(this, true); |
74 |
} finally { |
75 |
database.close(); |
76 |
} |
77 |
}; |
78 |
}); |
79 |
} |
112 |
} |
80 |
}, |
113 |
}, |
81 |
{ |
|
|
82 |
// TODO(@msramek): We should also test the PERSISTENT filesystem, however, |
83 |
// that might require storage permissions. |
84 |
"name": "filesystems", |
85 |
"supported": function() { |
86 |
return window.requestFileSystem || window.webkitRequestFileSystem; |
87 |
}, |
88 |
"add": function() { |
89 |
return new Promise(function(resolve, reject) { |
90 |
var onSuccess = function(fileSystem) { |
91 |
fileSystem.root.getFile('file', {"create": true}, resolve, resolve); |
92 |
} |
93 |
var onFailure = resolve; |
94 |
|
95 |
var requestFileSystem = |
96 |
window.requestFileSystem || window.webkitRequestFileSystem; |
97 |
requestFileSystem(window.TEMPORARY, 1 /* 1B */, |
98 |
onSuccess, onFailure); |
99 |
}); |
100 |
}, |
101 |
"isEmpty": function() { |
102 |
return new Promise(function(resolve, reject) { |
103 |
var onSuccess = function(fileSystem) { |
104 |
fileSystem.root.getFile( |
105 |
'file', {}, |
106 |
resolve.bind(this, false) /* opened successfully */, |
107 |
resolve.bind(this, true) /* failed to open */); |
108 |
} |
109 |
var onFailure = resolve.bind(this, true); |
110 |
|
111 |
var requestFileSystem = |
112 |
window.requestFileSystem || window.webkitRequestFileSystem; |
113 |
requestFileSystem(window.TEMPORARY, 1 /* 1B */, |
114 |
onSuccess, onFailure); |
115 |
}); |
116 |
} |
117 |
}, |
118 |
{ |
119 |
"name": "service workers", |
120 |
"supported": function() { return !!navigator.serviceWorker; }, |
121 |
"add": function() { |
122 |
return navigator.serviceWorker.register( |
123 |
"support/service_worker.js", |
124 |
{ scope: "support/"}); |
125 |
}, |
126 |
"isEmpty": function() { |
127 |
return new Promise(function(resolve, reject) { |
128 |
navigator.serviceWorker.getRegistrations() |
129 |
.then(function(registrations) { |
130 |
resolve(!registrations.length); |
131 |
}); |
132 |
}); |
133 |
} |
134 |
}, |
135 |
{ |
136 |
"name": "WebSQL", |
137 |
"supported": function() { return !!window.openDatabase; }, |
138 |
"add": function() { |
139 |
return new Promise(function(resolve, reject) { |
140 |
var database = window.openDatabase( |
141 |
"database", "1.0", "database", 1024 /* 1 kB */); |
142 |
database.transaction(function(context) { |
143 |
context.executeSql("CREATE TABLE IF NOT EXISTS data (column)"); |
144 |
context.executeSql( |
145 |
"INSERT INTO data (column) VALUES (1)", [], resolve); |
146 |
}); |
147 |
}); |
148 |
}, |
149 |
"isEmpty": function() { |
150 |
return new Promise(function(resolve, reject) { |
151 |
var database = window.openDatabase( |
152 |
"database", "1.0", "database", 1024 /* 1 kB */); |
153 |
database.transaction(function(context) { |
154 |
context.executeSql("CREATE TABLE IF NOT EXISTS data (column)"); |
155 |
context.executeSql( |
156 |
"SELECT * FROM data", [], |
157 |
function(transaction, result) { |
158 |
resolve(!result.rows.length); |
159 |
}); |
160 |
}); |
161 |
}); |
162 |
} |
163 |
} |
164 |
].filter(function(backend) { return backend.supported(); }); |
114 |
].filter(function(backend) { return backend.supported(); }); |
165 |
|
115 |
|
166 |
/** |
116 |
/** |
167 |
* All datatypes supported by Clear-Site-Data. |
117 |
* All datatypes supported by Clear-Site-Data. |
168 |
* @param{Array.<Datatype>} |
118 |
* @param{Array.<Datatype>} |
169 |
*/ |
119 |
*/ |
170 |
TestUtils.DATATYPES = [ |
120 |
TestUtils.DATATYPES = [ |
171 |
{ |
121 |
{ |