1 // Copyright 2014 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.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 "content/public/test/mock_special_storage_policy.h"
15 #include "net/base/net_errors.h"
16 #include "net/base/test_completion_callback.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "third_party/sqlite/sqlite3.h"
19 #include "webkit/browser/database/database_tracker.h"
20 #include "webkit/browser/quota/quota_manager_proxy.h"
21 #include "webkit/common/database/database_identifier.h"
23 using base::ASCIIToUTF16
;
24 using webkit_database::DatabaseConnections
;
25 using webkit_database::DatabaseTracker
;
26 using webkit_database::OriginInfo
;
30 const char kOrigin1Url
[] = "http://origin1";
31 const char kOrigin2Url
[] = "http://protected_origin2";
33 class TestObserver
: public webkit_database::DatabaseTracker::Observer
{
36 : new_notification_received_(false),
37 observe_size_changes_(true),
38 observe_scheduled_deletions_(true) {
40 TestObserver(bool observe_size_changes
, bool observe_scheduled_deletions
)
41 : new_notification_received_(false),
42 observe_size_changes_(observe_size_changes
),
43 observe_scheduled_deletions_(observe_scheduled_deletions
) {
46 virtual ~TestObserver() {}
47 virtual void OnDatabaseSizeChanged(const std::string
& origin_identifier
,
48 const base::string16
& database_name
,
49 int64 database_size
) OVERRIDE
{
50 if (!observe_size_changes_
)
52 new_notification_received_
= true;
53 origin_identifier_
= origin_identifier
;
54 database_name_
= database_name
;
55 database_size_
= database_size
;
57 virtual void OnDatabaseScheduledForDeletion(
58 const std::string
& origin_identifier
,
59 const base::string16
& database_name
) OVERRIDE
{
60 if (!observe_scheduled_deletions_
)
62 new_notification_received_
= true;
63 origin_identifier_
= origin_identifier
;
64 database_name_
= database_name
;
66 bool DidReceiveNewNotification() {
67 bool temp_new_notification_received
= new_notification_received_
;
68 new_notification_received_
= false;
69 return temp_new_notification_received
;
71 std::string
GetNotificationOriginIdentifier() {
72 return origin_identifier_
;
74 base::string16
GetNotificationDatabaseName() { return database_name_
; }
75 int64
GetNotificationDatabaseSize() { return database_size_
; }
78 bool new_notification_received_
;
79 bool observe_size_changes_
;
80 bool observe_scheduled_deletions_
;
81 std::string origin_identifier_
;
82 base::string16 database_name_
;
86 void CheckNotificationReceived(TestObserver
* observer
,
87 const std::string
& expected_origin_identifier
,
88 const base::string16
& expected_database_name
,
89 int64 expected_database_size
) {
90 EXPECT_TRUE(observer
->DidReceiveNewNotification());
91 EXPECT_EQ(expected_origin_identifier
,
92 observer
->GetNotificationOriginIdentifier());
93 EXPECT_EQ(expected_database_name
,
94 observer
->GetNotificationDatabaseName());
95 EXPECT_EQ(expected_database_size
,
96 observer
->GetNotificationDatabaseSize());
99 class TestQuotaManagerProxy
: public quota::QuotaManagerProxy
{
101 TestQuotaManagerProxy()
102 : QuotaManagerProxy(NULL
, NULL
),
103 registered_client_(NULL
) {
106 virtual void RegisterClient(quota::QuotaClient
* client
) OVERRIDE
{
107 EXPECT_FALSE(registered_client_
);
108 registered_client_
= client
;
111 virtual void NotifyStorageAccessed(quota::QuotaClient::ID client_id
,
113 quota::StorageType type
) OVERRIDE
{
114 EXPECT_EQ(quota::QuotaClient::kDatabase
, client_id
);
115 EXPECT_EQ(quota::kStorageTypeTemporary
, type
);
116 accesses_
[origin
] += 1;
119 virtual void NotifyStorageModified(quota::QuotaClient::ID client_id
,
121 quota::StorageType type
,
122 int64 delta
) OVERRIDE
{
123 EXPECT_EQ(quota::QuotaClient::kDatabase
, client_id
);
124 EXPECT_EQ(quota::kStorageTypeTemporary
, type
);
125 modifications_
[origin
].first
+= 1;
126 modifications_
[origin
].second
+= delta
;
129 // Not needed for our tests.
130 virtual void NotifyOriginInUse(const GURL
& origin
) OVERRIDE
{}
131 virtual void NotifyOriginNoLongerInUse(const GURL
& origin
) OVERRIDE
{}
132 virtual void SetUsageCacheEnabled(quota::QuotaClient::ID client_id
,
134 quota::StorageType type
,
135 bool enabled
) OVERRIDE
{}
136 virtual void GetUsageAndQuota(
137 base::SequencedTaskRunner
* original_task_runner
,
139 quota::StorageType type
,
140 const GetUsageAndQuotaCallback
& callback
) OVERRIDE
{}
142 void SimulateQuotaManagerDestroyed() {
143 if (registered_client_
) {
144 registered_client_
->OnQuotaManagerDestroyed();
145 registered_client_
= NULL
;
149 bool WasAccessNotified(const GURL
& origin
) {
150 return accesses_
[origin
] != 0;
153 bool WasModificationNotified(const GURL
& origin
, int64 amount
) {
154 return modifications_
[origin
].first
!= 0 &&
155 modifications_
[origin
].second
== amount
;
160 modifications_
.clear();
163 quota::QuotaClient
* registered_client_
;
165 // Map from origin to count of access notifications.
166 std::map
<GURL
, int> accesses_
;
168 // Map from origin to <count, sum of deltas>
169 std::map
<GURL
, std::pair
<int, int64
> > modifications_
;
172 virtual ~TestQuotaManagerProxy() {
173 EXPECT_FALSE(registered_client_
);
178 bool EnsureFileOfSize(const base::FilePath
& file_path
, int64 length
) {
179 base::File
file(file_path
,
180 base::File::FLAG_OPEN_ALWAYS
| base::File::FLAG_WRITE
);
183 return file
.SetLength(length
);
190 // We declare a helper class, and make it a friend of DatabaseTracker using
191 // the FORWARD_DECLARE_TEST macro, and we implement all tests we want to run as
192 // static methods of this class. Then we make our TEST() targets call these
193 // static functions. This allows us to run each test in normal mode and
194 // incognito mode without writing the same code twice.
195 class DatabaseTracker_TestHelper_Test
{
197 static void TestDeleteOpenDatabase(bool incognito_mode
) {
198 // Initialize the tracker database.
199 base::ScopedTempDir temp_dir
;
200 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
201 scoped_refptr
<MockSpecialStoragePolicy
> special_storage_policy
=
202 new MockSpecialStoragePolicy
;
203 special_storage_policy
->AddProtected(GURL(kOrigin2Url
));
204 scoped_refptr
<DatabaseTracker
> tracker(
205 new DatabaseTracker(temp_dir
.path(),
207 special_storage_policy
.get(),
211 // Create and open three databases.
212 int64 database_size
= 0;
213 const std::string kOrigin1
=
214 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin1Url
));
215 const std::string kOrigin2
=
216 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin2Url
));
217 const base::string16 kDB1
= ASCIIToUTF16("db1");
218 const base::string16 kDB2
= ASCIIToUTF16("db2");
219 const base::string16 kDB3
= ASCIIToUTF16("db3");
220 const base::string16 kDescription
= ASCIIToUTF16("database_description");
222 tracker
->DatabaseOpened(kOrigin1
, kDB1
, kDescription
, 0,
224 tracker
->DatabaseOpened(kOrigin2
, kDB2
, kDescription
, 0,
226 tracker
->DatabaseOpened(kOrigin2
, kDB3
, kDescription
, 0,
229 EXPECT_TRUE(base::CreateDirectory(
230 tracker
->DatabaseDirectory().Append(base::FilePath::FromUTF16Unsafe(
231 tracker
->GetOriginDirectory(kOrigin1
)))));
232 EXPECT_TRUE(base::CreateDirectory(
233 tracker
->DatabaseDirectory().Append(base::FilePath::FromUTF16Unsafe(
234 tracker
->GetOriginDirectory(kOrigin2
)))));
235 EXPECT_EQ(1, base::WriteFile(
236 tracker
->GetFullDBFilePath(kOrigin1
, kDB1
), "a", 1));
237 EXPECT_EQ(2, base::WriteFile(
238 tracker
->GetFullDBFilePath(kOrigin2
, kDB2
), "aa", 2));
239 EXPECT_EQ(3, base::WriteFile(
240 tracker
->GetFullDBFilePath(kOrigin2
, kDB3
), "aaa", 3));
241 tracker
->DatabaseModified(kOrigin1
, kDB1
);
242 tracker
->DatabaseModified(kOrigin2
, kDB2
);
243 tracker
->DatabaseModified(kOrigin2
, kDB3
);
245 // Delete db1. Should also delete origin1.
246 TestObserver observer
;
247 tracker
->AddObserver(&observer
);
248 net::TestCompletionCallback callback
;
249 int result
= tracker
->DeleteDatabase(kOrigin1
, kDB1
, callback
.callback());
250 EXPECT_EQ(net::ERR_IO_PENDING
, result
);
251 ASSERT_FALSE(callback
.have_result());
252 EXPECT_TRUE(observer
.DidReceiveNewNotification());
253 EXPECT_EQ(kOrigin1
, observer
.GetNotificationOriginIdentifier());
254 EXPECT_EQ(kDB1
, observer
.GetNotificationDatabaseName());
255 tracker
->DatabaseClosed(kOrigin1
, kDB1
);
256 result
= callback
.GetResult(result
);
257 EXPECT_EQ(net::OK
, result
);
258 EXPECT_FALSE(base::PathExists(
259 tracker
->DatabaseDirectory().AppendASCII(kOrigin1
)));
262 tracker
->DatabaseOpened(kOrigin1
, kDB1
, kDescription
, 0,
264 EXPECT_TRUE(base::CreateDirectory(
265 tracker
->DatabaseDirectory().Append(base::FilePath::FromUTF16Unsafe(
266 tracker
->GetOriginDirectory(kOrigin1
)))));
267 EXPECT_EQ(1, base::WriteFile(
268 tracker
->GetFullDBFilePath(kOrigin1
, kDB1
), "a", 1));
269 tracker
->DatabaseModified(kOrigin1
, kDB1
);
271 // Setup file modification times. db1 and db2 are modified now, db3 three
273 base::Time now
= base::Time::Now();
274 EXPECT_TRUE(base::TouchFile(tracker
->GetFullDBFilePath(kOrigin1
, kDB1
),
276 EXPECT_TRUE(base::TouchFile(tracker
->GetFullDBFilePath(kOrigin2
, kDB2
),
278 base::Time three_days_ago
= now
- base::TimeDelta::FromDays(3);
279 EXPECT_TRUE(base::TouchFile(tracker
->GetFullDBFilePath(kOrigin2
, kDB3
),
280 three_days_ago
, three_days_ago
));
282 // Delete databases modified since yesterday. db2 is whitelisted.
283 base::Time yesterday
= base::Time::Now();
284 yesterday
-= base::TimeDelta::FromDays(1);
285 result
= tracker
->DeleteDataModifiedSince(
286 yesterday
, callback
.callback());
287 EXPECT_EQ(net::ERR_IO_PENDING
, result
);
288 ASSERT_FALSE(callback
.have_result());
289 EXPECT_TRUE(observer
.DidReceiveNewNotification());
290 tracker
->DatabaseClosed(kOrigin1
, kDB1
);
291 tracker
->DatabaseClosed(kOrigin2
, kDB2
);
292 result
= callback
.GetResult(result
);
293 EXPECT_EQ(net::OK
, result
);
294 EXPECT_FALSE(base::PathExists(
295 tracker
->DatabaseDirectory().AppendASCII(kOrigin1
)));
297 base::PathExists(tracker
->GetFullDBFilePath(kOrigin2
, kDB2
)));
299 base::PathExists(tracker
->GetFullDBFilePath(kOrigin2
, kDB3
)));
301 tracker
->DatabaseClosed(kOrigin2
, kDB3
);
302 tracker
->RemoveObserver(&observer
);
305 static void TestDatabaseTracker(bool incognito_mode
) {
306 // Initialize the tracker database.
307 base::ScopedTempDir temp_dir
;
308 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
309 scoped_refptr
<MockSpecialStoragePolicy
> special_storage_policy
=
310 new MockSpecialStoragePolicy
;
311 special_storage_policy
->AddProtected(GURL(kOrigin2Url
));
312 scoped_refptr
<DatabaseTracker
> tracker(
313 new DatabaseTracker(temp_dir
.path(),
315 special_storage_policy
.get(),
319 // Add two observers.
320 TestObserver observer1
;
321 TestObserver observer2
;
322 tracker
->AddObserver(&observer1
);
323 tracker
->AddObserver(&observer2
);
325 // Open three new databases.
326 int64 database_size
= 0;
327 const std::string kOrigin1
=
328 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin1Url
));
329 const std::string kOrigin2
=
330 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin2Url
));
331 const base::string16 kDB1
= ASCIIToUTF16("db1");
332 const base::string16 kDB2
= ASCIIToUTF16("db2");
333 const base::string16 kDB3
= ASCIIToUTF16("db3");
334 const base::string16 kDescription
= ASCIIToUTF16("database_description");
336 // Get the info for kOrigin1 and kOrigin2
337 DatabaseTracker::CachedOriginInfo
* origin1_info
=
338 tracker
->GetCachedOriginInfo(kOrigin1
);
339 DatabaseTracker::CachedOriginInfo
* origin2_info
=
340 tracker
->GetCachedOriginInfo(kOrigin1
);
341 EXPECT_TRUE(origin1_info
);
342 EXPECT_TRUE(origin2_info
);
345 tracker
->DatabaseOpened(kOrigin1
, kDB1
, kDescription
, 0,
347 EXPECT_EQ(0, database_size
);
348 tracker
->DatabaseOpened(kOrigin2
, kDB2
, kDescription
, 0,
350 EXPECT_EQ(0, database_size
);
351 tracker
->DatabaseOpened(kOrigin1
, kDB3
, kDescription
, 0,
353 EXPECT_EQ(0, database_size
);
355 // Write some data to each file and check that the listeners are
356 // called with the appropriate values.
357 EXPECT_TRUE(base::CreateDirectory(
358 tracker
->DatabaseDirectory().Append(base::FilePath::FromUTF16Unsafe(
359 tracker
->GetOriginDirectory(kOrigin1
)))));
360 EXPECT_TRUE(base::CreateDirectory(
361 tracker
->DatabaseDirectory().Append(base::FilePath::FromUTF16Unsafe(
362 tracker
->GetOriginDirectory(kOrigin2
)))));
363 EXPECT_EQ(1, base::WriteFile(
364 tracker
->GetFullDBFilePath(kOrigin1
, kDB1
), "a", 1));
365 EXPECT_EQ(2, base::WriteFile(
366 tracker
->GetFullDBFilePath(kOrigin2
, kDB2
), "aa", 2));
367 EXPECT_EQ(4, base::WriteFile(
368 tracker
->GetFullDBFilePath(kOrigin1
, kDB3
), "aaaa", 4));
369 tracker
->DatabaseModified(kOrigin1
, kDB1
);
370 CheckNotificationReceived(&observer1
, kOrigin1
, kDB1
, 1);
371 CheckNotificationReceived(&observer2
, kOrigin1
, kDB1
, 1);
372 tracker
->DatabaseModified(kOrigin2
, kDB2
);
373 CheckNotificationReceived(&observer1
, kOrigin2
, kDB2
, 2);
374 CheckNotificationReceived(&observer2
, kOrigin2
, kDB2
, 2);
375 tracker
->DatabaseModified(kOrigin1
, kDB3
);
376 CheckNotificationReceived(&observer1
, kOrigin1
, kDB3
, 4);
377 CheckNotificationReceived(&observer2
, kOrigin1
, kDB3
, 4);
379 // Close all databases
380 tracker
->DatabaseClosed(kOrigin1
, kDB1
);
381 tracker
->DatabaseClosed(kOrigin2
, kDB2
);
382 tracker
->DatabaseClosed(kOrigin1
, kDB3
);
384 // Open an existing database and check the reported size
385 tracker
->DatabaseOpened(kOrigin1
, kDB1
, kDescription
, 0,
387 EXPECT_EQ(1, database_size
);
388 tracker
->DatabaseClosed(kOrigin1
, kDB1
);
390 // Remove an observer; this should clear all caches.
391 tracker
->RemoveObserver(&observer2
);
393 // Close the tracker database and clear all caches.
394 // Then make sure that DatabaseOpened() still returns the correct result.
395 tracker
->CloseTrackerDatabaseAndClearCaches();
396 tracker
->DatabaseOpened(kOrigin1
, kDB1
, kDescription
, 0,
398 EXPECT_EQ(1, database_size
);
399 tracker
->DatabaseClosed(kOrigin1
, kDB1
);
401 // Remove all observers.
402 tracker
->RemoveObserver(&observer1
);
404 // Trying to delete a database in use should fail
405 tracker
->DatabaseOpened(kOrigin1
, kDB3
, kDescription
, 0,
407 EXPECT_FALSE(tracker
->DeleteClosedDatabase(kOrigin1
, kDB3
));
408 origin1_info
= tracker
->GetCachedOriginInfo(kOrigin1
);
409 EXPECT_TRUE(origin1_info
);
410 EXPECT_EQ(4, origin1_info
->GetDatabaseSize(kDB3
));
411 tracker
->DatabaseClosed(kOrigin1
, kDB3
);
413 // Delete a database and make sure the space used by that origin is updated
414 EXPECT_TRUE(tracker
->DeleteClosedDatabase(kOrigin1
, kDB3
));
415 origin1_info
= tracker
->GetCachedOriginInfo(kOrigin1
);
416 EXPECT_TRUE(origin1_info
);
417 EXPECT_EQ(1, origin1_info
->GetDatabaseSize(kDB1
));
418 EXPECT_EQ(0, origin1_info
->GetDatabaseSize(kDB3
));
420 // Get all data for all origins
421 std::vector
<OriginInfo
> origins_info
;
422 EXPECT_TRUE(tracker
->GetAllOriginsInfo(&origins_info
));
423 EXPECT_EQ(size_t(2), origins_info
.size());
424 EXPECT_EQ(kOrigin1
, origins_info
[0].GetOriginIdentifier());
425 EXPECT_EQ(1, origins_info
[0].TotalSize());
426 EXPECT_EQ(1, origins_info
[0].GetDatabaseSize(kDB1
));
427 EXPECT_EQ(0, origins_info
[0].GetDatabaseSize(kDB3
));
429 EXPECT_EQ(kOrigin2
, origins_info
[1].GetOriginIdentifier());
430 EXPECT_EQ(2, origins_info
[1].TotalSize());
432 // Trying to delete an origin with databases in use should fail
433 tracker
->DatabaseOpened(kOrigin1
, kDB1
, kDescription
, 0,
435 EXPECT_FALSE(tracker
->DeleteOrigin(kOrigin1
, false));
436 origin1_info
= tracker
->GetCachedOriginInfo(kOrigin1
);
437 EXPECT_TRUE(origin1_info
);
438 EXPECT_EQ(1, origin1_info
->GetDatabaseSize(kDB1
));
439 tracker
->DatabaseClosed(kOrigin1
, kDB1
);
441 // Delete an origin that doesn't have any database in use
442 EXPECT_TRUE(tracker
->DeleteOrigin(kOrigin1
, false));
443 origins_info
.clear();
444 EXPECT_TRUE(tracker
->GetAllOriginsInfo(&origins_info
));
445 EXPECT_EQ(size_t(1), origins_info
.size());
446 EXPECT_EQ(kOrigin2
, origins_info
[0].GetOriginIdentifier());
448 origin1_info
= tracker
->GetCachedOriginInfo(kOrigin1
);
449 EXPECT_TRUE(origin1_info
);
450 EXPECT_EQ(0, origin1_info
->TotalSize());
453 static void DatabaseTrackerQuotaIntegration() {
454 const GURL
kOrigin(kOrigin1Url
);
455 const std::string kOriginId
=
456 webkit_database::GetIdentifierFromOrigin(kOrigin
);
457 const base::string16 kName
= ASCIIToUTF16("name");
458 const base::string16 kDescription
= ASCIIToUTF16("description");
460 base::ScopedTempDir temp_dir
;
461 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
463 // Initialize the tracker with a QuotaManagerProxy
464 scoped_refptr
<TestQuotaManagerProxy
> test_quota_proxy(
465 new TestQuotaManagerProxy
);
466 scoped_refptr
<DatabaseTracker
> tracker(
467 new DatabaseTracker(temp_dir
.path(),
468 false /* incognito */,
470 test_quota_proxy
.get(),
472 EXPECT_TRUE(test_quota_proxy
->registered_client_
);
474 // Create a database and modify it a couple of times, close it,
475 // then delete it. Observe the tracker notifies accordingly.
477 int64 database_size
= 0;
478 tracker
->DatabaseOpened(kOriginId
, kName
, kDescription
, 0,
480 EXPECT_TRUE(test_quota_proxy
->WasAccessNotified(kOrigin
));
481 test_quota_proxy
->reset();
483 base::FilePath
db_file(tracker
->GetFullDBFilePath(kOriginId
, kName
));
484 EXPECT_TRUE(base::CreateDirectory(db_file
.DirName()));
485 EXPECT_TRUE(EnsureFileOfSize(db_file
, 10));
486 tracker
->DatabaseModified(kOriginId
, kName
);
487 EXPECT_TRUE(test_quota_proxy
->WasModificationNotified(kOrigin
, 10));
488 test_quota_proxy
->reset();
490 EXPECT_TRUE(EnsureFileOfSize(db_file
, 100));
491 tracker
->DatabaseModified(kOriginId
, kName
);
492 EXPECT_TRUE(test_quota_proxy
->WasModificationNotified(kOrigin
, 90));
493 test_quota_proxy
->reset();
495 tracker
->DatabaseClosed(kOriginId
, kName
);
496 EXPECT_TRUE(test_quota_proxy
->WasAccessNotified(kOrigin
));
497 EXPECT_EQ(net::OK
, tracker
->DeleteDatabase(
498 kOriginId
, kName
, net::CompletionCallback()));
499 EXPECT_TRUE(test_quota_proxy
->WasModificationNotified(kOrigin
, -100));
500 test_quota_proxy
->reset();
502 // Create a database and modify it, try to delete it while open,
503 // then close it (at which time deletion will actually occur).
504 // Observe the tracker notifies accordingly.
506 tracker
->DatabaseOpened(kOriginId
, kName
, kDescription
, 0,
508 EXPECT_TRUE(test_quota_proxy
->WasAccessNotified(kOrigin
));
509 test_quota_proxy
->reset();
511 db_file
= tracker
->GetFullDBFilePath(kOriginId
, kName
);
512 EXPECT_TRUE(base::CreateDirectory(db_file
.DirName()));
513 EXPECT_TRUE(EnsureFileOfSize(db_file
, 100));
514 tracker
->DatabaseModified(kOriginId
, kName
);
515 EXPECT_TRUE(test_quota_proxy
->WasModificationNotified(kOrigin
, 100));
516 test_quota_proxy
->reset();
518 EXPECT_EQ(net::ERR_IO_PENDING
,
519 tracker
->DeleteDatabase(kOriginId
, kName
,
520 net::CompletionCallback()));
521 EXPECT_FALSE(test_quota_proxy
->WasModificationNotified(kOrigin
, -100));
523 tracker
->DatabaseClosed(kOriginId
, kName
);
524 EXPECT_TRUE(test_quota_proxy
->WasAccessNotified(kOrigin
));
525 EXPECT_TRUE(test_quota_proxy
->WasModificationNotified(kOrigin
, -100));
526 test_quota_proxy
->reset();
528 // Create a database and up the file size without telling
529 // the tracker about the modification, than simulate a
531 // Observe the tracker notifies accordingly.
533 tracker
->DatabaseOpened(kOriginId
, kName
, kDescription
, 0,
535 EXPECT_TRUE(test_quota_proxy
->WasAccessNotified(kOrigin
));
536 test_quota_proxy
->reset();
537 db_file
= tracker
->GetFullDBFilePath(kOriginId
, kName
);
538 EXPECT_TRUE(base::CreateDirectory(db_file
.DirName()));
539 EXPECT_TRUE(EnsureFileOfSize(db_file
, 100));
540 DatabaseConnections crashed_renderer_connections
;
541 crashed_renderer_connections
.AddConnection(kOriginId
, kName
);
542 EXPECT_FALSE(test_quota_proxy
->WasModificationNotified(kOrigin
, 100));
543 tracker
->CloseDatabases(crashed_renderer_connections
);
544 EXPECT_TRUE(test_quota_proxy
->WasModificationNotified(kOrigin
, 100));
547 crashed_renderer_connections
.RemoveAllConnections();
548 test_quota_proxy
->SimulateQuotaManagerDestroyed();
551 static void DatabaseTrackerClearSessionOnlyDatabasesOnExit() {
552 int64 database_size
= 0;
553 const std::string kOrigin1
=
554 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin1Url
));
555 const std::string kOrigin2
=
556 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin2Url
));
557 const base::string16 kDB1
= ASCIIToUTF16("db1");
558 const base::string16 kDB2
= ASCIIToUTF16("db2");
559 const base::string16 kDescription
= ASCIIToUTF16("database_description");
561 // Initialize the tracker database.
562 base::MessageLoop message_loop
;
563 base::ScopedTempDir temp_dir
;
564 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
565 base::FilePath origin1_db_dir
;
566 base::FilePath origin2_db_dir
;
568 scoped_refptr
<MockSpecialStoragePolicy
> special_storage_policy
=
569 new MockSpecialStoragePolicy
;
570 special_storage_policy
->AddSessionOnly(GURL(kOrigin2Url
));
571 scoped_refptr
<DatabaseTracker
> tracker(
572 new DatabaseTracker(temp_dir
.path(),
574 special_storage_policy
.get(),
576 base::MessageLoopProxy::current().get()));
578 // Open two new databases.
579 tracker
->DatabaseOpened(kOrigin1
, kDB1
, kDescription
, 0,
581 EXPECT_EQ(0, database_size
);
582 tracker
->DatabaseOpened(kOrigin2
, kDB2
, kDescription
, 0,
584 EXPECT_EQ(0, database_size
);
586 // Write some data to each file.
587 base::FilePath db_file
;
588 db_file
= tracker
->GetFullDBFilePath(kOrigin1
, kDB1
);
589 EXPECT_TRUE(base::CreateDirectory(db_file
.DirName()));
590 EXPECT_TRUE(EnsureFileOfSize(db_file
, 1));
592 db_file
= tracker
->GetFullDBFilePath(kOrigin2
, kDB2
);
593 EXPECT_TRUE(base::CreateDirectory(db_file
.DirName()));
594 EXPECT_TRUE(EnsureFileOfSize(db_file
, 2));
596 // Store the origin database directories as long as they still exist.
597 origin1_db_dir
= tracker
->GetFullDBFilePath(kOrigin1
, kDB1
).DirName();
598 origin2_db_dir
= tracker
->GetFullDBFilePath(kOrigin2
, kDB2
).DirName();
600 tracker
->DatabaseModified(kOrigin1
, kDB1
);
601 tracker
->DatabaseModified(kOrigin2
, kDB2
);
603 // Close all databases.
604 tracker
->DatabaseClosed(kOrigin1
, kDB1
);
605 tracker
->DatabaseClosed(kOrigin2
, kDB2
);
610 // At this point, the database tracker should be gone. Create a new one.
611 scoped_refptr
<DatabaseTracker
> tracker(
612 new DatabaseTracker(temp_dir
.path(), false, NULL
, NULL
, NULL
));
614 // Get all data for all origins.
615 std::vector
<OriginInfo
> origins_info
;
616 EXPECT_TRUE(tracker
->GetAllOriginsInfo(&origins_info
));
617 // kOrigin1 was not session-only, so it survived. kOrigin2 was session-only
618 // and it got deleted.
619 EXPECT_EQ(size_t(1), origins_info
.size());
620 EXPECT_EQ(kOrigin1
, origins_info
[0].GetOriginIdentifier());
622 base::PathExists(tracker
->GetFullDBFilePath(kOrigin1
, kDB1
)));
623 EXPECT_EQ(base::FilePath(), tracker
->GetFullDBFilePath(kOrigin2
, kDB2
));
625 // The origin directory of kOrigin1 remains, but the origin directory of
626 // kOrigin2 is deleted.
627 EXPECT_TRUE(base::PathExists(origin1_db_dir
));
628 EXPECT_FALSE(base::PathExists(origin2_db_dir
));
631 static void DatabaseTrackerSetForceKeepSessionState() {
632 int64 database_size
= 0;
633 const std::string kOrigin1
=
634 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin1Url
));
635 const std::string kOrigin2
=
636 webkit_database::GetIdentifierFromOrigin(GURL(kOrigin2Url
));
637 const base::string16 kDB1
= ASCIIToUTF16("db1");
638 const base::string16 kDB2
= ASCIIToUTF16("db2");
639 const base::string16 kDescription
= ASCIIToUTF16("database_description");
641 // Initialize the tracker database.
642 base::MessageLoop message_loop
;
643 base::ScopedTempDir temp_dir
;
644 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
645 base::FilePath origin1_db_dir
;
646 base::FilePath origin2_db_dir
;
648 scoped_refptr
<MockSpecialStoragePolicy
> special_storage_policy
=
649 new MockSpecialStoragePolicy
;
650 special_storage_policy
->AddSessionOnly(GURL(kOrigin2Url
));
651 scoped_refptr
<DatabaseTracker
> tracker(
652 new DatabaseTracker(temp_dir
.path(),
654 special_storage_policy
.get(),
656 base::MessageLoopProxy::current().get()));
657 tracker
->SetForceKeepSessionState();
659 // Open two new databases.
660 tracker
->DatabaseOpened(kOrigin1
, kDB1
, kDescription
, 0,
662 EXPECT_EQ(0, database_size
);
663 tracker
->DatabaseOpened(kOrigin2
, kDB2
, kDescription
, 0,
665 EXPECT_EQ(0, database_size
);
667 // Write some data to each file.
668 base::FilePath db_file
;
669 db_file
= tracker
->GetFullDBFilePath(kOrigin1
, kDB1
);
670 EXPECT_TRUE(base::CreateDirectory(db_file
.DirName()));
671 EXPECT_TRUE(EnsureFileOfSize(db_file
, 1));
673 db_file
= tracker
->GetFullDBFilePath(kOrigin2
, kDB2
);
674 EXPECT_TRUE(base::CreateDirectory(db_file
.DirName()));
675 EXPECT_TRUE(EnsureFileOfSize(db_file
, 2));
677 // Store the origin database directories as long as they still exist.
678 origin1_db_dir
= tracker
->GetFullDBFilePath(kOrigin1
, kDB1
).DirName();
679 origin2_db_dir
= tracker
->GetFullDBFilePath(kOrigin2
, kDB2
).DirName();
681 tracker
->DatabaseModified(kOrigin1
, kDB1
);
682 tracker
->DatabaseModified(kOrigin2
, kDB2
);
684 // Close all databases.
685 tracker
->DatabaseClosed(kOrigin1
, kDB1
);
686 tracker
->DatabaseClosed(kOrigin2
, kDB2
);
691 // At this point, the database tracker should be gone. Create a new one.
692 scoped_refptr
<DatabaseTracker
> tracker(
693 new DatabaseTracker(temp_dir
.path(), false, NULL
, NULL
, NULL
));
695 // Get all data for all origins.
696 std::vector
<OriginInfo
> origins_info
;
697 EXPECT_TRUE(tracker
->GetAllOriginsInfo(&origins_info
));
698 // No origins were deleted.
699 EXPECT_EQ(size_t(2), origins_info
.size());
701 base::PathExists(tracker
->GetFullDBFilePath(kOrigin1
, kDB1
)));
703 base::PathExists(tracker
->GetFullDBFilePath(kOrigin2
, kDB2
)));
705 EXPECT_TRUE(base::PathExists(origin1_db_dir
));
706 EXPECT_TRUE(base::PathExists(origin2_db_dir
));
709 static void EmptyDatabaseNameIsValid() {
710 const GURL
kOrigin(kOrigin1Url
);
711 const std::string kOriginId
=
712 webkit_database::GetIdentifierFromOrigin(kOrigin
);
713 const base::string16 kEmptyName
;
714 const base::string16
kDescription(ASCIIToUTF16("description"));
715 const base::string16
kChangedDescription(
716 ASCIIToUTF16("changed_description"));
718 // Initialize a tracker database, no need to put it on disk.
719 const bool kUseInMemoryTrackerDatabase
= true;
720 base::ScopedTempDir temp_dir
;
721 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
722 scoped_refptr
<DatabaseTracker
> tracker(
723 new DatabaseTracker(temp_dir
.path(), kUseInMemoryTrackerDatabase
,
726 // Starts off with no databases.
727 std::vector
<OriginInfo
> infos
;
728 EXPECT_TRUE(tracker
->GetAllOriginsInfo(&infos
));
729 EXPECT_TRUE(infos
.empty());
731 // Create a db with an empty name.
732 int64 database_size
= -1;
733 tracker
->DatabaseOpened(kOriginId
, kEmptyName
, kDescription
, 0,
735 EXPECT_EQ(0, database_size
);
736 tracker
->DatabaseModified(kOriginId
, kEmptyName
);
737 EXPECT_TRUE(tracker
->GetAllOriginsInfo(&infos
));
738 EXPECT_EQ(1u, infos
.size());
739 EXPECT_EQ(kDescription
, infos
[0].GetDatabaseDescription(kEmptyName
));
740 EXPECT_FALSE(tracker
->GetFullDBFilePath(kOriginId
, kEmptyName
).empty());
741 tracker
->DatabaseOpened(kOriginId
, kEmptyName
, kChangedDescription
, 0,
744 EXPECT_TRUE(tracker
->GetAllOriginsInfo(&infos
));
745 EXPECT_EQ(1u, infos
.size());
746 EXPECT_EQ(kChangedDescription
, infos
[0].GetDatabaseDescription(kEmptyName
));
747 tracker
->DatabaseClosed(kOriginId
, kEmptyName
);
748 tracker
->DatabaseClosed(kOriginId
, kEmptyName
);
750 // Deleting it should return to the initial state.
751 EXPECT_EQ(net::OK
, tracker
->DeleteDatabase(kOriginId
, kEmptyName
,
752 net::CompletionCallback()));
754 EXPECT_TRUE(tracker
->GetAllOriginsInfo(&infos
));
755 EXPECT_TRUE(infos
.empty());
758 static void HandleSqliteError() {
759 const GURL
kOrigin(kOrigin1Url
);
760 const std::string kOriginId
=
761 webkit_database::GetIdentifierFromOrigin(kOrigin
);
762 const base::string16
kName(ASCIIToUTF16("name"));
763 const base::string16
kDescription(ASCIIToUTF16("description"));
765 // Initialize a tracker database, no need to put it on disk.
766 const bool kUseInMemoryTrackerDatabase
= true;
767 base::ScopedTempDir temp_dir
;
768 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
769 scoped_refptr
<DatabaseTracker
> tracker(
770 new DatabaseTracker(temp_dir
.path(), kUseInMemoryTrackerDatabase
,
773 // Setup to observe OnScheduledForDelete notifications.
774 TestObserver
observer(false, true);
775 tracker
->AddObserver(&observer
);
777 // Verify does no harm when there is no such database.
778 tracker
->HandleSqliteError(kOriginId
, kName
, SQLITE_CORRUPT
);
779 EXPECT_FALSE(tracker
->IsDatabaseScheduledForDeletion(kOriginId
, kName
));
780 EXPECT_FALSE(observer
.DidReceiveNewNotification());
782 // --------------------------------------------------------
783 // Create a record of a database in the tracker db and create
784 // a spoof_db_file on disk in the expected location.
785 int64 database_size
= 0;
786 tracker
->DatabaseOpened(kOriginId
, kName
, kDescription
, 0,
788 base::FilePath spoof_db_file
= tracker
->GetFullDBFilePath(kOriginId
, kName
);
789 EXPECT_FALSE(tracker
->GetFullDBFilePath(kOriginId
, kName
).empty());
790 EXPECT_TRUE(base::CreateDirectory(spoof_db_file
.DirName()));
791 EXPECT_TRUE(EnsureFileOfSize(spoof_db_file
, 1));
793 // Verify does no harm with a non-error is reported.
794 tracker
->HandleSqliteError(kOriginId
, kName
, SQLITE_OK
);
795 EXPECT_FALSE(tracker
->IsDatabaseScheduledForDeletion(kOriginId
, kName
));
796 EXPECT_FALSE(observer
.DidReceiveNewNotification());
798 // Verify that with a connection open, the db is scheduled for deletion,
799 // but that the file still exists.
800 tracker
->HandleSqliteError(kOriginId
, kName
, SQLITE_CORRUPT
);
801 EXPECT_TRUE(tracker
->IsDatabaseScheduledForDeletion(kOriginId
, kName
));
802 EXPECT_TRUE(observer
.DidReceiveNewNotification());
803 EXPECT_TRUE(base::PathExists(spoof_db_file
));
805 // Verify that once closed, the file is deleted and the record in the
806 // tracker db is removed.
807 tracker
->DatabaseClosed(kOriginId
, kName
);
808 EXPECT_FALSE(base::PathExists(spoof_db_file
));
809 EXPECT_TRUE(tracker
->GetFullDBFilePath(kOriginId
, kName
).empty());
811 // --------------------------------------------------------
812 // Create another record of a database in the tracker db and create
813 // a spoof_db_file on disk in the expected location.
814 tracker
->DatabaseOpened(kOriginId
, kName
, kDescription
, 0,
816 base::FilePath spoof_db_file2
= tracker
->GetFullDBFilePath(kOriginId
,
818 EXPECT_FALSE(tracker
->GetFullDBFilePath(kOriginId
, kName
).empty());
819 EXPECT_NE(spoof_db_file
, spoof_db_file2
);
820 EXPECT_TRUE(base::CreateDirectory(spoof_db_file2
.DirName()));
821 EXPECT_TRUE(EnsureFileOfSize(spoof_db_file2
, 1));
823 // Verify that with no connection open, the db is deleted immediately.
824 tracker
->DatabaseClosed(kOriginId
, kName
);
825 tracker
->HandleSqliteError(kOriginId
, kName
, SQLITE_CORRUPT
);
826 EXPECT_FALSE(tracker
->IsDatabaseScheduledForDeletion(kOriginId
, kName
));
827 EXPECT_FALSE(observer
.DidReceiveNewNotification());
828 EXPECT_TRUE(tracker
->GetFullDBFilePath(kOriginId
, kName
).empty());
829 EXPECT_FALSE(base::PathExists(spoof_db_file2
));
831 tracker
->RemoveObserver(&observer
);
835 TEST(DatabaseTrackerTest
, DeleteOpenDatabase
) {
836 DatabaseTracker_TestHelper_Test::TestDeleteOpenDatabase(false);
839 TEST(DatabaseTrackerTest
, DeleteOpenDatabaseIncognitoMode
) {
840 DatabaseTracker_TestHelper_Test::TestDeleteOpenDatabase(true);
843 TEST(DatabaseTrackerTest
, DatabaseTracker
) {
844 DatabaseTracker_TestHelper_Test::TestDatabaseTracker(false);
847 TEST(DatabaseTrackerTest
, DatabaseTrackerIncognitoMode
) {
848 DatabaseTracker_TestHelper_Test::TestDatabaseTracker(true);
851 TEST(DatabaseTrackerTest
, DatabaseTrackerQuotaIntegration
) {
852 // There is no difference in behavior between incognito and not.
853 DatabaseTracker_TestHelper_Test::DatabaseTrackerQuotaIntegration();
856 TEST(DatabaseTrackerTest
, DatabaseTrackerClearSessionOnlyDatabasesOnExit
) {
857 // Only works for regular mode.
858 DatabaseTracker_TestHelper_Test::
859 DatabaseTrackerClearSessionOnlyDatabasesOnExit();
862 TEST(DatabaseTrackerTest
, DatabaseTrackerSetForceKeepSessionState
) {
863 // Only works for regular mode.
864 DatabaseTracker_TestHelper_Test::DatabaseTrackerSetForceKeepSessionState();
867 TEST(DatabaseTrackerTest
, EmptyDatabaseNameIsValid
) {
868 DatabaseTracker_TestHelper_Test::EmptyDatabaseNameIsValid();
871 TEST(DatabaseTrackerTest
, HandleSqliteError
) {
872 DatabaseTracker_TestHelper_Test::HandleSqliteError();
875 } // namespace content