Always set *error when CreateDirectoryAndGetError fails.
[chromium-blink-merge.git] / webkit / browser / database / database_tracker_unittest.cc
blob94f36a994d503bfe421f10bbfb471bf660761f41
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/message_loop_proxy.h"
11 #include "base/platform_file.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/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.h"
21 #include "webkit/common/database/database_identifier.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 std::string& 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 std::string& 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 std::string 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 std::string origin_identifier_;
77 base::string16 database_name_;
78 int64 database_size_;
81 void CheckNotificationReceived(TestObserver* observer,
82 const std::string& 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(),
200 incognito_mode,
201 special_storage_policy.get(),
202 NULL,
203 NULL));
205 // Create and open three databases.
206 int64 database_size = 0;
207 const std::string kOrigin1 =
208 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin1Url));
209 const std::string kOrigin2 =
210 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin2Url));
211 const base::string16 kDB1 = ASCIIToUTF16("db1");
212 const base::string16 kDB2 = ASCIIToUTF16("db2");
213 const base::string16 kDB3 = ASCIIToUTF16("db3");
214 const base::string16 kDescription = ASCIIToUTF16("database_description");
216 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
217 &database_size);
218 tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0,
219 &database_size);
220 tracker->DatabaseOpened(kOrigin2, kDB3, kDescription, 0,
221 &database_size);
223 EXPECT_TRUE(file_util::CreateDirectory(tracker->DatabaseDirectory().Append(
224 base::FilePath::FromWStringHack(UTF16ToWide(
225 tracker->GetOriginDirectory(kOrigin1))))));
226 EXPECT_TRUE(file_util::CreateDirectory(tracker->DatabaseDirectory().Append(
227 base::FilePath::FromWStringHack(UTF16ToWide(
228 tracker->GetOriginDirectory(kOrigin2))))));
229 EXPECT_EQ(1, file_util::WriteFile(
230 tracker->GetFullDBFilePath(kOrigin1, kDB1), "a", 1));
231 EXPECT_EQ(2, file_util::WriteFile(
232 tracker->GetFullDBFilePath(kOrigin2, kDB2), "aa", 2));
233 EXPECT_EQ(3, file_util::WriteFile(
234 tracker->GetFullDBFilePath(kOrigin2, kDB3), "aaa", 3));
235 tracker->DatabaseModified(kOrigin1, kDB1);
236 tracker->DatabaseModified(kOrigin2, kDB2);
237 tracker->DatabaseModified(kOrigin2, kDB3);
239 // Delete db1. Should also delete origin1.
240 TestObserver observer;
241 tracker->AddObserver(&observer);
242 net::TestCompletionCallback callback;
243 int result = tracker->DeleteDatabase(kOrigin1, kDB1, callback.callback());
244 EXPECT_EQ(net::ERR_IO_PENDING, result);
245 ASSERT_FALSE(callback.have_result());
246 EXPECT_TRUE(observer.DidReceiveNewNotification());
247 EXPECT_EQ(kOrigin1, observer.GetNotificationOriginIdentifier());
248 EXPECT_EQ(kDB1, observer.GetNotificationDatabaseName());
249 tracker->DatabaseClosed(kOrigin1, kDB1);
250 result = callback.GetResult(result);
251 EXPECT_EQ(net::OK, result);
252 EXPECT_FALSE(file_util::PathExists(
253 tracker->DatabaseDirectory().AppendASCII(kOrigin1)));
255 // Recreate db1.
256 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
257 &database_size);
258 EXPECT_TRUE(file_util::CreateDirectory(tracker->DatabaseDirectory().Append(
259 base::FilePath::FromWStringHack(UTF16ToWide(
260 tracker->GetOriginDirectory(kOrigin1))))));
261 EXPECT_EQ(1, file_util::WriteFile(
262 tracker->GetFullDBFilePath(kOrigin1, kDB1), "a", 1));
263 tracker->DatabaseModified(kOrigin1, kDB1);
265 // Setup file modification times. db1 and db2 are modified now, db3 three
266 // days ago.
267 EXPECT_TRUE(file_util::SetLastModifiedTime(
268 tracker->GetFullDBFilePath(kOrigin1, kDB1), base::Time::Now()));
269 EXPECT_TRUE(file_util::SetLastModifiedTime(
270 tracker->GetFullDBFilePath(kOrigin2, kDB2), base::Time::Now()));
271 base::Time three_days_ago = base::Time::Now();
272 three_days_ago -= base::TimeDelta::FromDays(3);
273 EXPECT_TRUE(file_util::SetLastModifiedTime(
274 tracker->GetFullDBFilePath(kOrigin2, kDB3), three_days_ago));
276 // Delete databases modified since yesterday. db2 is whitelisted.
277 base::Time yesterday = base::Time::Now();
278 yesterday -= base::TimeDelta::FromDays(1);
279 result = tracker->DeleteDataModifiedSince(
280 yesterday, callback.callback());
281 EXPECT_EQ(net::ERR_IO_PENDING, result);
282 ASSERT_FALSE(callback.have_result());
283 EXPECT_TRUE(observer.DidReceiveNewNotification());
284 tracker->DatabaseClosed(kOrigin1, kDB1);
285 tracker->DatabaseClosed(kOrigin2, kDB2);
286 result = callback.GetResult(result);
287 EXPECT_EQ(net::OK, result);
288 EXPECT_FALSE(file_util::PathExists(
289 tracker->DatabaseDirectory().AppendASCII(kOrigin1)));
290 EXPECT_TRUE(
291 file_util::PathExists(tracker->GetFullDBFilePath(kOrigin2, kDB2)));
292 EXPECT_TRUE(
293 file_util::PathExists(tracker->GetFullDBFilePath(kOrigin2, kDB3)));
295 tracker->DatabaseClosed(kOrigin2, kDB3);
296 tracker->RemoveObserver(&observer);
299 static void TestDatabaseTracker(bool incognito_mode) {
300 // Initialize the tracker database.
301 base::ScopedTempDir temp_dir;
302 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
303 scoped_refptr<quota::MockSpecialStoragePolicy> special_storage_policy =
304 new quota::MockSpecialStoragePolicy;
305 special_storage_policy->AddProtected(GURL(kOrigin2Url));
306 scoped_refptr<DatabaseTracker> tracker(
307 new DatabaseTracker(temp_dir.path(),
308 incognito_mode,
309 special_storage_policy.get(),
310 NULL,
311 NULL));
313 // Add two observers.
314 TestObserver observer1;
315 TestObserver observer2;
316 tracker->AddObserver(&observer1);
317 tracker->AddObserver(&observer2);
319 // Open three new databases.
320 int64 database_size = 0;
321 const std::string kOrigin1 =
322 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin1Url));
323 const std::string kOrigin2 =
324 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin2Url));
325 const base::string16 kDB1 = ASCIIToUTF16("db1");
326 const base::string16 kDB2 = ASCIIToUTF16("db2");
327 const base::string16 kDB3 = ASCIIToUTF16("db3");
328 const base::string16 kDescription = ASCIIToUTF16("database_description");
330 // Get the info for kOrigin1 and kOrigin2
331 DatabaseTracker::CachedOriginInfo* origin1_info =
332 tracker->GetCachedOriginInfo(kOrigin1);
333 DatabaseTracker::CachedOriginInfo* origin2_info =
334 tracker->GetCachedOriginInfo(kOrigin1);
335 EXPECT_TRUE(origin1_info);
336 EXPECT_TRUE(origin2_info);
339 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
340 &database_size);
341 EXPECT_EQ(0, database_size);
342 tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0,
343 &database_size);
344 EXPECT_EQ(0, database_size);
345 tracker->DatabaseOpened(kOrigin1, kDB3, kDescription, 0,
346 &database_size);
347 EXPECT_EQ(0, database_size);
349 // Write some data to each file and check that the listeners are
350 // called with the appropriate values.
351 EXPECT_TRUE(file_util::CreateDirectory(tracker->DatabaseDirectory().Append(
352 base::FilePath::FromWStringHack(UTF16ToWide(
353 tracker->GetOriginDirectory(kOrigin1))))));
354 EXPECT_TRUE(file_util::CreateDirectory(tracker->DatabaseDirectory().Append(
355 base::FilePath::FromWStringHack(UTF16ToWide(
356 tracker->GetOriginDirectory(kOrigin2))))));
357 EXPECT_EQ(1, file_util::WriteFile(
358 tracker->GetFullDBFilePath(kOrigin1, kDB1), "a", 1));
359 EXPECT_EQ(2, file_util::WriteFile(
360 tracker->GetFullDBFilePath(kOrigin2, kDB2), "aa", 2));
361 EXPECT_EQ(4, file_util::WriteFile(
362 tracker->GetFullDBFilePath(kOrigin1, kDB3), "aaaa", 4));
363 tracker->DatabaseModified(kOrigin1, kDB1);
364 CheckNotificationReceived(&observer1, kOrigin1, kDB1, 1);
365 CheckNotificationReceived(&observer2, kOrigin1, kDB1, 1);
366 tracker->DatabaseModified(kOrigin2, kDB2);
367 CheckNotificationReceived(&observer1, kOrigin2, kDB2, 2);
368 CheckNotificationReceived(&observer2, kOrigin2, kDB2, 2);
369 tracker->DatabaseModified(kOrigin1, kDB3);
370 CheckNotificationReceived(&observer1, kOrigin1, kDB3, 4);
371 CheckNotificationReceived(&observer2, kOrigin1, kDB3, 4);
373 // Close all databases
374 tracker->DatabaseClosed(kOrigin1, kDB1);
375 tracker->DatabaseClosed(kOrigin2, kDB2);
376 tracker->DatabaseClosed(kOrigin1, kDB3);
378 // Open an existing database and check the reported size
379 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
380 &database_size);
381 EXPECT_EQ(1, database_size);
382 tracker->DatabaseClosed(kOrigin1, kDB1);
384 // Remove an observer; this should clear all caches.
385 tracker->RemoveObserver(&observer2);
387 // Close the tracker database and clear all caches.
388 // Then make sure that DatabaseOpened() still returns the correct result.
389 tracker->CloseTrackerDatabaseAndClearCaches();
390 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
391 &database_size);
392 EXPECT_EQ(1, database_size);
393 tracker->DatabaseClosed(kOrigin1, kDB1);
395 // Remove all observers.
396 tracker->RemoveObserver(&observer1);
398 // Trying to delete a database in use should fail
399 tracker->DatabaseOpened(kOrigin1, kDB3, kDescription, 0,
400 &database_size);
401 EXPECT_FALSE(tracker->DeleteClosedDatabase(kOrigin1, kDB3));
402 origin1_info = tracker->GetCachedOriginInfo(kOrigin1);
403 EXPECT_TRUE(origin1_info);
404 EXPECT_EQ(4, origin1_info->GetDatabaseSize(kDB3));
405 tracker->DatabaseClosed(kOrigin1, kDB3);
407 // Delete a database and make sure the space used by that origin is updated
408 EXPECT_TRUE(tracker->DeleteClosedDatabase(kOrigin1, kDB3));
409 origin1_info = tracker->GetCachedOriginInfo(kOrigin1);
410 EXPECT_TRUE(origin1_info);
411 EXPECT_EQ(1, origin1_info->GetDatabaseSize(kDB1));
412 EXPECT_EQ(0, origin1_info->GetDatabaseSize(kDB3));
414 // Get all data for all origins
415 std::vector<OriginInfo> origins_info;
416 EXPECT_TRUE(tracker->GetAllOriginsInfo(&origins_info));
417 EXPECT_EQ(size_t(2), origins_info.size());
418 EXPECT_EQ(kOrigin1, origins_info[0].GetOriginIdentifier());
419 EXPECT_EQ(1, origins_info[0].TotalSize());
420 EXPECT_EQ(1, origins_info[0].GetDatabaseSize(kDB1));
421 EXPECT_EQ(0, origins_info[0].GetDatabaseSize(kDB3));
423 EXPECT_EQ(kOrigin2, origins_info[1].GetOriginIdentifier());
424 EXPECT_EQ(2, origins_info[1].TotalSize());
426 // Trying to delete an origin with databases in use should fail
427 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
428 &database_size);
429 EXPECT_FALSE(tracker->DeleteOrigin(kOrigin1, false));
430 origin1_info = tracker->GetCachedOriginInfo(kOrigin1);
431 EXPECT_TRUE(origin1_info);
432 EXPECT_EQ(1, origin1_info->GetDatabaseSize(kDB1));
433 tracker->DatabaseClosed(kOrigin1, kDB1);
435 // Delete an origin that doesn't have any database in use
436 EXPECT_TRUE(tracker->DeleteOrigin(kOrigin1, false));
437 origins_info.clear();
438 EXPECT_TRUE(tracker->GetAllOriginsInfo(&origins_info));
439 EXPECT_EQ(size_t(1), origins_info.size());
440 EXPECT_EQ(kOrigin2, origins_info[0].GetOriginIdentifier());
442 origin1_info = tracker->GetCachedOriginInfo(kOrigin1);
443 EXPECT_TRUE(origin1_info);
444 EXPECT_EQ(0, origin1_info->TotalSize());
447 static void DatabaseTrackerQuotaIntegration() {
448 const GURL kOrigin(kOrigin1Url);
449 const std::string kOriginId =
450 webkit_database::GetIdentifierFromOrigin(kOrigin);
451 const base::string16 kName = ASCIIToUTF16("name");
452 const base::string16 kDescription = ASCIIToUTF16("description");
454 base::ScopedTempDir temp_dir;
455 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
457 // Initialize the tracker with a QuotaManagerProxy
458 scoped_refptr<TestQuotaManagerProxy> test_quota_proxy(
459 new TestQuotaManagerProxy);
460 scoped_refptr<DatabaseTracker> tracker(
461 new DatabaseTracker(temp_dir.path(),
462 false /* incognito */,
463 NULL,
464 test_quota_proxy.get(),
465 NULL));
466 EXPECT_TRUE(test_quota_proxy->registered_client_);
468 // Create a database and modify it a couple of times, close it,
469 // then delete it. Observe the tracker notifies accordingly.
471 int64 database_size = 0;
472 tracker->DatabaseOpened(kOriginId, kName, kDescription, 0,
473 &database_size);
474 EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin));
475 test_quota_proxy->reset();
477 base::FilePath db_file(tracker->GetFullDBFilePath(kOriginId, kName));
478 EXPECT_TRUE(file_util::CreateDirectory(db_file.DirName()));
479 EXPECT_TRUE(EnsureFileOfSize(db_file, 10));
480 tracker->DatabaseModified(kOriginId, kName);
481 EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, 10));
482 test_quota_proxy->reset();
484 EXPECT_TRUE(EnsureFileOfSize(db_file, 100));
485 tracker->DatabaseModified(kOriginId, kName);
486 EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, 90));
487 test_quota_proxy->reset();
489 tracker->DatabaseClosed(kOriginId, kName);
490 EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin));
491 EXPECT_EQ(net::OK, tracker->DeleteDatabase(
492 kOriginId, kName, net::CompletionCallback()));
493 EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, -100));
494 test_quota_proxy->reset();
496 // Create a database and modify it, try to delete it while open,
497 // then close it (at which time deletion will actually occur).
498 // Observe the tracker notifies accordingly.
500 tracker->DatabaseOpened(kOriginId, kName, kDescription, 0,
501 &database_size);
502 EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin));
503 test_quota_proxy->reset();
505 db_file = tracker->GetFullDBFilePath(kOriginId, kName);
506 EXPECT_TRUE(file_util::CreateDirectory(db_file.DirName()));
507 EXPECT_TRUE(EnsureFileOfSize(db_file, 100));
508 tracker->DatabaseModified(kOriginId, kName);
509 EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, 100));
510 test_quota_proxy->reset();
512 EXPECT_EQ(net::ERR_IO_PENDING,
513 tracker->DeleteDatabase(kOriginId, kName,
514 net::CompletionCallback()));
515 EXPECT_FALSE(test_quota_proxy->WasModificationNotified(kOrigin, -100));
517 tracker->DatabaseClosed(kOriginId, kName);
518 EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin));
519 EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, -100));
520 test_quota_proxy->reset();
522 // Create a database and up the file size without telling
523 // the tracker about the modification, than simulate a
524 // a renderer crash.
525 // Observe the tracker notifies accordingly.
527 tracker->DatabaseOpened(kOriginId, kName, kDescription, 0,
528 &database_size);
529 EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin));
530 test_quota_proxy->reset();
531 db_file = tracker->GetFullDBFilePath(kOriginId, kName);
532 EXPECT_TRUE(file_util::CreateDirectory(db_file.DirName()));
533 EXPECT_TRUE(EnsureFileOfSize(db_file, 100));
534 DatabaseConnections crashed_renderer_connections;
535 crashed_renderer_connections.AddConnection(kOriginId, kName);
536 EXPECT_FALSE(test_quota_proxy->WasModificationNotified(kOrigin, 100));
537 tracker->CloseDatabases(crashed_renderer_connections);
538 EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, 100));
540 // Cleanup.
541 crashed_renderer_connections.RemoveAllConnections();
542 test_quota_proxy->SimulateQuotaManagerDestroyed();
545 static void DatabaseTrackerClearSessionOnlyDatabasesOnExit() {
546 int64 database_size = 0;
547 const std::string kOrigin1 =
548 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin1Url));
549 const std::string kOrigin2 =
550 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin2Url));
551 const base::string16 kDB1 = ASCIIToUTF16("db1");
552 const base::string16 kDB2 = ASCIIToUTF16("db2");
553 const base::string16 kDescription = ASCIIToUTF16("database_description");
555 // Initialize the tracker database.
556 base::MessageLoop message_loop;
557 base::ScopedTempDir temp_dir;
558 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
559 base::FilePath origin1_db_dir;
560 base::FilePath origin2_db_dir;
562 scoped_refptr<quota::MockSpecialStoragePolicy> special_storage_policy =
563 new quota::MockSpecialStoragePolicy;
564 special_storage_policy->AddSessionOnly(GURL(kOrigin2Url));
565 scoped_refptr<DatabaseTracker> tracker(
566 new DatabaseTracker(temp_dir.path(),
567 false,
568 special_storage_policy.get(),
569 NULL,
570 base::MessageLoopProxy::current().get()));
572 // Open two new databases.
573 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
574 &database_size);
575 EXPECT_EQ(0, database_size);
576 tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0,
577 &database_size);
578 EXPECT_EQ(0, database_size);
580 // Write some data to each file.
581 base::FilePath db_file;
582 db_file = tracker->GetFullDBFilePath(kOrigin1, kDB1);
583 EXPECT_TRUE(file_util::CreateDirectory(db_file.DirName()));
584 EXPECT_TRUE(EnsureFileOfSize(db_file, 1));
586 db_file = tracker->GetFullDBFilePath(kOrigin2, kDB2);
587 EXPECT_TRUE(file_util::CreateDirectory(db_file.DirName()));
588 EXPECT_TRUE(EnsureFileOfSize(db_file, 2));
590 // Store the origin database directories as long as they still exist.
591 origin1_db_dir = tracker->GetFullDBFilePath(kOrigin1, kDB1).DirName();
592 origin2_db_dir = tracker->GetFullDBFilePath(kOrigin2, kDB2).DirName();
594 tracker->DatabaseModified(kOrigin1, kDB1);
595 tracker->DatabaseModified(kOrigin2, kDB2);
597 // Close all databases.
598 tracker->DatabaseClosed(kOrigin1, kDB1);
599 tracker->DatabaseClosed(kOrigin2, kDB2);
601 tracker->Shutdown();
604 // At this point, the database tracker should be gone. Create a new one.
605 scoped_refptr<DatabaseTracker> tracker(
606 new DatabaseTracker(temp_dir.path(), false, NULL, NULL, NULL));
608 // Get all data for all origins.
609 std::vector<OriginInfo> origins_info;
610 EXPECT_TRUE(tracker->GetAllOriginsInfo(&origins_info));
611 // kOrigin1 was not session-only, so it survived. kOrigin2 was session-only
612 // and it got deleted.
613 EXPECT_EQ(size_t(1), origins_info.size());
614 EXPECT_EQ(kOrigin1, origins_info[0].GetOriginIdentifier());
615 EXPECT_TRUE(
616 file_util::PathExists(tracker->GetFullDBFilePath(kOrigin1, kDB1)));
617 EXPECT_EQ(base::FilePath(), tracker->GetFullDBFilePath(kOrigin2, kDB2));
619 // The origin directory of kOrigin1 remains, but the origin directory of
620 // kOrigin2 is deleted.
621 EXPECT_TRUE(file_util::PathExists(origin1_db_dir));
622 EXPECT_FALSE(file_util::PathExists(origin2_db_dir));
625 static void DatabaseTrackerSetForceKeepSessionState() {
626 int64 database_size = 0;
627 const std::string kOrigin1 =
628 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin1Url));
629 const std::string kOrigin2 =
630 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin2Url));
631 const base::string16 kDB1 = ASCIIToUTF16("db1");
632 const base::string16 kDB2 = ASCIIToUTF16("db2");
633 const base::string16 kDescription = ASCIIToUTF16("database_description");
635 // Initialize the tracker database.
636 base::MessageLoop message_loop;
637 base::ScopedTempDir temp_dir;
638 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
639 base::FilePath origin1_db_dir;
640 base::FilePath origin2_db_dir;
642 scoped_refptr<quota::MockSpecialStoragePolicy> special_storage_policy =
643 new quota::MockSpecialStoragePolicy;
644 special_storage_policy->AddSessionOnly(GURL(kOrigin2Url));
645 scoped_refptr<DatabaseTracker> tracker(
646 new DatabaseTracker(temp_dir.path(),
647 false,
648 special_storage_policy.get(),
649 NULL,
650 base::MessageLoopProxy::current().get()));
651 tracker->SetForceKeepSessionState();
653 // Open two new databases.
654 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
655 &database_size);
656 EXPECT_EQ(0, database_size);
657 tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0,
658 &database_size);
659 EXPECT_EQ(0, database_size);
661 // Write some data to each file.
662 base::FilePath db_file;
663 db_file = tracker->GetFullDBFilePath(kOrigin1, kDB1);
664 EXPECT_TRUE(file_util::CreateDirectory(db_file.DirName()));
665 EXPECT_TRUE(EnsureFileOfSize(db_file, 1));
667 db_file = tracker->GetFullDBFilePath(kOrigin2, kDB2);
668 EXPECT_TRUE(file_util::CreateDirectory(db_file.DirName()));
669 EXPECT_TRUE(EnsureFileOfSize(db_file, 2));
671 // Store the origin database directories as long as they still exist.
672 origin1_db_dir = tracker->GetFullDBFilePath(kOrigin1, kDB1).DirName();
673 origin2_db_dir = tracker->GetFullDBFilePath(kOrigin2, kDB2).DirName();
675 tracker->DatabaseModified(kOrigin1, kDB1);
676 tracker->DatabaseModified(kOrigin2, kDB2);
678 // Close all databases.
679 tracker->DatabaseClosed(kOrigin1, kDB1);
680 tracker->DatabaseClosed(kOrigin2, kDB2);
682 tracker->Shutdown();
685 // At this point, the database tracker should be gone. Create a new one.
686 scoped_refptr<DatabaseTracker> tracker(
687 new DatabaseTracker(temp_dir.path(), false, NULL, NULL, NULL));
689 // Get all data for all origins.
690 std::vector<OriginInfo> origins_info;
691 EXPECT_TRUE(tracker->GetAllOriginsInfo(&origins_info));
692 // No origins were deleted.
693 EXPECT_EQ(size_t(2), origins_info.size());
694 EXPECT_TRUE(
695 file_util::PathExists(tracker->GetFullDBFilePath(kOrigin1, kDB1)));
696 EXPECT_TRUE(
697 file_util::PathExists(tracker->GetFullDBFilePath(kOrigin2, kDB2)));
699 EXPECT_TRUE(file_util::PathExists(origin1_db_dir));
700 EXPECT_TRUE(file_util::PathExists(origin2_db_dir));
703 static void EmptyDatabaseNameIsValid() {
704 const GURL kOrigin(kOrigin1Url);
705 const std::string kOriginId =
706 webkit_database::GetIdentifierFromOrigin(kOrigin);
707 const base::string16 kEmptyName;
708 const base::string16 kDescription(ASCIIToUTF16("description"));
709 const base::string16 kChangedDescription(
710 ASCIIToUTF16("changed_description"));
712 // Initialize a tracker database, no need to put it on disk.
713 const bool kUseInMemoryTrackerDatabase = true;
714 base::ScopedTempDir temp_dir;
715 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
716 scoped_refptr<DatabaseTracker> tracker(
717 new DatabaseTracker(temp_dir.path(), kUseInMemoryTrackerDatabase,
718 NULL, NULL, NULL));
720 // Starts off with no databases.
721 std::vector<OriginInfo> infos;
722 EXPECT_TRUE(tracker->GetAllOriginsInfo(&infos));
723 EXPECT_TRUE(infos.empty());
725 // Create a db with an empty name.
726 int64 database_size = -1;
727 tracker->DatabaseOpened(kOriginId, kEmptyName, kDescription, 0,
728 &database_size);
729 EXPECT_EQ(0, database_size);
730 tracker->DatabaseModified(kOriginId, kEmptyName);
731 EXPECT_TRUE(tracker->GetAllOriginsInfo(&infos));
732 EXPECT_EQ(1u, infos.size());
733 EXPECT_EQ(kDescription, infos[0].GetDatabaseDescription(kEmptyName));
734 EXPECT_FALSE(tracker->GetFullDBFilePath(kOriginId, kEmptyName).empty());
735 tracker->DatabaseOpened(kOriginId, kEmptyName, kChangedDescription, 0,
736 &database_size);
737 infos.clear();
738 EXPECT_TRUE(tracker->GetAllOriginsInfo(&infos));
739 EXPECT_EQ(1u, infos.size());
740 EXPECT_EQ(kChangedDescription, infos[0].GetDatabaseDescription(kEmptyName));
741 tracker->DatabaseClosed(kOriginId, kEmptyName);
742 tracker->DatabaseClosed(kOriginId, kEmptyName);
744 // Deleting it should return to the initial state.
745 EXPECT_EQ(net::OK, tracker->DeleteDatabase(kOriginId, kEmptyName,
746 net::CompletionCallback()));
747 infos.clear();
748 EXPECT_TRUE(tracker->GetAllOriginsInfo(&infos));
749 EXPECT_TRUE(infos.empty());
752 static void HandleSqliteError() {
753 const GURL kOrigin(kOrigin1Url);
754 const std::string kOriginId =
755 webkit_database::GetIdentifierFromOrigin(kOrigin);
756 const base::string16 kName(ASCIIToUTF16("name"));
757 const base::string16 kDescription(ASCIIToUTF16("description"));
759 // Initialize a tracker database, no need to put it on disk.
760 const bool kUseInMemoryTrackerDatabase = true;
761 base::ScopedTempDir temp_dir;
762 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
763 scoped_refptr<DatabaseTracker> tracker(
764 new DatabaseTracker(temp_dir.path(), kUseInMemoryTrackerDatabase,
765 NULL, NULL, NULL));
767 // Setup to observe OnScheduledForDelete notifications.
768 TestObserver observer(false, true);
769 tracker->AddObserver(&observer);
771 // Verify does no harm when there is no such database.
772 tracker->HandleSqliteError(kOriginId, kName, SQLITE_CORRUPT);
773 EXPECT_FALSE(tracker->IsDatabaseScheduledForDeletion(kOriginId, kName));
774 EXPECT_FALSE(observer.DidReceiveNewNotification());
776 // --------------------------------------------------------
777 // Create a record of a database in the tracker db and create
778 // a spoof_db_file on disk in the expected location.
779 int64 database_size = 0;
780 tracker->DatabaseOpened(kOriginId, kName, kDescription, 0,
781 &database_size);
782 base::FilePath spoof_db_file = tracker->GetFullDBFilePath(kOriginId, kName);
783 EXPECT_FALSE(tracker->GetFullDBFilePath(kOriginId, kName).empty());
784 EXPECT_TRUE(file_util::CreateDirectory(spoof_db_file.DirName()));
785 EXPECT_TRUE(EnsureFileOfSize(spoof_db_file, 1));
787 // Verify does no harm with a non-error is reported.
788 tracker->HandleSqliteError(kOriginId, kName, SQLITE_OK);
789 EXPECT_FALSE(tracker->IsDatabaseScheduledForDeletion(kOriginId, kName));
790 EXPECT_FALSE(observer.DidReceiveNewNotification());
792 // Verify that with a connection open, the db is scheduled for deletion,
793 // but that the file still exists.
794 tracker->HandleSqliteError(kOriginId, kName, SQLITE_CORRUPT);
795 EXPECT_TRUE(tracker->IsDatabaseScheduledForDeletion(kOriginId, kName));
796 EXPECT_TRUE(observer.DidReceiveNewNotification());
797 EXPECT_TRUE(file_util::PathExists(spoof_db_file));
799 // Verify that once closed, the file is deleted and the record in the
800 // tracker db is removed.
801 tracker->DatabaseClosed(kOriginId, kName);
802 EXPECT_FALSE(file_util::PathExists(spoof_db_file));
803 EXPECT_TRUE(tracker->GetFullDBFilePath(kOriginId, kName).empty());
805 // --------------------------------------------------------
806 // Create another record of a database in the tracker db and create
807 // a spoof_db_file on disk in the expected location.
808 tracker->DatabaseOpened(kOriginId, kName, kDescription, 0,
809 &database_size);
810 base::FilePath spoof_db_file2 = tracker->GetFullDBFilePath(kOriginId, kName);
811 EXPECT_FALSE(tracker->GetFullDBFilePath(kOriginId, kName).empty());
812 EXPECT_NE(spoof_db_file, spoof_db_file2);
813 EXPECT_TRUE(file_util::CreateDirectory(spoof_db_file2.DirName()));
814 EXPECT_TRUE(EnsureFileOfSize(spoof_db_file2, 1));
816 // Verify that with no connection open, the db is deleted immediately.
817 tracker->DatabaseClosed(kOriginId, kName);
818 tracker->HandleSqliteError(kOriginId, kName, SQLITE_CORRUPT);
819 EXPECT_FALSE(tracker->IsDatabaseScheduledForDeletion(kOriginId, kName));
820 EXPECT_FALSE(observer.DidReceiveNewNotification());
821 EXPECT_TRUE(tracker->GetFullDBFilePath(kOriginId, kName).empty());
822 EXPECT_FALSE(file_util::PathExists(spoof_db_file2));
824 tracker->RemoveObserver(&observer);
828 TEST(DatabaseTrackerTest, DeleteOpenDatabase) {
829 DatabaseTracker_TestHelper_Test::TestDeleteOpenDatabase(false);
832 TEST(DatabaseTrackerTest, DeleteOpenDatabaseIncognitoMode) {
833 DatabaseTracker_TestHelper_Test::TestDeleteOpenDatabase(true);
836 TEST(DatabaseTrackerTest, DatabaseTracker) {
837 DatabaseTracker_TestHelper_Test::TestDatabaseTracker(false);
840 TEST(DatabaseTrackerTest, DatabaseTrackerIncognitoMode) {
841 DatabaseTracker_TestHelper_Test::TestDatabaseTracker(true);
844 TEST(DatabaseTrackerTest, DatabaseTrackerQuotaIntegration) {
845 // There is no difference in behavior between incognito and not.
846 DatabaseTracker_TestHelper_Test::DatabaseTrackerQuotaIntegration();
849 TEST(DatabaseTrackerTest, DatabaseTrackerClearSessionOnlyDatabasesOnExit) {
850 // Only works for regular mode.
851 DatabaseTracker_TestHelper_Test::
852 DatabaseTrackerClearSessionOnlyDatabasesOnExit();
855 TEST(DatabaseTrackerTest, DatabaseTrackerSetForceKeepSessionState) {
856 // Only works for regular mode.
857 DatabaseTracker_TestHelper_Test::DatabaseTrackerSetForceKeepSessionState();
860 TEST(DatabaseTrackerTest, EmptyDatabaseNameIsValid) {
861 DatabaseTracker_TestHelper_Test::EmptyDatabaseNameIsValid();
864 TEST(DatabaseTrackerTest, HandleSqliteError) {
865 DatabaseTracker_TestHelper_Test::HandleSqliteError();
868 } // namespace webkit_database