Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 var testnum = 0;
6 let dbConnection; // used for deleted table tests
8 Cu.import("resource://gre/modules/Promise.jsm");
10 function countDeletedEntries(expected)
11 {
12 let deferred = Promise.defer();
13 let stmt = dbConnection.createAsyncStatement("SELECT COUNT(*) AS numEntries FROM moz_deleted_formhistory");
14 stmt.executeAsync({
15 handleResult: function(resultSet) {
16 do_check_eq(expected, resultSet.getNextRow().getResultByName("numEntries"));
17 deferred.resolve();
18 },
19 handleError : function () {
20 do_throw("Error occurred counting deleted entries: " + error);
21 deferred.reject();
22 },
23 handleCompletion : function () {
24 stmt.finalize();
25 }
26 });
27 return deferred.promise;
28 }
30 function checkTimeDeleted(guid, checkFunction)
31 {
32 let deferred = Promise.defer();
33 let stmt = dbConnection.createAsyncStatement("SELECT timeDeleted FROM moz_deleted_formhistory WHERE guid = :guid");
34 stmt.params.guid = guid;
35 stmt.executeAsync({
36 handleResult: function(resultSet) {
37 checkFunction(resultSet.getNextRow().getResultByName("timeDeleted"));
38 deferred.resolve();
39 },
40 handleError : function () {
41 do_throw("Error occurred getting deleted entries: " + error);
42 deferred.reject();
43 },
44 handleCompletion : function () {
45 stmt.finalize();
46 }
47 });
48 return deferred.promise;
49 }
51 function promiseUpdateEntry(op, name, value)
52 {
53 var change = { op: op };
54 if (name !== null)
55 change.fieldname = name;
56 if (value !== null)
57 change.value = value;
58 return promiseUpdate(change);
59 }
61 function promiseUpdate(change)
62 {
63 let deferred = Promise.defer();
64 FormHistory.update(change,
65 { handleError: function (error) {
66 do_throw("Error occurred updating form history: " + error);
67 deferred.reject(error);
68 },
69 handleCompletion: function (reason) { if (!reason) deferred.resolve(); }
70 });
71 return deferred.promise;
72 }
74 function promiseSearchEntries(terms, params)
75 {
76 let deferred = Promise.defer();
77 let results = [];
78 FormHistory.search(terms, params,
79 { handleResult: function(result) results.push(result),
80 handleError: function (error) {
81 do_throw("Error occurred searching form history: " + error);
82 deferred.reject(error);
83 },
84 handleCompletion: function (reason) { if (!reason) deferred.resolve(results); }
85 });
86 return deferred.promise;
87 }
89 function promiseCountEntries(name, value, checkFn)
90 {
91 let deferred = Promise.defer();
92 countEntries(name, value, function (result) { checkFn(result); deferred.resolve(); } );
93 return deferred.promise;
94 }
96 add_task(function ()
97 {
98 let oldSupportsDeletedTable = FormHistory._supportsDeletedTable;
99 FormHistory._supportsDeletedTable = true;
101 try {
103 // ===== test init =====
104 var testfile = do_get_file("formhistory_apitest.sqlite");
105 var profileDir = dirSvc.get("ProfD", Ci.nsIFile);
107 // Cleanup from any previous tests or failures.
108 var destFile = profileDir.clone();
109 destFile.append("formhistory.sqlite");
110 if (destFile.exists())
111 destFile.remove(false);
113 testfile.copyTo(profileDir, "formhistory.sqlite");
115 function checkExists(num) { do_check_true(num > 0); }
116 function checkNotExists(num) { do_check_true(num == 0); }
118 // ===== 1 =====
119 // Check initial state is as expected
120 testnum++;
121 yield promiseCountEntries("name-A", null, checkExists);
122 yield promiseCountEntries("name-B", null, checkExists);
123 yield promiseCountEntries("name-C", null, checkExists);
124 yield promiseCountEntries("name-D", null, checkExists);
125 yield promiseCountEntries("name-A", "value-A", checkExists);
126 yield promiseCountEntries("name-B", "value-B1", checkExists);
127 yield promiseCountEntries("name-B", "value-B2", checkExists);
128 yield promiseCountEntries("name-C", "value-C", checkExists);
129 yield promiseCountEntries("name-D", "value-D", checkExists);
130 // time-A/B/C/D checked below.
132 // Delete anything from the deleted table
133 let dbFile = Services.dirsvc.get("ProfD", Ci.nsIFile).clone();
134 dbFile.append("formhistory.sqlite");
135 dbConnection = Services.storage.openUnsharedDatabase(dbFile);
137 let deferred = Promise.defer();
139 let stmt = dbConnection.createAsyncStatement("DELETE FROM moz_deleted_formhistory");
140 stmt.executeAsync({
141 handleResult: function(resultSet) { },
142 handleError : function () {
143 do_throw("Error occurred counting deleted all entries: " + error);
144 },
145 handleCompletion : function () {
146 stmt.finalize();
147 deferred.resolve();
148 }
149 });
150 yield deferred.promise;
152 // ===== 2 =====
153 // Test looking for nonexistent / bogus data.
154 testnum++;
155 yield promiseCountEntries("blah", null, checkNotExists);
156 yield promiseCountEntries("", null, checkNotExists);
157 yield promiseCountEntries("name-A", "blah", checkNotExists);
158 yield promiseCountEntries("name-A", "", checkNotExists);
159 yield promiseCountEntries("name-A", null, checkExists);
160 yield promiseCountEntries("blah", "value-A", checkNotExists);
161 yield promiseCountEntries("", "value-A", checkNotExists);
162 yield promiseCountEntries(null, "value-A", checkExists);
164 // Cannot use promiseCountEntries when name and value are null because it treats null values as not set
165 // and here a search should be done explicity for null.
166 deferred = Promise.defer();
167 yield FormHistory.count({ fieldname: null, value: null },
168 { handleResult: function(result) checkNotExists(result),
169 handleError: function (error) {
170 do_throw("Error occurred searching form history: " + error);
171 },
172 handleCompletion: function(reason) { if (!reason) deferred.resolve() }
173 });
174 yield deferred.promise;
176 // ===== 3 =====
177 // Test removeEntriesForName with a single matching value
178 testnum++;
179 yield promiseUpdateEntry("remove", "name-A", null);
181 yield promiseCountEntries("name-A", "value-A", checkNotExists);
182 yield promiseCountEntries("name-B", "value-B1", checkExists);
183 yield promiseCountEntries("name-B", "value-B2", checkExists);
184 yield promiseCountEntries("name-C", "value-C", checkExists);
185 yield promiseCountEntries("name-D", "value-D", checkExists);
186 yield countDeletedEntries(1);
188 // ===== 4 =====
189 // Test removeEntriesForName with multiple matching values
190 testnum++;
191 yield promiseUpdateEntry("remove", "name-B", null);
193 yield promiseCountEntries("name-A", "value-A", checkNotExists);
194 yield promiseCountEntries("name-B", "value-B1", checkNotExists);
195 yield promiseCountEntries("name-B", "value-B2", checkNotExists);
196 yield promiseCountEntries("name-C", "value-C", checkExists);
197 yield promiseCountEntries("name-D", "value-D", checkExists);
198 yield countDeletedEntries(3);
200 // ===== 5 =====
201 // Test removing by time range (single entry, not surrounding entries)
202 testnum++;
203 yield promiseCountEntries("time-A", null, checkExists); // firstUsed=1000, lastUsed=1000
204 yield promiseCountEntries("time-B", null, checkExists); // firstUsed=1000, lastUsed=1099
205 yield promiseCountEntries("time-C", null, checkExists); // firstUsed=1099, lastUsed=1099
206 yield promiseCountEntries("time-D", null, checkExists); // firstUsed=2001, lastUsed=2001
207 yield promiseUpdate({ op : "remove", firstUsedStart: 1050, firstUsedEnd: 2000 });
209 yield promiseCountEntries("time-A", null, checkExists);
210 yield promiseCountEntries("time-B", null, checkExists);
211 yield promiseCountEntries("time-C", null, checkNotExists);
212 yield promiseCountEntries("time-D", null, checkExists);
213 yield countDeletedEntries(4);
215 // ===== 6 =====
216 // Test removing by time range (multiple entries)
217 testnum++;
218 yield promiseUpdate({ op : "remove", firstUsedStart: 1000, firstUsedEnd: 2000 });
220 yield promiseCountEntries("time-A", null, checkNotExists);
221 yield promiseCountEntries("time-B", null, checkNotExists);
222 yield promiseCountEntries("time-C", null, checkNotExists);
223 yield promiseCountEntries("time-D", null, checkExists);
224 yield countDeletedEntries(6);
226 // ===== 7 =====
227 // test removeAllEntries
228 testnum++;
229 yield promiseUpdateEntry("remove", null, null);
231 yield promiseCountEntries("name-C", null, checkNotExists);
232 yield promiseCountEntries("name-D", null, checkNotExists);
233 yield promiseCountEntries("name-C", "value-C", checkNotExists);
234 yield promiseCountEntries("name-D", "value-D", checkNotExists);
236 yield promiseCountEntries(null, null, checkNotExists);
237 yield countDeletedEntries(6);
239 // ===== 8 =====
240 // Add a single entry back
241 testnum++;
242 yield promiseUpdateEntry("add", "newname-A", "newvalue-A");
243 yield promiseCountEntries("newname-A", "newvalue-A", checkExists);
245 // ===== 9 =====
246 // Remove the single entry
247 testnum++;
248 yield promiseUpdateEntry("remove", "newname-A", "newvalue-A");
249 yield promiseCountEntries("newname-A", "newvalue-A", checkNotExists);
251 // ===== 10 =====
252 // Add a single entry
253 testnum++;
254 yield promiseUpdateEntry("add", "field1", "value1");
255 yield promiseCountEntries("field1", "value1", checkExists);
257 let processFirstResult = function processResults(results)
258 {
259 // Only handle the first result
260 if (results.length > 0) {
261 let result = results[0];
262 return [result.timesUsed, result.firstUsed, result.lastUsed, result.guid];
263 }
264 }
266 results = yield promiseSearchEntries(["timesUsed", "firstUsed", "lastUsed"],
267 { fieldname: "field1", value: "value1" });
268 let [timesUsed, firstUsed, lastUsed] = processFirstResult(results);
269 do_check_eq(1, timesUsed);
270 do_check_true(firstUsed > 0);
271 do_check_true(lastUsed > 0);
272 yield promiseCountEntries(null, null, function(num) do_check_eq(num, 1));
274 // ===== 11 =====
275 // Add another single entry
276 testnum++;
277 yield promiseUpdateEntry("add", "field1", "value1b");
278 yield promiseCountEntries("field1", "value1", checkExists);
279 yield promiseCountEntries("field1", "value1b", checkExists);
280 yield promiseCountEntries(null, null, function(num) do_check_eq(num, 2));
282 // ===== 12 =====
283 // Update a single entry
284 testnum++;
286 results = yield promiseSearchEntries(["guid"], { fieldname: "field1", value: "value1" });
287 let guid = processFirstResult(results)[3];
289 yield promiseUpdate({ op : "update", guid: guid, value: "modifiedValue" });
290 yield promiseCountEntries("field1", "modifiedValue", checkExists);
291 yield promiseCountEntries("field1", "value1", checkNotExists);
292 yield promiseCountEntries("field1", "value1b", checkExists);
293 yield promiseCountEntries(null, null, function(num) do_check_eq(num, 2));
295 // ===== 13 =====
296 // Add a single entry with times
297 testnum++;
298 yield promiseUpdate({ op : "add", fieldname: "field2", value: "value2",
299 timesUsed: 20, firstUsed: 100, lastUsed: 500 });
301 results = yield promiseSearchEntries(["timesUsed", "firstUsed", "lastUsed"],
302 { fieldname: "field2", value: "value2" });
303 [timesUsed, firstUsed, lastUsed] = processFirstResult(results);
305 do_check_eq(20, timesUsed);
306 do_check_eq(100, firstUsed);
307 do_check_eq(500, lastUsed);
308 yield promiseCountEntries(null, null, function(num) do_check_eq(num, 3));
310 // ===== 14 =====
311 // Bump an entry, which updates its lastUsed field
312 testnum++;
313 yield promiseUpdate({ op : "bump", fieldname: "field2", value: "value2",
314 timesUsed: 20, firstUsed: 100, lastUsed: 500 });
315 results = yield promiseSearchEntries(["timesUsed", "firstUsed", "lastUsed"],
316 { fieldname: "field2", value: "value2" });
317 [timesUsed, firstUsed, lastUsed] = processFirstResult(results);
318 do_check_eq(21, timesUsed);
319 do_check_eq(100, firstUsed);
320 do_check_true(lastUsed > 500);
321 yield promiseCountEntries(null, null, function(num) do_check_eq(num, 3));
323 // ===== 15 =====
324 // Bump an entry that does not exist
325 testnum++;
326 yield promiseUpdate({ op : "bump", fieldname: "field3", value: "value3",
327 timesUsed: 10, firstUsed: 50, lastUsed: 400 });
328 results = yield promiseSearchEntries(["timesUsed", "firstUsed", "lastUsed"],
329 { fieldname: "field3", value: "value3" });
330 [timesUsed, firstUsed, lastUsed] = processFirstResult(results);
331 do_check_eq(10, timesUsed);
332 do_check_eq(50, firstUsed);
333 do_check_eq(400, lastUsed);
334 yield promiseCountEntries(null, null, function(num) do_check_eq(num, 4));
336 // ===== 16 =====
337 // Bump an entry with a guid
338 testnum++;
339 results = yield promiseSearchEntries(["guid"], { fieldname: "field3", value: "value3" });
340 guid = processFirstResult(results)[3];
341 yield promiseUpdate({ op : "bump", guid: guid, timesUsed: 20, firstUsed: 55, lastUsed: 400 });
342 results = yield promiseSearchEntries(["timesUsed", "firstUsed", "lastUsed"],
343 { fieldname: "field3", value: "value3" });
344 [timesUsed, firstUsed, lastUsed] = processFirstResult(results);
345 do_check_eq(11, timesUsed);
346 do_check_eq(50, firstUsed);
347 do_check_true(lastUsed > 400);
348 yield promiseCountEntries(null, null, function(num) do_check_eq(num, 4));
350 // ===== 17 =====
351 // Remove an entry
352 testnum++;
353 yield countDeletedEntries(7);
355 results = yield promiseSearchEntries(["guid"], { fieldname: "field1", value: "value1b" });
356 guid = processFirstResult(results)[3];
358 yield promiseUpdate({ op : "remove", guid: guid});
359 yield promiseCountEntries("field1", "modifiedValue", checkExists);
360 yield promiseCountEntries("field1", "value1b", checkNotExists);
361 yield promiseCountEntries(null, null, function(num) do_check_eq(num, 3));
363 yield countDeletedEntries(8);
364 yield checkTimeDeleted(guid, function (timeDeleted) do_check_true(timeDeleted > 10000));
366 // ===== 18 =====
367 // Add yet another single entry
368 testnum++;
369 yield promiseUpdate({ op : "add", fieldname: "field4", value: "value4",
370 timesUsed: 5, firstUsed: 230, lastUsed: 600 });
371 yield promiseCountEntries(null, null, function(num) do_check_eq(num, 4));
373 // ===== 19 =====
374 // Remove an entry by time
375 testnum++;
376 yield promiseUpdate({ op : "remove", firstUsedStart: 60, firstUsedEnd: 250 });
377 yield promiseCountEntries("field1", "modifiedValue", checkExists);
378 yield promiseCountEntries("field2", "value2", checkNotExists);
379 yield promiseCountEntries("field3", "value3", checkExists);
380 yield promiseCountEntries("field4", "value4", checkNotExists);
381 yield promiseCountEntries(null, null, function(num) do_check_eq(num, 2));
382 yield countDeletedEntries(10);
384 // ===== 20 =====
385 // Bump multiple existing entries at once
386 testnum++;
388 yield promiseUpdate([{ op : "add", fieldname: "field5", value: "value5",
389 timesUsed: 5, firstUsed: 230, lastUsed: 600 },
390 { op : "add", fieldname: "field6", value: "value6",
391 timesUsed: 12, firstUsed: 430, lastUsed: 700 }]);
392 yield promiseCountEntries(null, null, function(num) do_check_eq(num, 4));
394 yield promiseUpdate([
395 { op : "bump", fieldname: "field5", value: "value5" },
396 { op : "bump", fieldname: "field6", value: "value6" }]);
397 results = yield promiseSearchEntries(["fieldname", "timesUsed", "firstUsed", "lastUsed"], { });
399 do_check_eq(6, results[2].timesUsed);
400 do_check_eq(13, results[3].timesUsed);
401 do_check_eq(230, results[2].firstUsed);
402 do_check_eq(430, results[3].firstUsed);
403 do_check_true(results[2].lastUsed > 600);
404 do_check_true(results[3].lastUsed > 700);
406 yield promiseCountEntries(null, null, function(num) do_check_eq(num, 4));
408 } catch (e) {
409 throw "FAILED in test #" + testnum + " -- " + e;
410 }
411 finally {
412 FormHistory._supportsDeletedTable = oldSupportsDeletedTable;
413 dbConnection.asyncClose(do_test_finished);
414 }
415 });
417 function run_test() run_next_test();