Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: test/filterStorage_readwrite.js

Issue 29356024: Issue 4223 - Adapt filter storage read/write tests to work in adblockpluscore repository (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore
Patch Set: Simplified loadFilters/saveFilters helpers a bit further Created Oct. 6, 2016, 7:36 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « README.md ('k') | test/stub-modules/io.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 (function() 1 /*
2 { 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 module("Filter storage read/write", { 3 * Copyright (C) 2006-2016 Eyeo GmbH
4 setup: function() 4 *
5 { 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 prepareFilterComponents.call(this); 6 * it under the terms of the GNU General Public License version 3 as
7 preparePrefs.call(this); 7 * published by the Free Software Foundation.
8 8 *
9 FilterStorage.addSubscription(Subscription.fromURL("~fl~")); 9 * Adblock Plus is distributed in the hope that it will be useful,
10 }, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 teardown: function() 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 { 12 * GNU General Public License for more details.
13 restoreFilterComponents.call(this); 13 *
14 restorePrefs.call(this); 14 * You should have received a copy of the GNU General Public License
15 } 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 "use strict";
19
20 let {createSandbox, unexpectedError} = require("./_common");
21
22 let Filter = null;
23 let FilterNotifier = null;
24 let FilterStorage = null;
25 let IO = null;
26 let Prefs = null;
27 let Subscription = null;
28 let ExternalSubscription = null;
29
30 exports.setUp = function(callback)
31 {
32 let sandboxedRequire = createSandbox();
33 (
34 {Filter} = sandboxedRequire("../lib/filterClasses"),
35 {FilterNotifier} = sandboxedRequire("../lib/filterNotifier"),
36 {FilterStorage} = sandboxedRequire("../lib/filterStorage"),
37 {IO} = sandboxedRequire("./stub-modules/io"),
38 {Prefs} = sandboxedRequire("./stub-modules/prefs"),
39 {Subscription, ExternalSubscription} = sandboxedRequire("../lib/subscription Classes")
40 );
41
42 FilterStorage.addSubscription(Subscription.fromURL("~fl~"));
43 callback();
44 }
45
46 let testData = new Promise((resolve, reject) =>
47 {
48 let fs = require("fs");
49 let path = require("path");
50 let datapath = path.resolve(__dirname, "data", "patterns.ini");
51
52 fs.readFile(datapath, "utf-8", (error, data) =>
53 {
54 if (error)
55 reject(error);
56 else
57 resolve(data);
16 }); 58 });
17 59 });
18 let {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", null); 60
19 let {NetUtil} = Cu.import("resource://gre/modules/NetUtil.jsm", null); 61 function loadFilters(file)
20 62 {
21 function loadFilters(file, callback) 63 FilterStorage.loadFromDisk(file);
22 { 64 return FilterNotifier.once("load");
23 let listener = function(action) 65 }
24 { 66
25 if (action == "load") 67 function saveFilters(file)
68 {
69 FilterStorage.saveToDisk(file);
70 return FilterNotifier.once("save");
71 }
72
73 function testReadWrite(test, withExternal)
74 {
75 let tempFile = IO.resolveFilePath("temp_patterns1.ini");
76 let tempFile2 = IO.resolveFilePath("temp_patterns2.ini");
77
78 function canonize(data)
79 {
80 let curSection = null;
81 let sections = [];
82 for (let line of (data + "\n[end]").split(/[\r\n]+/))
83 {
84 if (/^\[.*\]$/.test(line))
26 { 85 {
27 FilterNotifier.removeListener(listener); 86 if (curSection)
28 callback(); 87 sections.push(curSection);
88
89 curSection = {header: line, data: []};
29 } 90 }
30 }; 91 else if (curSection && /\S/.test(line))
31 FilterNotifier.addListener(listener); 92 curSection.data.push(line);
32 93 }
33 FilterStorage.loadFromDisk(file); 94 for (let section of sections)
95 {
96 section.key = section.header + " " + section.data[0];
97 section.data.sort();
98 }
99 sections.sort(function(a, b)
100 {
101 if (a.key < b.key)
102 return -1;
103 else if (a.key > b.key)
104 return 1;
105 else
106 return 0;
107 });
108 return sections.map(function(section) {
109 return [section.header].concat(section.data).join("\n");
110 }).join("\n");
34 } 111 }
35 112
36 function writeToFile(file, data) 113 return testData.then(data =>
37 { 114 {
38 let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createIns tance(Ci.nsIScriptableUnicodeConverter); 115 tempFile.contents = data;
39 converter.charset = "utf-8"; 116 return loadFilters(tempFile);
40 data = converter.ConvertFromUnicode(data); 117 }).then(() =>
41 118 {
42 let stream = FileUtils.openFileOutputStream(file); 119 test.equal(FilterStorage.fileProperties.version, FilterStorage.formatVersion , "File format version");
43 stream.write(data, data.length); 120
44 stream.close(); 121 if (withExternal)
45 } 122 {
46 123 let subscription = new ExternalSubscription("~external~external subscripti on ID", "External subscription");
47 function saveFilters(file, callback) 124 subscription.filters = [Filter.fromText("foo"), Filter.fromText("bar")];
48 { 125 FilterStorage.addSubscription(subscription);
49 let listener = function(action) 126
50 { 127 let externalSubscriptions = FilterStorage.subscriptions.filter(subscriptio n => subscription instanceof ExternalSubscription);
51 if (action == "save") 128 test.equal(externalSubscriptions.length, 1, "Number of external subscripti ons after updateExternalSubscription");
52 { 129
53 FilterNotifier.removeListener(listener); 130 test.equal(externalSubscriptions[0].url, "~external~external subscription ID", "ID of external subscription");
54 callback(); 131 test.equal(externalSubscriptions[0].filters.length, 2, "Number of filters in external subscription");
55 } 132 }
56 }; 133
57 FilterNotifier.addListener(listener); 134 return saveFilters(tempFile2);
58 135 }).then(() => testData).then(expected =>
59 FilterStorage.saveToDisk(file); 136 {
60 } 137 test.equal(canonize(tempFile2.contents), canonize(expected), "Read/write res ult");
61 138 }).catch(unexpectedError.bind(test)).then(() => test.done());
62 function testReadWrite(withExternal) 139 }
63 { 140
64 let tempFile = FileUtils.getFile("TmpD", ["temp_patterns1.ini"]); 141 exports.testReadAndSaveToFile = function(test)
65 let tempFile2 = FileUtils.getFile("TmpD", ["temp_patterns2.ini"]); 142 {
66 tempFile.createUnique(tempFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); 143 testReadWrite(test, false);
67 createTempFile(); 144 };
68 145
69 function canonize(data) 146 exports.testReadAndSaveToFileWithExternalSubscription = function(test)
70 { 147 {
71 let curSection = null; 148 testReadWrite(test, true);
72 let sections = []; 149 };
73 for (let line of (data + "\n[end]").split(/[\r\n]+/)) 150
74 { 151 exports.testLegacyGroups = {};
75 if (/^\[.*\]$/.test(line)) 152
76 { 153 for (let url of ["~wl~", "~fl~", "~eh~"])
77 if (curSection) 154 {
78 sections.push(curSection); 155 exports.testLegacyGroups["read empty " + url] = function(test)
79 156 {
80 curSection = {header: line, data: []}; 157 let data = "[Subscription]\nurl=" + url;
81 } 158 let tempFile = IO.resolveFilePath("temp_patterns1.ini");
82 else if (curSection && /\S/.test(line)) 159 tempFile.contents = data;
83 curSection.data.push(line);
84 }
85 for (let section of sections)
86 {
87 section.key = section.header + " " + section.data[0];
88 section.data.sort();
89 }
90 sections.sort(function(a, b)
91 {
92 if (a.key < b.key)
93 return -1;
94 else if (a.key > b.key)
95 return 1;
96 else
97 return 0;
98 });
99 return sections.map(function(section) {
100 return [section.header].concat(section.data).join("\n");
101 }).join("\n");
102 }
103
104 function createTempFile()
105 {
106 let request = new XMLHttpRequest();
107 request.open("GET", "data/patterns.ini");
108 request.overrideMimeType("text/plain; charset=utf-8");
109 request.addEventListener("load", function()
110 {
111 writeToFile(tempFile, request.responseText);
112 loadFilters(tempFile, saveFile);
113 }, false);
114 request.send(null);
115 }
116
117 function saveFile()
118 {
119 equal(FilterStorage.fileProperties.version, FilterStorage.formatVersion, " File format version");
120
121 if (withExternal)
122 {
123 let {AdblockPlus} = Cu.import(Cc["@adblockplus.org/abp/public;1"].getSer vice(Ci.nsIURI).spec, null);
124 AdblockPlus.updateExternalSubscription("~external~external subscription ID", "External subscription", ["foo", "bar"]);
125
126 let externalSubscriptions = FilterStorage.subscriptions.filter(function (subscription) subscription instanceof ExternalSubscription);
127 equal(externalSubscriptions.length, 1, "Number of external subscriptions after updateExternalSubscription");
128
129 if (externalSubscriptions.length == 1)
130 {
131 equal(externalSubscriptions[0].url, "~external~external subscription I D", "ID of external subscription");
132 equal(externalSubscriptions[0].filters.length, 2, "Number of filters i n external subscription");
133 }
134 }
135
136 saveFilters(tempFile2, compareFile);
137 }
138
139 function compareFile()
140 {
141 let stream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance (Ci.nsIFileInputStream);
142 stream.init(tempFile2, FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, Ci.nsI FileInputStream.DEFER_OPEN);
143
144 NetUtil.asyncFetch(stream, function(inputStream, nsresult)
145 {
146 let result = NetUtil.readInputStreamToString(inputStream, inputStream.av ailable(), {charset: "utf-8"});
147
148 let request = new XMLHttpRequest();
149 request.open("GET", "data/patterns.ini");
150 request.overrideMimeType("text/plain");
151 request.addEventListener("load", function()
152 {
153 let expected = request.responseText;
154 equal(canonize(result), canonize(expected), "Read/write result");
155
156 tempFile.remove(false);
157 tempFile2.remove(false);
158 start();
159 }, false);
160 request.send(null);
161 });
162 }
163 }
164
165 asyncTest("Read and save to file", testReadWrite.bind(false));
166 asyncTest("Read, add external subscription and save to file", testReadWrite.bi nd(true));
167
168 let groupTests = [
169 ["~wl~", "whitelist"],
170 ["~fl~", "blocking"],
171 ["~eh~", "elemhide"]
172 ];
173 for (let i = 0; i < groupTests.length; i++)
174 {
175 let [url, defaults] = groupTests[i];
176 asyncTest("Read empty legacy user-defined group (" + url + ")", function()
177 {
178 let data = "[Subscription]\nurl=" + url;
179 let tempFile = FileUtils.getFile("TmpD", ["temp_patterns1.ini"]);
180 writeToFile(tempFile, data);
181
182 loadFilters(tempFile, function()
183 {
184 tempFile.remove(false);
185 equal(FilterStorage.subscriptions.length, 0, "Number of filter subscript ions");
186 start();
187 });
188 });
189 asyncTest("Read non-empty legacy user-defined group (" + url + ")", function ()
190 {
191 let data = "[Subscription]\nurl=" + url + "\n[Subscription filters]\nfoo";
192 let tempFile = FileUtils.getFile("TmpD", ["temp_patterns1.ini"]);
193 writeToFile(tempFile, data);
194
195 loadFilters(tempFile, function()
196 {
197 tempFile.remove(false);
198 equal(FilterStorage.subscriptions.length, 1, "Number of filter subscript ions");
199 if (FilterStorage.subscriptions.length == 1)
200 {
201 let subscription = FilterStorage.subscriptions[0];
202 equal(subscription.url, url, "Subscription ID");
203 equal(subscription.title, Utils.getString(defaults + "Group_title"), " Subscription title");
204 deepEqual(subscription.defaults, [defaults], "Default types");
205 equal(subscription.filters.length, 1, "Number of subscription filters" );
206 if (subscription.filters.length == 1)
207 equal(subscription.filters[0].text, "foo", "First filter");
208 }
209 start();
210 });
211 });
212 }
213
214 asyncTest("Read legacy user-defined filters", function()
215 {
216 let data = "[Subscription]\nurl=~user~1234\ntitle=Foo\n[Subscription filters ]\n[User patterns]\nfoo\n\\[bar]\nfoo#bar";
217 let tempFile = FileUtils.getFile("TmpD", ["temp_patterns1.ini"]);
218 writeToFile(tempFile, data);
219 160
220 loadFilters(tempFile, function() 161 loadFilters(tempFile, function()
221 { 162 {
222 tempFile.remove(false); 163 test.equal(FilterStorage.subscriptions.length, 0, "Number of filter subscr iptions");
223 equal(FilterStorage.subscriptions.length, 1, "Number of filter subscriptio ns"); 164 }).catch(unexpectedError.bind(test)).then(() => test.done());
165 };
166
167 exports.testLegacyGroups["read non-empty " + url] = function(test)
168 {
169 let data = "[Subscription]\nurl=" + url + "\n[Subscription filters]\nfoo";
170 let tempFile = IO.resolveFilePath("temp_patterns1.ini");
171 tempFile.contents = data;
172
173 loadFilters(tempFile).then(() =>
174 {
175 test.equal(FilterStorage.subscriptions.length, 1, "Number of filter subscr iptions");
224 if (FilterStorage.subscriptions.length == 1) 176 if (FilterStorage.subscriptions.length == 1)
225 { 177 {
226 let subscription = FilterStorage.subscriptions[0]; 178 let subscription = FilterStorage.subscriptions[0];
227 equal(subscription.filters.length, 3, "Number of subscription filters"); 179 test.equal(subscription.url, url, "Subscription ID");
228 if (subscription.filters.length == 3) 180 test.equal(subscription.title, null, "Subscription title");
229 { 181 test.deepEqual(subscription.defaults, null, "Default types");
230 equal(subscription.filters[0].text, "foo", "First filter"); 182 test.equal(subscription.filters.length, 1, "Number of subscription filte rs");
231 equal(subscription.filters[1].text, "[bar]", "Second filter"); 183 if (subscription.filters.length == 1)
232 equal(subscription.filters[2].text, "foo#bar", "Third filter"); 184 test.equal(subscription.filters[0].text, "foo", "First filter");
233 }
234 } 185 }
235 start(); 186 }).catch(unexpectedError.bind(test)).then(() => test.done());
236 }); 187 };
237 }); 188 }
238 189
239 asyncTest("Saving without backups", function() 190 exports.testReadLegacyFilters = function(test)
240 { 191 {
241 Prefs.patternsbackups = 0; 192 let data = "[Subscription]\nurl=~user~1234\ntitle=Foo\n[Subscription filters]\ n[User patterns]\nfoo\n\\[bar]\nfoo#bar";
242 Prefs.patternsbackupinterval = 24; 193 let tempFile = IO.resolveFilePath("temp_patterns1.ini");
243 194 tempFile.contents = data;
244 let tempFile = FileUtils.getFile("TmpD", ["temp_patterns.ini"]); 195
245 tempFile.createUnique(tempFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); 196 loadFilters(tempFile).then(() =>
246 FilterStorage.__defineGetter__("sourceFile", () => tempFile.clone()); 197 {
247 198 test.equal(FilterStorage.subscriptions.length, 1, "Number of filter subscrip tions");
248 saveFilters(null, function() 199 if (FilterStorage.subscriptions.length == 1)
249 { 200 {
250 saveFilters(null, function() 201 let subscription = FilterStorage.subscriptions[0];
202 test.equal(subscription.filters.length, 3, "Number of subscription filters ");
203 if (subscription.filters.length == 3)
251 { 204 {
252 let backupFile = tempFile.clone(); 205 test.equal(subscription.filters[0].text, "foo", "First filter");
253 backupFile.leafName = backupFile.leafName.replace(/\.ini$/, "-backup1.in i"); 206 test.equal(subscription.filters[1].text, "[bar]", "Second filter");
254 ok(!backupFile.exists(), "Backup shouldn't be created"); 207 test.equal(subscription.filters[2].text, "foo#bar", "Third filter");
255 start(); 208 }
256 }); 209 }
257 }); 210 }).catch(unexpectedError.bind(test)).then(() => test.done());
258 }); 211 };
259 212
260 asyncTest("Saving with backups", function() 213 exports.testSavingWithoutBackups = function(test)
261 { 214 {
262 Prefs.patternsbackups = 2; 215 Prefs.patternsbackups = 0;
263 Prefs.patternsbackupinterval = 24; 216 Prefs.patternsbackupinterval = 24;
264 217
265 let tempFile = FileUtils.getFile("TmpD", ["temp_patterns.ini"]); 218 let tempFile = IO.resolveFilePath("temp_patterns.ini");
266 tempFile.createUnique(tempFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); 219 Object.defineProperty(FilterStorage, "sourceFile", {get: () => tempFile.clone( )});
267 FilterStorage.__defineGetter__("sourceFile", () => tempFile.clone()); 220
268 221 saveFilters(null).then(() =>
222 {
223 return saveFilters(null);
224 }).then(() =>
225 {
269 let backupFile = tempFile.clone(); 226 let backupFile = tempFile.clone();
270 backupFile.leafName = backupFile.leafName.replace(/\.ini$/, "-backup1.ini"); 227 backupFile.leafName = backupFile.leafName.replace(/\.ini$/, "-backup1.ini");
271 228 test.ok(!backupFile.exists(), "Backup shouldn't be created");
272 let backupFile2 = tempFile.clone(); 229 }).catch(unexpectedError.bind(test)).then(() => test.done());
273 backupFile2.leafName = backupFile2.leafName.replace(/\.ini$/, "-backup2.ini" ); 230 };
274 231
275 let backupFile3 = tempFile.clone(); 232 exports.testSavingWithBackups = function(test)
276 backupFile3.leafName = backupFile3.leafName.replace(/\.ini$/, "-backup3.ini" ); 233 {
277 234 Prefs.patternsbackups = 2;
278 let oldModifiedTime; 235 Prefs.patternsbackupinterval = 24;
279 236
280 saveFilters(null, callback1); 237 let tempFile = IO.resolveFilePath("temp_patterns.ini");
281 238 Object.defineProperty(FilterStorage, "sourceFile", {get: () => tempFile.clone( )});
282 function callback1() 239
283 { 240 let backupFile = tempFile.clone();
284 // Save again immediately 241 backupFile.leafName = backupFile.leafName.replace(/\.ini$/, "-backup1.ini");
285 saveFilters(null, callback2); 242
286 } 243 let backupFile2 = tempFile.clone();
287 244 backupFile2.leafName = backupFile2.leafName.replace(/\.ini$/, "-backup2.ini");
288 function callback2() 245
289 { 246 let backupFile3 = tempFile.clone();
290 backupFile = backupFile.clone(); // File parameters are cached, clone to prevent this 247 backupFile3.leafName = backupFile3.leafName.replace(/\.ini$/, "-backup3.ini");
291 ok(backupFile.exists(), "First backup created"); 248
292 249 let oldModifiedTime;
293 backupFile.lastModifiedTime -= 10000; 250
294 oldModifiedTime = backupFile.lastModifiedTime; 251 saveFilters(null).then(() =>
295 saveFilters(null, callback3); 252 {
296 } 253 // Save again immediately
297 254 return saveFilters(null);
298 function callback3() 255 }).then(() =>
299 { 256 {
300 backupFile = backupFile.clone(); // File parameters are cached, clone to prevent this 257 test.ok(backupFile.exists(), "First backup created");
301 equal(backupFile.lastModifiedTime, oldModifiedTime, "Backup not overwritte n if it is only 10 seconds old"); 258
302 259 backupFile.lastModifiedTime -= 10000;
303 backupFile.lastModifiedTime -= 40*60*60*1000; 260 oldModifiedTime = backupFile.lastModifiedTime;
304 oldModifiedTime = backupFile.lastModifiedTime; 261 return saveFilters(null);
305 saveFilters(null, callback4); 262 }).then(() =>
306 } 263 {
307 264 test.equal(backupFile.lastModifiedTime, oldModifiedTime, "Backup not overwri tten if it is only 10 seconds old");
308 function callback4() 265
309 { 266 backupFile.lastModifiedTime -= 40*60*60*1000;
310 backupFile = backupFile.clone(); // File parameters are cached, clone to prevent this 267 oldModifiedTime = backupFile.lastModifiedTime;
311 notEqual(backupFile.lastModifiedTime, oldModifiedTime, "Backup overwritten if it is 40 hours old"); 268 return saveFilters(null);
312 269 }).then(() =>
313 backupFile2 = backupFile2.clone(); // File parameters are cached, clone t o prevent this 270 {
314 ok(backupFile2.exists(), "Second backup created when first backup is overw ritten"); 271 test.notEqual(backupFile.lastModifiedTime, oldModifiedTime, "Backup overwrit ten if it is 40 hours old");
315 272
316 backupFile.lastModifiedTime -= 20000; 273 test.ok(backupFile2.exists(), "Second backup created when first backup is ov erwritten");
317 oldModifiedTime = backupFile2.lastModifiedTime; 274
318 saveFilters(null, callback5); 275 backupFile.lastModifiedTime -= 20000;
319 } 276 oldModifiedTime = backupFile2.lastModifiedTime;
320 277 return saveFilters(null);
321 function callback5() 278 }).then(() =>
322 { 279 {
323 backupFile2 = backupFile2.clone(); // File parameters are cached, clone t o prevent this 280 test.equal(backupFile2.lastModifiedTime, oldModifiedTime, "Second backup not overwritten if first one is only 20 seconds old");
324 equal(backupFile2.lastModifiedTime, oldModifiedTime, "Second backup not ov erwritten if first one is only 20 seconds old"); 281
325 282 backupFile.lastModifiedTime -= 25*60*60*1000;
326 backupFile.lastModifiedTime -= 25*60*60*1000; 283 oldModifiedTime = backupFile2.lastModifiedTime;
327 oldModifiedTime = backupFile2.lastModifiedTime; 284 return saveFilters(null);
328 saveFilters(null, callback6); 285 }).then(() =>
329 } 286 {
330 287 test.notEqual(backupFile2.lastModifiedTime, oldModifiedTime, "Second backup overwritten if first one is 25 hours old");
331 function callback6() 288
332 { 289 test.ok(!backupFile3.exists(), "Third backup not created with patternsbackup s = 2");
333 backupFile2 = backupFile2.clone(); // File parameters are cached, clone t o prevent this 290 }).catch(unexpectedError.bind(test)).then(() => test.done());
334 notEqual(backupFile2.lastModifiedTime, oldModifiedTime, "Second backup ove rwritten if first one is 25 hours old"); 291 };
335
336 ok(!backupFile3.exists(), "Third backup not created with patternsbackups = 2");
337
338 try
339 {
340 tempFile.remove(false);
341 } catch (e) {}
342 try
343 {
344 backupFile.remove(false);
345 } catch (e) {}
346 try
347 {
348 backupFile2.remove(false);
349 } catch (e) {}
350 try
351 {
352 backupFile3.remove(false);
353 } catch (e) {}
354
355 start();
356 }
357 });
358 })();
OLDNEW
« no previous file with comments | « README.md ('k') | test/stub-modules/io.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld