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