Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* Any copyright is dedicated to the Public Domain.
2 http://creativecommons.org/publicdomain/zero/1.0/ */
4 // Test the various ways opening a cookie database can fail in a synchronous
5 // (i.e. immediate) manner, and that the database is renamed and recreated
6 // under each circumstance. These circumstances are, in no particular order:
7 //
8 // 1) A corrupt database, such that opening the connection fails.
9 // 2) The 'moz_cookies' table doesn't exist.
10 // 3) Not all of the expected columns exist, and statement creation fails when:
11 // a) The schema version is larger than the current version.
12 // b) The schema version is less than or equal to the current version.
13 // 4) Migration fails. This will have different modes depending on the initial
14 // version:
15 // a) Schema 1: the 'lastAccessed' column already exists.
16 // b) Schema 2: the 'baseDomain' column already exists; or 'baseDomain'
17 // cannot be computed for a particular host.
18 // c) Schema 3: the 'creationTime' column already exists; or the
19 // 'moz_uniqueid' index already exists.
21 let COOKIE_DATABASE_SCHEMA_CURRENT = 5;
23 let test_generator = do_run_test();
25 function run_test() {
26 do_test_pending();
27 do_run_generator(test_generator);
28 }
30 function finish_test() {
31 do_execute_soon(function() {
32 test_generator.close();
33 do_test_finished();
34 });
35 }
37 function do_run_test() {
38 // Set up a profile.
39 this.profile = do_get_profile();
41 // Allow all cookies.
42 Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
44 // Get the cookie file and the backup file.
45 this.cookieFile = profile.clone();
46 cookieFile.append("cookies.sqlite");
47 this.backupFile = profile.clone();
48 backupFile.append("cookies.sqlite.bak");
49 do_check_false(cookieFile.exists());
50 do_check_false(backupFile.exists());
52 // Create a cookie object for testing.
53 this.now = Date.now() * 1000;
54 this.futureExpiry = Math.round(this.now / 1e6 + 1000);
55 this.cookie = new Cookie("oh", "hai", "bar.com", "/", this.futureExpiry,
56 this.now, this.now, false, false, false);
58 this.sub_generator = run_test_1(test_generator);
59 sub_generator.next();
60 yield;
62 this.sub_generator = run_test_2(test_generator);
63 sub_generator.next();
64 yield;
66 this.sub_generator = run_test_3(test_generator, 99);
67 sub_generator.next();
68 yield;
70 this.sub_generator = run_test_3(test_generator, COOKIE_DATABASE_SCHEMA_CURRENT);
71 sub_generator.next();
72 yield;
74 this.sub_generator = run_test_3(test_generator, 4);
75 sub_generator.next();
76 yield;
78 this.sub_generator = run_test_3(test_generator, 3);
79 sub_generator.next();
80 yield;
82 this.sub_generator = run_test_4_exists(test_generator, 1,
83 "ALTER TABLE moz_cookies ADD lastAccessed INTEGER");
84 sub_generator.next();
85 yield;
87 this.sub_generator = run_test_4_exists(test_generator, 2,
88 "ALTER TABLE moz_cookies ADD baseDomain TEXT");
89 sub_generator.next();
90 yield;
92 this.sub_generator = run_test_4_baseDomain(test_generator);
93 sub_generator.next();
94 yield;
96 this.sub_generator = run_test_4_exists(test_generator, 3,
97 "ALTER TABLE moz_cookies ADD creationTime INTEGER");
98 sub_generator.next();
99 yield;
101 this.sub_generator = run_test_4_exists(test_generator, 3,
102 "CREATE UNIQUE INDEX moz_uniqueid ON moz_cookies (name, host, path)");
103 sub_generator.next();
104 yield;
106 finish_test();
107 return;
108 }
110 const garbage = "hello thar!";
112 function create_garbage_file(file)
113 {
114 // Create an empty database file.
115 file.create(Ci.nsIFile.NORMAL_FILE_TYPE, -1);
116 do_check_true(file.exists());
117 do_check_eq(file.fileSize, 0);
119 // Write some garbage to it.
120 let ostream = Cc["@mozilla.org/network/file-output-stream;1"].
121 createInstance(Ci.nsIFileOutputStream);
122 ostream.init(file, -1, -1, 0);
123 ostream.write(garbage, garbage.length);
124 ostream.flush();
125 ostream.close();
127 file = file.clone(); // Windows maintains a stat cache. It's lame.
128 do_check_eq(file.fileSize, garbage.length);
129 }
131 function check_garbage_file(file)
132 {
133 do_check_true(file.exists());
134 do_check_eq(file.fileSize, garbage.length);
135 file.remove(false);
136 do_check_false(file.exists());
137 }
139 function run_test_1(generator)
140 {
141 // Create a garbage database file.
142 create_garbage_file(cookieFile);
144 // Load the profile and populate it.
145 let uri = NetUtil.newURI("http://foo.com/");
146 Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null);
148 // Fake a profile change.
149 do_close_profile(sub_generator);
150 yield;
151 do_load_profile();
153 // Check that the new database contains the cookie, and the old file was
154 // renamed.
155 do_check_eq(do_count_cookies(), 1);
156 check_garbage_file(backupFile);
158 // Close the profile.
159 do_close_profile(sub_generator);
160 yield;
162 // Clean up.
163 cookieFile.remove(false);
164 do_check_false(cookieFile.exists());
165 do_run_generator(generator);
166 }
168 function run_test_2(generator)
169 {
170 // Load the profile and populate it.
171 do_load_profile();
172 let uri = NetUtil.newURI("http://foo.com/");
173 Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null);
175 // Fake a profile change.
176 do_close_profile(sub_generator);
177 yield;
179 // Drop the table.
180 let db = Services.storage.openDatabase(cookieFile);
181 db.executeSimpleSQL("DROP TABLE moz_cookies");
182 db.close();
184 // Load the profile and check that the table is recreated in-place.
185 do_load_profile();
186 do_check_eq(do_count_cookies(), 0);
187 do_check_false(backupFile.exists());
189 // Close the profile.
190 do_close_profile(sub_generator);
191 yield;
193 // Clean up.
194 cookieFile.remove(false);
195 do_check_false(cookieFile.exists());
196 do_run_generator(generator);
197 }
199 function run_test_3(generator, schema)
200 {
201 // Manually create a schema 2 database, populate it, and set the schema
202 // version to the desired number.
203 let schema2db = new CookieDatabaseConnection(do_get_cookie_file(profile), 2);
204 schema2db.insertCookie(cookie);
205 schema2db.db.schemaVersion = schema;
206 schema2db.close();
208 // Load the profile and check that the column existence test fails.
209 do_load_profile();
210 do_check_eq(do_count_cookies(), 0);
212 // Close the profile.
213 do_close_profile(sub_generator);
214 yield;
216 // Check that the schema version has been reset.
217 let db = Services.storage.openDatabase(cookieFile);
218 do_check_eq(db.schemaVersion, COOKIE_DATABASE_SCHEMA_CURRENT);
219 db.close();
221 // Clean up.
222 cookieFile.remove(false);
223 do_check_false(cookieFile.exists());
224 do_run_generator(generator);
225 }
227 function run_test_4_exists(generator, schema, stmt)
228 {
229 // Manually create a database, populate it, and add the desired column.
230 let db = new CookieDatabaseConnection(do_get_cookie_file(profile), schema);
231 db.insertCookie(cookie);
232 db.db.executeSimpleSQL(stmt);
233 db.close();
235 // Load the profile and check that migration fails.
236 do_load_profile();
237 do_check_eq(do_count_cookies(), 0);
239 // Close the profile.
240 do_close_profile(sub_generator);
241 yield;
243 // Check that the schema version has been reset and the backup file exists.
244 db = Services.storage.openDatabase(cookieFile);
245 do_check_eq(db.schemaVersion, COOKIE_DATABASE_SCHEMA_CURRENT);
246 db.close();
247 do_check_true(backupFile.exists());
249 // Clean up.
250 cookieFile.remove(false);
251 backupFile.remove(false);
252 do_check_false(cookieFile.exists());
253 do_check_false(backupFile.exists());
254 do_run_generator(generator);
255 }
257 function run_test_4_baseDomain(generator)
258 {
259 // Manually create a database and populate it with a bad host.
260 let db = new CookieDatabaseConnection(do_get_cookie_file(profile), 2);
261 let badCookie = new Cookie("oh", "hai", ".", "/", this.futureExpiry, this.now,
262 this.now, false, false, false);
263 db.insertCookie(badCookie);
264 db.close();
266 // Load the profile and check that migration fails.
267 do_load_profile();
268 do_check_eq(do_count_cookies(), 0);
270 // Close the profile.
271 do_close_profile(sub_generator);
272 yield;
274 // Check that the schema version has been reset and the backup file exists.
275 db = Services.storage.openDatabase(cookieFile);
276 do_check_eq(db.schemaVersion, COOKIE_DATABASE_SCHEMA_CURRENT);
277 db.close();
278 do_check_true(backupFile.exists());
280 // Clean up.
281 cookieFile.remove(false);
282 backupFile.remove(false);
283 do_check_false(cookieFile.exists());
284 do_check_false(backupFile.exists());
285 do_run_generator(generator);
286 }