OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/file_util.h" | |
6 #include "base/files/file.h" | |
7 #include "base/files/file_path.h" | |
8 #include "base/files/scoped_temp_dir.h" | |
9 #include "base/memory/scoped_ptr.h" | |
10 #include "base/message_loop/message_loop.h" | |
11 #include "base/message_loop/message_loop_proxy.h" | |
12 #include "base/strings/utf_string_conversions.h" | |
13 #include "base/time/time.h" | |
14 #include "net/base/net_errors.h" | |
15 #include "net/base/test_completion_callback.h" | |
16 #include "testing/gtest/include/gtest/gtest.h" | |
17 #include "third_party/sqlite/sqlite3.h" | |
18 #include "webkit/browser/database/database_tracker.h" | |
19 #include "webkit/browser/quota/mock_special_storage_policy.h" | |
20 #include "webkit/browser/quota/quota_manager_proxy.h" | |
21 #include "webkit/common/database/database_identifier.h" | |
22 | |
23 using base::ASCIIToUTF16; | |
24 | |
25 namespace { | |
26 | |
27 const char kOrigin1Url[] = "http://origin1"; | |
28 const char kOrigin2Url[] = "http://protected_origin2"; | |
29 | |
30 class TestObserver : public webkit_database::DatabaseTracker::Observer { | |
31 public: | |
32 TestObserver() | |
33 : new_notification_received_(false), | |
34 observe_size_changes_(true), | |
35 observe_scheduled_deletions_(true) { | |
36 } | |
37 TestObserver(bool observe_size_changes, bool observe_scheduled_deletions) | |
38 : new_notification_received_(false), | |
39 observe_size_changes_(observe_size_changes), | |
40 observe_scheduled_deletions_(observe_scheduled_deletions) { | |
41 } | |
42 | |
43 virtual ~TestObserver() {} | |
44 virtual void OnDatabaseSizeChanged(const std::string& origin_identifier, | |
45 const base::string16& database_name, | |
46 int64 database_size) OVERRIDE { | |
47 if (!observe_size_changes_) | |
48 return; | |
49 new_notification_received_ = true; | |
50 origin_identifier_ = origin_identifier; | |
51 database_name_ = database_name; | |
52 database_size_ = database_size; | |
53 } | |
54 virtual void OnDatabaseScheduledForDeletion( | |
55 const std::string& origin_identifier, | |
56 const base::string16& database_name) OVERRIDE { | |
57 if (!observe_scheduled_deletions_) | |
58 return; | |
59 new_notification_received_ = true; | |
60 origin_identifier_ = origin_identifier; | |
61 database_name_ = database_name; | |
62 } | |
63 bool DidReceiveNewNotification() { | |
64 bool temp_new_notification_received = new_notification_received_; | |
65 new_notification_received_ = false; | |
66 return temp_new_notification_received; | |
67 } | |
68 std::string GetNotificationOriginIdentifier() { | |
69 return origin_identifier_; | |
70 } | |
71 base::string16 GetNotificationDatabaseName() { return database_name_; } | |
72 int64 GetNotificationDatabaseSize() { return database_size_; } | |
73 | |
74 private: | |
75 bool new_notification_received_; | |
76 bool observe_size_changes_; | |
77 bool observe_scheduled_deletions_; | |
78 std::string origin_identifier_; | |
79 base::string16 database_name_; | |
80 int64 database_size_; | |
81 }; | |
82 | |
83 void CheckNotificationReceived(TestObserver* observer, | |
84 const std::string& expected_origin_identifier, | |
85 const base::string16& expected_database_name, | |
86 int64 expected_database_size) { | |
87 EXPECT_TRUE(observer->DidReceiveNewNotification()); | |
88 EXPECT_EQ(expected_origin_identifier, | |
89 observer->GetNotificationOriginIdentifier()); | |
90 EXPECT_EQ(expected_database_name, | |
91 observer->GetNotificationDatabaseName()); | |
92 EXPECT_EQ(expected_database_size, | |
93 observer->GetNotificationDatabaseSize()); | |
94 } | |
95 | |
96 class TestQuotaManagerProxy : public quota::QuotaManagerProxy { | |
97 public: | |
98 TestQuotaManagerProxy() | |
99 : QuotaManagerProxy(NULL, NULL), | |
100 registered_client_(NULL) { | |
101 } | |
102 | |
103 virtual void RegisterClient(quota::QuotaClient* client) OVERRIDE { | |
104 EXPECT_FALSE(registered_client_); | |
105 registered_client_ = client; | |
106 } | |
107 | |
108 virtual void NotifyStorageAccessed(quota::QuotaClient::ID client_id, | |
109 const GURL& origin, | |
110 quota::StorageType type) OVERRIDE { | |
111 EXPECT_EQ(quota::QuotaClient::kDatabase, client_id); | |
112 EXPECT_EQ(quota::kStorageTypeTemporary, type); | |
113 accesses_[origin] += 1; | |
114 } | |
115 | |
116 virtual void NotifyStorageModified(quota::QuotaClient::ID client_id, | |
117 const GURL& origin, | |
118 quota::StorageType type, | |
119 int64 delta) OVERRIDE { | |
120 EXPECT_EQ(quota::QuotaClient::kDatabase, client_id); | |
121 EXPECT_EQ(quota::kStorageTypeTemporary, type); | |
122 modifications_[origin].first += 1; | |
123 modifications_[origin].second += delta; | |
124 } | |
125 | |
126 // Not needed for our tests. | |
127 virtual void NotifyOriginInUse(const GURL& origin) OVERRIDE {} | |
128 virtual void NotifyOriginNoLongerInUse(const GURL& origin) OVERRIDE {} | |
129 virtual void SetUsageCacheEnabled(quota::QuotaClient::ID client_id, | |
130 const GURL& origin, | |
131 quota::StorageType type, | |
132 bool enabled) OVERRIDE {} | |
133 virtual void GetUsageAndQuota( | |
134 base::SequencedTaskRunner* original_task_runner, | |
135 const GURL& origin, | |
136 quota::StorageType type, | |
137 const GetUsageAndQuotaCallback& callback) OVERRIDE {} | |
138 | |
139 void SimulateQuotaManagerDestroyed() { | |
140 if (registered_client_) { | |
141 registered_client_->OnQuotaManagerDestroyed(); | |
142 registered_client_ = NULL; | |
143 } | |
144 } | |
145 | |
146 bool WasAccessNotified(const GURL& origin) { | |
147 return accesses_[origin] != 0; | |
148 } | |
149 | |
150 bool WasModificationNotified(const GURL& origin, int64 amount) { | |
151 return modifications_[origin].first != 0 && | |
152 modifications_[origin].second == amount; | |
153 } | |
154 | |
155 void reset() { | |
156 accesses_.clear(); | |
157 modifications_.clear(); | |
158 } | |
159 | |
160 quota::QuotaClient* registered_client_; | |
161 | |
162 // Map from origin to count of access notifications. | |
163 std::map<GURL, int> accesses_; | |
164 | |
165 // Map from origin to <count, sum of deltas> | |
166 std::map<GURL, std::pair<int, int64> > modifications_; | |
167 | |
168 protected: | |
169 virtual ~TestQuotaManagerProxy() { | |
170 EXPECT_FALSE(registered_client_); | |
171 } | |
172 }; | |
173 | |
174 | |
175 bool EnsureFileOfSize(const base::FilePath& file_path, int64 length) { | |
176 base::File file(file_path, | |
177 base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_WRITE); | |
178 if (!file.IsValid()) | |
179 return false; | |
180 return file.SetLength(length); | |
181 } | |
182 | |
183 } // namespace | |
184 | |
185 namespace webkit_database { | |
186 | |
187 // We declare a helper class, and make it a friend of DatabaseTracker using | |
188 // the FRIEND_TEST() macro, and we implement all tests we want to run as | |
189 // static methods of this class. Then we make our TEST() targets call these | |
190 // static functions. This allows us to run each test in normal mode and | |
191 // incognito mode without writing the same code twice. | |
192 class DatabaseTracker_TestHelper_Test { | |
193 public: | |
194 static void TestDeleteOpenDatabase(bool incognito_mode) { | |
195 // Initialize the tracker database. | |
196 base::ScopedTempDir temp_dir; | |
197 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
198 scoped_refptr<quota::MockSpecialStoragePolicy> special_storage_policy = | |
199 new quota::MockSpecialStoragePolicy; | |
200 special_storage_policy->AddProtected(GURL(kOrigin2Url)); | |
201 scoped_refptr<DatabaseTracker> tracker( | |
202 new DatabaseTracker(temp_dir.path(), | |
203 incognito_mode, | |
204 special_storage_policy.get(), | |
205 NULL, | |
206 NULL)); | |
207 | |
208 // Create and open three databases. | |
209 int64 database_size = 0; | |
210 const std::string kOrigin1 = | |
211 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin1Url)); | |
212 const std::string kOrigin2 = | |
213 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin2Url)); | |
214 const base::string16 kDB1 = ASCIIToUTF16("db1"); | |
215 const base::string16 kDB2 = ASCIIToUTF16("db2"); | |
216 const base::string16 kDB3 = ASCIIToUTF16("db3"); | |
217 const base::string16 kDescription = ASCIIToUTF16("database_description"); | |
218 | |
219 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0, | |
220 &database_size); | |
221 tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0, | |
222 &database_size); | |
223 tracker->DatabaseOpened(kOrigin2, kDB3, kDescription, 0, | |
224 &database_size); | |
225 | |
226 EXPECT_TRUE(base::CreateDirectory( | |
227 tracker->DatabaseDirectory().Append(base::FilePath::FromUTF16Unsafe( | |
228 tracker->GetOriginDirectory(kOrigin1))))); | |
229 EXPECT_TRUE(base::CreateDirectory( | |
230 tracker->DatabaseDirectory().Append(base::FilePath::FromUTF16Unsafe( | |
231 tracker->GetOriginDirectory(kOrigin2))))); | |
232 EXPECT_EQ(1, base::WriteFile( | |
233 tracker->GetFullDBFilePath(kOrigin1, kDB1), "a", 1)); | |
234 EXPECT_EQ(2, base::WriteFile( | |
235 tracker->GetFullDBFilePath(kOrigin2, kDB2), "aa", 2)); | |
236 EXPECT_EQ(3, base::WriteFile( | |
237 tracker->GetFullDBFilePath(kOrigin2, kDB3), "aaa", 3)); | |
238 tracker->DatabaseModified(kOrigin1, kDB1); | |
239 tracker->DatabaseModified(kOrigin2, kDB2); | |
240 tracker->DatabaseModified(kOrigin2, kDB3); | |
241 | |
242 // Delete db1. Should also delete origin1. | |
243 TestObserver observer; | |
244 tracker->AddObserver(&observer); | |
245 net::TestCompletionCallback callback; | |
246 int result = tracker->DeleteDatabase(kOrigin1, kDB1, callback.callback()); | |
247 EXPECT_EQ(net::ERR_IO_PENDING, result); | |
248 ASSERT_FALSE(callback.have_result()); | |
249 EXPECT_TRUE(observer.DidReceiveNewNotification()); | |
250 EXPECT_EQ(kOrigin1, observer.GetNotificationOriginIdentifier()); | |
251 EXPECT_EQ(kDB1, observer.GetNotificationDatabaseName()); | |
252 tracker->DatabaseClosed(kOrigin1, kDB1); | |
253 result = callback.GetResult(result); | |
254 EXPECT_EQ(net::OK, result); | |
255 EXPECT_FALSE(base::PathExists( | |
256 tracker->DatabaseDirectory().AppendASCII(kOrigin1))); | |
257 | |
258 // Recreate db1. | |
259 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0, | |
260 &database_size); | |
261 EXPECT_TRUE(base::CreateDirectory( | |
262 tracker->DatabaseDirectory().Append(base::FilePath::FromUTF16Unsafe( | |
263 tracker->GetOriginDirectory(kOrigin1))))); | |
264 EXPECT_EQ(1, base::WriteFile( | |
265 tracker->GetFullDBFilePath(kOrigin1, kDB1), "a", 1)); | |
266 tracker->DatabaseModified(kOrigin1, kDB1); | |
267 | |
268 // Setup file modification times. db1 and db2 are modified now, db3 three | |
269 // days ago. | |
270 base::Time now = base::Time::Now(); | |
271 EXPECT_TRUE(base::TouchFile(tracker->GetFullDBFilePath(kOrigin1, kDB1), | |
272 now, now)); | |
273 EXPECT_TRUE(base::TouchFile(tracker->GetFullDBFilePath(kOrigin2, kDB2), | |
274 now, now)); | |
275 base::Time three_days_ago = now - base::TimeDelta::FromDays(3); | |
276 EXPECT_TRUE(base::TouchFile(tracker->GetFullDBFilePath(kOrigin2, kDB3), | |
277 three_days_ago, three_days_ago)); | |
278 | |
279 // Delete databases modified since yesterday. db2 is whitelisted. | |
280 base::Time yesterday = base::Time::Now(); | |
281 yesterday -= base::TimeDelta::FromDays(1); | |
282 result = tracker->DeleteDataModifiedSince( | |
283 yesterday, callback.callback()); | |
284 EXPECT_EQ(net::ERR_IO_PENDING, result); | |
285 ASSERT_FALSE(callback.have_result()); | |
286 EXPECT_TRUE(observer.DidReceiveNewNotification()); | |
287 tracker->DatabaseClosed(kOrigin1, kDB1); | |
288 tracker->DatabaseClosed(kOrigin2, kDB2); | |
289 result = callback.GetResult(result); | |
290 EXPECT_EQ(net::OK, result); | |
291 EXPECT_FALSE(base::PathExists( | |
292 tracker->DatabaseDirectory().AppendASCII(kOrigin1))); | |
293 EXPECT_TRUE( | |
294 base::PathExists(tracker->GetFullDBFilePath(kOrigin2, kDB2))); | |
295 EXPECT_TRUE( | |
296 base::PathExists(tracker->GetFullDBFilePath(kOrigin2, kDB3))); | |
297 | |
298 tracker->DatabaseClosed(kOrigin2, kDB3); | |
299 tracker->RemoveObserver(&observer); | |
300 } | |
301 | |
302 static void TestDatabaseTracker(bool incognito_mode) { | |
303 // Initialize the tracker database. | |
304 base::ScopedTempDir temp_dir; | |
305 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
306 scoped_refptr<quota::MockSpecialStoragePolicy> special_storage_policy = | |
307 new quota::MockSpecialStoragePolicy; | |
308 special_storage_policy->AddProtected(GURL(kOrigin2Url)); | |
309 scoped_refptr<DatabaseTracker> tracker( | |
310 new DatabaseTracker(temp_dir.path(), | |
311 incognito_mode, | |
312 special_storage_policy.get(), | |
313 NULL, | |
314 NULL)); | |
315 | |
316 // Add two observers. | |
317 TestObserver observer1; | |
318 TestObserver observer2; | |
319 tracker->AddObserver(&observer1); | |
320 tracker->AddObserver(&observer2); | |
321 | |
322 // Open three new databases. | |
323 int64 database_size = 0; | |
324 const std::string kOrigin1 = | |
325 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin1Url)); | |
326 const std::string kOrigin2 = | |
327 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin2Url)); | |
328 const base::string16 kDB1 = ASCIIToUTF16("db1"); | |
329 const base::string16 kDB2 = ASCIIToUTF16("db2"); | |
330 const base::string16 kDB3 = ASCIIToUTF16("db3"); | |
331 const base::string16 kDescription = ASCIIToUTF16("database_description"); | |
332 | |
333 // Get the info for kOrigin1 and kOrigin2 | |
334 DatabaseTracker::CachedOriginInfo* origin1_info = | |
335 tracker->GetCachedOriginInfo(kOrigin1); | |
336 DatabaseTracker::CachedOriginInfo* origin2_info = | |
337 tracker->GetCachedOriginInfo(kOrigin1); | |
338 EXPECT_TRUE(origin1_info); | |
339 EXPECT_TRUE(origin2_info); | |
340 | |
341 | |
342 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0, | |
343 &database_size); | |
344 EXPECT_EQ(0, database_size); | |
345 tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0, | |
346 &database_size); | |
347 EXPECT_EQ(0, database_size); | |
348 tracker->DatabaseOpened(kOrigin1, kDB3, kDescription, 0, | |
349 &database_size); | |
350 EXPECT_EQ(0, database_size); | |
351 | |
352 // Write some data to each file and check that the listeners are | |
353 // called with the appropriate values. | |
354 EXPECT_TRUE(base::CreateDirectory( | |
355 tracker->DatabaseDirectory().Append(base::FilePath::FromUTF16Unsafe( | |
356 tracker->GetOriginDirectory(kOrigin1))))); | |
357 EXPECT_TRUE(base::CreateDirectory( | |
358 tracker->DatabaseDirectory().Append(base::FilePath::FromUTF16Unsafe( | |
359 tracker->GetOriginDirectory(kOrigin2))))); | |
360 EXPECT_EQ(1, base::WriteFile( | |
361 tracker->GetFullDBFilePath(kOrigin1, kDB1), "a", 1)); | |
362 EXPECT_EQ(2, base::WriteFile( | |
363 tracker->GetFullDBFilePath(kOrigin2, kDB2), "aa", 2)); | |
364 EXPECT_EQ(4, base::WriteFile( | |
365 tracker->GetFullDBFilePath(kOrigin1, kDB3), "aaaa", 4)); | |
366 tracker->DatabaseModified(kOrigin1, kDB1); | |
367 CheckNotificationReceived(&observer1, kOrigin1, kDB1, 1); | |
368 CheckNotificationReceived(&observer2, kOrigin1, kDB1, 1); | |
369 tracker->DatabaseModified(kOrigin2, kDB2); | |
370 CheckNotificationReceived(&observer1, kOrigin2, kDB2, 2); | |
371 CheckNotificationReceived(&observer2, kOrigin2, kDB2, 2); | |
372 tracker->DatabaseModified(kOrigin1, kDB3); | |
373 CheckNotificationReceived(&observer1, kOrigin1, kDB3, 4); | |
374 CheckNotificationReceived(&observer2, kOrigin1, kDB3, 4); | |
375 | |
376 // Close all databases | |
377 tracker->DatabaseClosed(kOrigin1, kDB1); | |
378 tracker->DatabaseClosed(kOrigin2, kDB2); | |
379 tracker->DatabaseClosed(kOrigin1, kDB3); | |
380 | |
381 // Open an existing database and check the reported size | |
382 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0, | |
383 &database_size); | |
384 EXPECT_EQ(1, database_size); | |
385 tracker->DatabaseClosed(kOrigin1, kDB1); | |
386 | |
387 // Remove an observer; this should clear all caches. | |
388 tracker->RemoveObserver(&observer2); | |
389 | |
390 // Close the tracker database and clear all caches. | |
391 // Then make sure that DatabaseOpened() still returns the correct result. | |
392 tracker->CloseTrackerDatabaseAndClearCaches(); | |
393 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0, | |
394 &database_size); | |
395 EXPECT_EQ(1, database_size); | |
396 tracker->DatabaseClosed(kOrigin1, kDB1); | |
397 | |
398 // Remove all observers. | |
399 tracker->RemoveObserver(&observer1); | |
400 | |
401 // Trying to delete a database in use should fail | |
402 tracker->DatabaseOpened(kOrigin1, kDB3, kDescription, 0, | |
403 &database_size); | |
404 EXPECT_FALSE(tracker->DeleteClosedDatabase(kOrigin1, kDB3)); | |
405 origin1_info = tracker->GetCachedOriginInfo(kOrigin1); | |
406 EXPECT_TRUE(origin1_info); | |
407 EXPECT_EQ(4, origin1_info->GetDatabaseSize(kDB3)); | |
408 tracker->DatabaseClosed(kOrigin1, kDB3); | |
409 | |
410 // Delete a database and make sure the space used by that origin is updated | |
411 EXPECT_TRUE(tracker->DeleteClosedDatabase(kOrigin1, kDB3)); | |
412 origin1_info = tracker->GetCachedOriginInfo(kOrigin1); | |
413 EXPECT_TRUE(origin1_info); | |
414 EXPECT_EQ(1, origin1_info->GetDatabaseSize(kDB1)); | |
415 EXPECT_EQ(0, origin1_info->GetDatabaseSize(kDB3)); | |
416 | |
417 // Get all data for all origins | |
418 std::vector<OriginInfo> origins_info; | |
419 EXPECT_TRUE(tracker->GetAllOriginsInfo(&origins_info)); | |
420 EXPECT_EQ(size_t(2), origins_info.size()); | |
421 EXPECT_EQ(kOrigin1, origins_info[0].GetOriginIdentifier()); | |
422 EXPECT_EQ(1, origins_info[0].TotalSize()); | |
423 EXPECT_EQ(1, origins_info[0].GetDatabaseSize(kDB1)); | |
424 EXPECT_EQ(0, origins_info[0].GetDatabaseSize(kDB3)); | |
425 | |
426 EXPECT_EQ(kOrigin2, origins_info[1].GetOriginIdentifier()); | |
427 EXPECT_EQ(2, origins_info[1].TotalSize()); | |
428 | |
429 // Trying to delete an origin with databases in use should fail | |
430 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0, | |
431 &database_size); | |
432 EXPECT_FALSE(tracker->DeleteOrigin(kOrigin1, false)); | |
433 origin1_info = tracker->GetCachedOriginInfo(kOrigin1); | |
434 EXPECT_TRUE(origin1_info); | |
435 EXPECT_EQ(1, origin1_info->GetDatabaseSize(kDB1)); | |
436 tracker->DatabaseClosed(kOrigin1, kDB1); | |
437 | |
438 // Delete an origin that doesn't have any database in use | |
439 EXPECT_TRUE(tracker->DeleteOrigin(kOrigin1, false)); | |
440 origins_info.clear(); | |
441 EXPECT_TRUE(tracker->GetAllOriginsInfo(&origins_info)); | |
442 EXPECT_EQ(size_t(1), origins_info.size()); | |
443 EXPECT_EQ(kOrigin2, origins_info[0].GetOriginIdentifier()); | |
444 | |
445 origin1_info = tracker->GetCachedOriginInfo(kOrigin1); | |
446 EXPECT_TRUE(origin1_info); | |
447 EXPECT_EQ(0, origin1_info->TotalSize()); | |
448 } | |
449 | |
450 static void DatabaseTrackerQuotaIntegration() { | |
451 const GURL kOrigin(kOrigin1Url); | |
452 const std::string kOriginId = | |
453 webkit_database::GetIdentifierFromOrigin(kOrigin); | |
454 const base::string16 kName = ASCIIToUTF16("name"); | |
455 const base::string16 kDescription = ASCIIToUTF16("description"); | |
456 | |
457 base::ScopedTempDir temp_dir; | |
458 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
459 | |
460 // Initialize the tracker with a QuotaManagerProxy | |
461 scoped_refptr<TestQuotaManagerProxy> test_quota_proxy( | |
462 new TestQuotaManagerProxy); | |
463 scoped_refptr<DatabaseTracker> tracker( | |
464 new DatabaseTracker(temp_dir.path(), | |
465 false /* incognito */, | |
466 NULL, | |
467 test_quota_proxy.get(), | |
468 NULL)); | |
469 EXPECT_TRUE(test_quota_proxy->registered_client_); | |
470 | |
471 // Create a database and modify it a couple of times, close it, | |
472 // then delete it. Observe the tracker notifies accordingly. | |
473 | |
474 int64 database_size = 0; | |
475 tracker->DatabaseOpened(kOriginId, kName, kDescription, 0, | |
476 &database_size); | |
477 EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin)); | |
478 test_quota_proxy->reset(); | |
479 | |
480 base::FilePath db_file(tracker->GetFullDBFilePath(kOriginId, kName)); | |
481 EXPECT_TRUE(base::CreateDirectory(db_file.DirName())); | |
482 EXPECT_TRUE(EnsureFileOfSize(db_file, 10)); | |
483 tracker->DatabaseModified(kOriginId, kName); | |
484 EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, 10)); | |
485 test_quota_proxy->reset(); | |
486 | |
487 EXPECT_TRUE(EnsureFileOfSize(db_file, 100)); | |
488 tracker->DatabaseModified(kOriginId, kName); | |
489 EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, 90)); | |
490 test_quota_proxy->reset(); | |
491 | |
492 tracker->DatabaseClosed(kOriginId, kName); | |
493 EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin)); | |
494 EXPECT_EQ(net::OK, tracker->DeleteDatabase( | |
495 kOriginId, kName, net::CompletionCallback())); | |
496 EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, -100)); | |
497 test_quota_proxy->reset(); | |
498 | |
499 // Create a database and modify it, try to delete it while open, | |
500 // then close it (at which time deletion will actually occur). | |
501 // Observe the tracker notifies accordingly. | |
502 | |
503 tracker->DatabaseOpened(kOriginId, kName, kDescription, 0, | |
504 &database_size); | |
505 EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin)); | |
506 test_quota_proxy->reset(); | |
507 | |
508 db_file = tracker->GetFullDBFilePath(kOriginId, kName); | |
509 EXPECT_TRUE(base::CreateDirectory(db_file.DirName())); | |
510 EXPECT_TRUE(EnsureFileOfSize(db_file, 100)); | |
511 tracker->DatabaseModified(kOriginId, kName); | |
512 EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, 100)); | |
513 test_quota_proxy->reset(); | |
514 | |
515 EXPECT_EQ(net::ERR_IO_PENDING, | |
516 tracker->DeleteDatabase(kOriginId, kName, | |
517 net::CompletionCallback())); | |
518 EXPECT_FALSE(test_quota_proxy->WasModificationNotified(kOrigin, -100)); | |
519 | |
520 tracker->DatabaseClosed(kOriginId, kName); | |
521 EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin)); | |
522 EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, -100)); | |
523 test_quota_proxy->reset(); | |
524 | |
525 // Create a database and up the file size without telling | |
526 // the tracker about the modification, than simulate a | |
527 // a renderer crash. | |
528 // Observe the tracker notifies accordingly. | |
529 | |
530 tracker->DatabaseOpened(kOriginId, kName, kDescription, 0, | |
531 &database_size); | |
532 EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin)); | |
533 test_quota_proxy->reset(); | |
534 db_file = tracker->GetFullDBFilePath(kOriginId, kName); | |
535 EXPECT_TRUE(base::CreateDirectory(db_file.DirName())); | |
536 EXPECT_TRUE(EnsureFileOfSize(db_file, 100)); | |
537 DatabaseConnections crashed_renderer_connections; | |
538 crashed_renderer_connections.AddConnection(kOriginId, kName); | |
539 EXPECT_FALSE(test_quota_proxy->WasModificationNotified(kOrigin, 100)); | |
540 tracker->CloseDatabases(crashed_renderer_connections); | |
541 EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, 100)); | |
542 | |
543 // Cleanup. | |
544 crashed_renderer_connections.RemoveAllConnections(); | |
545 test_quota_proxy->SimulateQuotaManagerDestroyed(); | |
546 } | |
547 | |
548 static void DatabaseTrackerClearSessionOnlyDatabasesOnExit() { | |
549 int64 database_size = 0; | |
550 const std::string kOrigin1 = | |
551 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin1Url)); | |
552 const std::string kOrigin2 = | |
553 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin2Url)); | |
554 const base::string16 kDB1 = ASCIIToUTF16("db1"); | |
555 const base::string16 kDB2 = ASCIIToUTF16("db2"); | |
556 const base::string16 kDescription = ASCIIToUTF16("database_description"); | |
557 | |
558 // Initialize the tracker database. | |
559 base::MessageLoop message_loop; | |
560 base::ScopedTempDir temp_dir; | |
561 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
562 base::FilePath origin1_db_dir; | |
563 base::FilePath origin2_db_dir; | |
564 { | |
565 scoped_refptr<quota::MockSpecialStoragePolicy> special_storage_policy = | |
566 new quota::MockSpecialStoragePolicy; | |
567 special_storage_policy->AddSessionOnly(GURL(kOrigin2Url)); | |
568 scoped_refptr<DatabaseTracker> tracker( | |
569 new DatabaseTracker(temp_dir.path(), | |
570 false, | |
571 special_storage_policy.get(), | |
572 NULL, | |
573 base::MessageLoopProxy::current().get())); | |
574 | |
575 // Open two new databases. | |
576 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0, | |
577 &database_size); | |
578 EXPECT_EQ(0, database_size); | |
579 tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0, | |
580 &database_size); | |
581 EXPECT_EQ(0, database_size); | |
582 | |
583 // Write some data to each file. | |
584 base::FilePath db_file; | |
585 db_file = tracker->GetFullDBFilePath(kOrigin1, kDB1); | |
586 EXPECT_TRUE(base::CreateDirectory(db_file.DirName())); | |
587 EXPECT_TRUE(EnsureFileOfSize(db_file, 1)); | |
588 | |
589 db_file = tracker->GetFullDBFilePath(kOrigin2, kDB2); | |
590 EXPECT_TRUE(base::CreateDirectory(db_file.DirName())); | |
591 EXPECT_TRUE(EnsureFileOfSize(db_file, 2)); | |
592 | |
593 // Store the origin database directories as long as they still exist. | |
594 origin1_db_dir = tracker->GetFullDBFilePath(kOrigin1, kDB1).DirName(); | |
595 origin2_db_dir = tracker->GetFullDBFilePath(kOrigin2, kDB2).DirName(); | |
596 | |
597 tracker->DatabaseModified(kOrigin1, kDB1); | |
598 tracker->DatabaseModified(kOrigin2, kDB2); | |
599 | |
600 // Close all databases. | |
601 tracker->DatabaseClosed(kOrigin1, kDB1); | |
602 tracker->DatabaseClosed(kOrigin2, kDB2); | |
603 | |
604 tracker->Shutdown(); | |
605 } | |
606 | |
607 // At this point, the database tracker should be gone. Create a new one. | |
608 scoped_refptr<DatabaseTracker> tracker( | |
609 new DatabaseTracker(temp_dir.path(), false, NULL, NULL, NULL)); | |
610 | |
611 // Get all data for all origins. | |
612 std::vector<OriginInfo> origins_info; | |
613 EXPECT_TRUE(tracker->GetAllOriginsInfo(&origins_info)); | |
614 // kOrigin1 was not session-only, so it survived. kOrigin2 was session-only | |
615 // and it got deleted. | |
616 EXPECT_EQ(size_t(1), origins_info.size()); | |
617 EXPECT_EQ(kOrigin1, origins_info[0].GetOriginIdentifier()); | |
618 EXPECT_TRUE( | |
619 base::PathExists(tracker->GetFullDBFilePath(kOrigin1, kDB1))); | |
620 EXPECT_EQ(base::FilePath(), tracker->GetFullDBFilePath(kOrigin2, kDB2)); | |
621 | |
622 // The origin directory of kOrigin1 remains, but the origin directory of | |
623 // kOrigin2 is deleted. | |
624 EXPECT_TRUE(base::PathExists(origin1_db_dir)); | |
625 EXPECT_FALSE(base::PathExists(origin2_db_dir)); | |
626 } | |
627 | |
628 static void DatabaseTrackerSetForceKeepSessionState() { | |
629 int64 database_size = 0; | |
630 const std::string kOrigin1 = | |
631 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin1Url)); | |
632 const std::string kOrigin2 = | |
633 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin2Url)); | |
634 const base::string16 kDB1 = ASCIIToUTF16("db1"); | |
635 const base::string16 kDB2 = ASCIIToUTF16("db2"); | |
636 const base::string16 kDescription = ASCIIToUTF16("database_description"); | |
637 | |
638 // Initialize the tracker database. | |
639 base::MessageLoop message_loop; | |
640 base::ScopedTempDir temp_dir; | |
641 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
642 base::FilePath origin1_db_dir; | |
643 base::FilePath origin2_db_dir; | |
644 { | |
645 scoped_refptr<quota::MockSpecialStoragePolicy> special_storage_policy = | |
646 new quota::MockSpecialStoragePolicy; | |
647 special_storage_policy->AddSessionOnly(GURL(kOrigin2Url)); | |
648 scoped_refptr<DatabaseTracker> tracker( | |
649 new DatabaseTracker(temp_dir.path(), | |
650 false, | |
651 special_storage_policy.get(), | |
652 NULL, | |
653 base::MessageLoopProxy::current().get())); | |
654 tracker->SetForceKeepSessionState(); | |
655 | |
656 // Open two new databases. | |
657 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0, | |
658 &database_size); | |
659 EXPECT_EQ(0, database_size); | |
660 tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0, | |
661 &database_size); | |
662 EXPECT_EQ(0, database_size); | |
663 | |
664 // Write some data to each file. | |
665 base::FilePath db_file; | |
666 db_file = tracker->GetFullDBFilePath(kOrigin1, kDB1); | |
667 EXPECT_TRUE(base::CreateDirectory(db_file.DirName())); | |
668 EXPECT_TRUE(EnsureFileOfSize(db_file, 1)); | |
669 | |
670 db_file = tracker->GetFullDBFilePath(kOrigin2, kDB2); | |
671 EXPECT_TRUE(base::CreateDirectory(db_file.DirName())); | |
672 EXPECT_TRUE(EnsureFileOfSize(db_file, 2)); | |
673 | |
674 // Store the origin database directories as long as they still exist. | |
675 origin1_db_dir = tracker->GetFullDBFilePath(kOrigin1, kDB1).DirName(); | |
676 origin2_db_dir = tracker->GetFullDBFilePath(kOrigin2, kDB2).DirName(); | |
677 | |
678 tracker->DatabaseModified(kOrigin1, kDB1); | |
679 tracker->DatabaseModified(kOrigin2, kDB2); | |
680 | |
681 // Close all databases. | |
682 tracker->DatabaseClosed(kOrigin1, kDB1); | |
683 tracker->DatabaseClosed(kOrigin2, kDB2); | |
684 | |
685 tracker->Shutdown(); | |
686 } | |
687 | |
688 // At this point, the database tracker should be gone. Create a new one. | |
689 scoped_refptr<DatabaseTracker> tracker( | |
690 new DatabaseTracker(temp_dir.path(), false, NULL, NULL, NULL)); | |
691 | |
692 // Get all data for all origins. | |
693 std::vector<OriginInfo> origins_info; | |
694 EXPECT_TRUE(tracker->GetAllOriginsInfo(&origins_info)); | |
695 // No origins were deleted. | |
696 EXPECT_EQ(size_t(2), origins_info.size()); | |
697 EXPECT_TRUE( | |
698 base::PathExists(tracker->GetFullDBFilePath(kOrigin1, kDB1))); | |
699 EXPECT_TRUE( | |
700 base::PathExists(tracker->GetFullDBFilePath(kOrigin2, kDB2))); | |
701 | |
702 EXPECT_TRUE(base::PathExists(origin1_db_dir)); | |
703 EXPECT_TRUE(base::PathExists(origin2_db_dir)); | |
704 } | |
705 | |
706 static void EmptyDatabaseNameIsValid() { | |
707 const GURL kOrigin(kOrigin1Url); | |
708 const std::string kOriginId = | |
709 webkit_database::GetIdentifierFromOrigin(kOrigin); | |
710 const base::string16 kEmptyName; | |
711 const base::string16 kDescription(ASCIIToUTF16("description")); | |
712 const base::string16 kChangedDescription( | |
713 ASCIIToUTF16("changed_description")); | |
714 | |
715 // Initialize a tracker database, no need to put it on disk. | |
716 const bool kUseInMemoryTrackerDatabase = true; | |
717 base::ScopedTempDir temp_dir; | |
718 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
719 scoped_refptr<DatabaseTracker> tracker( | |
720 new DatabaseTracker(temp_dir.path(), kUseInMemoryTrackerDatabase, | |
721 NULL, NULL, NULL)); | |
722 | |
723 // Starts off with no databases. | |
724 std::vector<OriginInfo> infos; | |
725 EXPECT_TRUE(tracker->GetAllOriginsInfo(&infos)); | |
726 EXPECT_TRUE(infos.empty()); | |
727 | |
728 // Create a db with an empty name. | |
729 int64 database_size = -1; | |
730 tracker->DatabaseOpened(kOriginId, kEmptyName, kDescription, 0, | |
731 &database_size); | |
732 EXPECT_EQ(0, database_size); | |
733 tracker->DatabaseModified(kOriginId, kEmptyName); | |
734 EXPECT_TRUE(tracker->GetAllOriginsInfo(&infos)); | |
735 EXPECT_EQ(1u, infos.size()); | |
736 EXPECT_EQ(kDescription, infos[0].GetDatabaseDescription(kEmptyName)); | |
737 EXPECT_FALSE(tracker->GetFullDBFilePath(kOriginId, kEmptyName).empty()); | |
738 tracker->DatabaseOpened(kOriginId, kEmptyName, kChangedDescription, 0, | |
739 &database_size); | |
740 infos.clear(); | |
741 EXPECT_TRUE(tracker->GetAllOriginsInfo(&infos)); | |
742 EXPECT_EQ(1u, infos.size()); | |
743 EXPECT_EQ(kChangedDescription, infos[0].GetDatabaseDescription(kEmptyName)); | |
744 tracker->DatabaseClosed(kOriginId, kEmptyName); | |
745 tracker->DatabaseClosed(kOriginId, kEmptyName); | |
746 | |
747 // Deleting it should return to the initial state. | |
748 EXPECT_EQ(net::OK, tracker->DeleteDatabase(kOriginId, kEmptyName, | |
749 net::CompletionCallback())); | |
750 infos.clear(); | |
751 EXPECT_TRUE(tracker->GetAllOriginsInfo(&infos)); | |
752 EXPECT_TRUE(infos.empty()); | |
753 } | |
754 | |
755 static void HandleSqliteError() { | |
756 const GURL kOrigin(kOrigin1Url); | |
757 const std::string kOriginId = | |
758 webkit_database::GetIdentifierFromOrigin(kOrigin); | |
759 const base::string16 kName(ASCIIToUTF16("name")); | |
760 const base::string16 kDescription(ASCIIToUTF16("description")); | |
761 | |
762 // Initialize a tracker database, no need to put it on disk. | |
763 const bool kUseInMemoryTrackerDatabase = true; | |
764 base::ScopedTempDir temp_dir; | |
765 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
766 scoped_refptr<DatabaseTracker> tracker( | |
767 new DatabaseTracker(temp_dir.path(), kUseInMemoryTrackerDatabase, | |
768 NULL, NULL, NULL)); | |
769 | |
770 // Setup to observe OnScheduledForDelete notifications. | |
771 TestObserver observer(false, true); | |
772 tracker->AddObserver(&observer); | |
773 | |
774 // Verify does no harm when there is no such database. | |
775 tracker->HandleSqliteError(kOriginId, kName, SQLITE_CORRUPT); | |
776 EXPECT_FALSE(tracker->IsDatabaseScheduledForDeletion(kOriginId, kName)); | |
777 EXPECT_FALSE(observer.DidReceiveNewNotification()); | |
778 | |
779 // -------------------------------------------------------- | |
780 // Create a record of a database in the tracker db and create | |
781 // a spoof_db_file on disk in the expected location. | |
782 int64 database_size = 0; | |
783 tracker->DatabaseOpened(kOriginId, kName, kDescription, 0, | |
784 &database_size); | |
785 base::FilePath spoof_db_file = tracker->GetFullDBFilePath(kOriginId, kName); | |
786 EXPECT_FALSE(tracker->GetFullDBFilePath(kOriginId, kName).empty()); | |
787 EXPECT_TRUE(base::CreateDirectory(spoof_db_file.DirName())); | |
788 EXPECT_TRUE(EnsureFileOfSize(spoof_db_file, 1)); | |
789 | |
790 // Verify does no harm with a non-error is reported. | |
791 tracker->HandleSqliteError(kOriginId, kName, SQLITE_OK); | |
792 EXPECT_FALSE(tracker->IsDatabaseScheduledForDeletion(kOriginId, kName)); | |
793 EXPECT_FALSE(observer.DidReceiveNewNotification()); | |
794 | |
795 // Verify that with a connection open, the db is scheduled for deletion, | |
796 // but that the file still exists. | |
797 tracker->HandleSqliteError(kOriginId, kName, SQLITE_CORRUPT); | |
798 EXPECT_TRUE(tracker->IsDatabaseScheduledForDeletion(kOriginId, kName)); | |
799 EXPECT_TRUE(observer.DidReceiveNewNotification()); | |
800 EXPECT_TRUE(base::PathExists(spoof_db_file)); | |
801 | |
802 // Verify that once closed, the file is deleted and the record in the | |
803 // tracker db is removed. | |
804 tracker->DatabaseClosed(kOriginId, kName); | |
805 EXPECT_FALSE(base::PathExists(spoof_db_file)); | |
806 EXPECT_TRUE(tracker->GetFullDBFilePath(kOriginId, kName).empty()); | |
807 | |
808 // -------------------------------------------------------- | |
809 // Create another record of a database in the tracker db and create | |
810 // a spoof_db_file on disk in the expected location. | |
811 tracker->DatabaseOpened(kOriginId, kName, kDescription, 0, | |
812 &database_size); | |
813 base::FilePath spoof_db_file2 = tracker->GetFullDBFilePath(kOriginId, kName)
; | |
814 EXPECT_FALSE(tracker->GetFullDBFilePath(kOriginId, kName).empty()); | |
815 EXPECT_NE(spoof_db_file, spoof_db_file2); | |
816 EXPECT_TRUE(base::CreateDirectory(spoof_db_file2.DirName())); | |
817 EXPECT_TRUE(EnsureFileOfSize(spoof_db_file2, 1)); | |
818 | |
819 // Verify that with no connection open, the db is deleted immediately. | |
820 tracker->DatabaseClosed(kOriginId, kName); | |
821 tracker->HandleSqliteError(kOriginId, kName, SQLITE_CORRUPT); | |
822 EXPECT_FALSE(tracker->IsDatabaseScheduledForDeletion(kOriginId, kName)); | |
823 EXPECT_FALSE(observer.DidReceiveNewNotification()); | |
824 EXPECT_TRUE(tracker->GetFullDBFilePath(kOriginId, kName).empty()); | |
825 EXPECT_FALSE(base::PathExists(spoof_db_file2)); | |
826 | |
827 tracker->RemoveObserver(&observer); | |
828 } | |
829 }; | |
830 | |
831 TEST(DatabaseTrackerTest, DeleteOpenDatabase) { | |
832 DatabaseTracker_TestHelper_Test::TestDeleteOpenDatabase(false); | |
833 } | |
834 | |
835 TEST(DatabaseTrackerTest, DeleteOpenDatabaseIncognitoMode) { | |
836 DatabaseTracker_TestHelper_Test::TestDeleteOpenDatabase(true); | |
837 } | |
838 | |
839 TEST(DatabaseTrackerTest, DatabaseTracker) { | |
840 DatabaseTracker_TestHelper_Test::TestDatabaseTracker(false); | |
841 } | |
842 | |
843 TEST(DatabaseTrackerTest, DatabaseTrackerIncognitoMode) { | |
844 DatabaseTracker_TestHelper_Test::TestDatabaseTracker(true); | |
845 } | |
846 | |
847 TEST(DatabaseTrackerTest, DatabaseTrackerQuotaIntegration) { | |
848 // There is no difference in behavior between incognito and not. | |
849 DatabaseTracker_TestHelper_Test::DatabaseTrackerQuotaIntegration(); | |
850 } | |
851 | |
852 TEST(DatabaseTrackerTest, DatabaseTrackerClearSessionOnlyDatabasesOnExit) { | |
853 // Only works for regular mode. | |
854 DatabaseTracker_TestHelper_Test:: | |
855 DatabaseTrackerClearSessionOnlyDatabasesOnExit(); | |
856 } | |
857 | |
858 TEST(DatabaseTrackerTest, DatabaseTrackerSetForceKeepSessionState) { | |
859 // Only works for regular mode. | |
860 DatabaseTracker_TestHelper_Test::DatabaseTrackerSetForceKeepSessionState(); | |
861 } | |
862 | |
863 TEST(DatabaseTrackerTest, EmptyDatabaseNameIsValid) { | |
864 DatabaseTracker_TestHelper_Test::EmptyDatabaseNameIsValid(); | |
865 } | |
866 | |
867 TEST(DatabaseTrackerTest, HandleSqliteError) { | |
868 DatabaseTracker_TestHelper_Test::HandleSqliteError(); | |
869 } | |
870 | |
871 } // namespace webkit_database | |
OLD | NEW |