1ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
2ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// found in the LICENSE file.
4ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
5ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "base/bind.h"
6ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "base/files/file_util.h"
7ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "base/files/scoped_temp_dir.h"
8ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "base/message_loop/message_loop.h"
9ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "base/message_loop/message_loop_proxy.h"
10ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "base/strings/utf_string_conversions.h"
11ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "base/threading/sequenced_worker_pool.h"
12ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "base/time/time.h"
13ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "content/browser/dom_storage/dom_storage_area.h"
14ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "content/browser/dom_storage/dom_storage_database.h"
15ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "content/browser/dom_storage/dom_storage_database_adapter.h"
16ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "content/browser/dom_storage/dom_storage_task_runner.h"
17ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "content/browser/dom_storage/local_storage_database_adapter.h"
18ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "content/common/dom_storage/dom_storage_types.h"
19ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "testing/gtest/include/gtest/gtest.h"
20ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
21ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochusing base::ASCIIToUTF16;
22ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
23ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochnamespace content {
24ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
25ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochclass DOMStorageAreaTest : public testing::Test {
26ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch public:
27ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  DOMStorageAreaTest()
28ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    : kOrigin(GURL("http://dom_storage/")),
29ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      kKey(ASCIIToUTF16("key")),
30ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      kValue(ASCIIToUTF16("value")),
31ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      kKey2(ASCIIToUTF16("key2")),
32ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      kValue2(ASCIIToUTF16("value2")) {
33ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
34ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
35ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  const GURL kOrigin;
36ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  const base::string16 kKey;
37ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  const base::string16 kValue;
38ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  const base::string16 kKey2;
39ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  const base::string16 kValue2;
40ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
41ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Method used in the CommitTasks test case.
42ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  void InjectedCommitSequencingTask(DOMStorageArea* area) {
43ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // At this point the OnCommitTimer has run.
44ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // Verify that it put a commit in flight.
45ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    EXPECT_EQ(1, area->commit_batches_in_flight_);
46ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    EXPECT_FALSE(area->commit_batch_.get());
47ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    EXPECT_TRUE(area->HasUncommittedChanges());
48ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // Make additional change and verify that a new commit batch
49ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // is created for that change.
50ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    base::NullableString16 old_value;
51ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    EXPECT_TRUE(area->SetItem(kKey2, kValue2, &old_value));
52ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    EXPECT_TRUE(area->commit_batch_.get());
53ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    EXPECT_EQ(1, area->commit_batches_in_flight_);
54ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    EXPECT_TRUE(area->HasUncommittedChanges());
55ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
56ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
57ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Class used in the CommitChangesAtShutdown test case.
58ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  class VerifyChangesCommittedDatabase : public DOMStorageDatabase {
59ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch   public:
60ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    VerifyChangesCommittedDatabase() {}
61ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    virtual ~VerifyChangesCommittedDatabase() {
62ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      const base::string16 kKey(ASCIIToUTF16("key"));
63ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      const base::string16 kValue(ASCIIToUTF16("value"));
64ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      DOMStorageValuesMap values;
65ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      ReadAllValues(&values);
66ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      EXPECT_EQ(1u, values.size());
67ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      EXPECT_EQ(kValue, values[kKey].string());
68ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    }
69ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  };
70ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
71ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch private:
72ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  base::MessageLoop message_loop_;
73ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch};
74ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
75ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben MurdochTEST_F(DOMStorageAreaTest, DOMStorageAreaBasics) {
76ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  scoped_refptr<DOMStorageArea> area(
77ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      new DOMStorageArea(1, std::string(), kOrigin, NULL, NULL));
78010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  base::string16 old_value;
79010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  base::NullableString16 old_nullable_value;
80010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  scoped_refptr<DOMStorageArea> copy;
81010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
82ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // We don't focus on the underlying DOMStorageMap functionality
83010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // since that's covered by seperate unit tests.
84ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_EQ(kOrigin, area->origin());
85010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXPECT_EQ(1, area->namespace_id());
86ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_EQ(0u, area->Length());
87ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_TRUE(area->SetItem(kKey, kValue, &old_nullable_value));
88ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_TRUE(area->SetItem(kKey2, kValue2, &old_nullable_value));
89ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_FALSE(area->HasUncommittedChanges());
90ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
91ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Verify that a copy shares the same map.
92010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  copy = area->ShallowCopy(2, std::string());
93010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXPECT_EQ(kOrigin, copy->origin());
94010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXPECT_EQ(2, copy->namespace_id());
95010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXPECT_EQ(area->Length(), copy->Length());
96ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_EQ(area->GetItem(kKey).string(), copy->GetItem(kKey).string());
97010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXPECT_EQ(area->Key(0).string(), copy->Key(0).string());
98ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_EQ(copy->map_.get(), area->map_.get());
99010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
100ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // But will deep copy-on-write as needed.
101ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_TRUE(area->RemoveItem(kKey, &old_value));
102ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_NE(copy->map_.get(), area->map_.get());
103010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  copy = area->ShallowCopy(2, std::string());
104010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXPECT_EQ(copy->map_.get(), area->map_.get());
105010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXPECT_TRUE(area->SetItem(kKey, kValue, &old_nullable_value));
106010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXPECT_NE(copy->map_.get(), area->map_.get());
107ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  copy = area->ShallowCopy(2, std::string());
108ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_EQ(copy->map_.get(), area->map_.get());
109010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXPECT_NE(0u, area->Length());
110010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXPECT_TRUE(area->Clear());
111010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXPECT_EQ(0u, area->Length());
112010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXPECT_NE(copy->map_.get(), area->map_.get());
113ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
114010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Verify that once Shutdown(), behaves that way.
115ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  area->Shutdown();
116010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXPECT_TRUE(area->is_shutdown_);
117ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_FALSE(area->map_.get());
118ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_EQ(0u, area->Length());
119ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_TRUE(area->Key(0).is_null());
120ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_TRUE(area->GetItem(kKey).is_null());
121ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_FALSE(area->SetItem(kKey, kValue, &old_nullable_value));
122ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_FALSE(area->RemoveItem(kKey, &old_value));
123ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_FALSE(area->Clear());
124ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
125ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
126ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben MurdochTEST_F(DOMStorageAreaTest, BackingDatabaseOpened) {
127ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  const int64 kSessionStorageNamespaceId = kLocalStorageNamespaceId + 1;
128ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  base::ScopedTempDir temp_dir;
129ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
130ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  const base::FilePath kExpectedOriginFilePath = temp_dir.path().Append(
131ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      DOMStorageArea::DatabaseFileNameFromOrigin(kOrigin));
132ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
133ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // No directory, backing should be null.
134ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  {
135ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    scoped_refptr<DOMStorageArea> area(
136010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        new DOMStorageArea(kOrigin, base::FilePath(), NULL));
137ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    EXPECT_EQ(NULL, area->backing_.get());
138ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    EXPECT_TRUE(area->is_initial_import_done_);
139010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    EXPECT_FALSE(base::PathExists(kExpectedOriginFilePath));
140010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
141ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
142ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Valid directory and origin but no session storage backing. Backing should
143ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // be null.
144010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  {
145ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    scoped_refptr<DOMStorageArea> area(
146ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        new DOMStorageArea(kSessionStorageNamespaceId, std::string(), kOrigin,
147010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                           NULL, NULL));
148010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    EXPECT_EQ(NULL, area->backing_.get());
149ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    EXPECT_TRUE(area->is_initial_import_done_);
150ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
151ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    base::NullableString16 old_value;
152010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
153ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    ASSERT_TRUE(old_value.is_null());
154ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
155010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // Check that saving a value has still left us without a backing database.
156010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    EXPECT_EQ(NULL, area->backing_.get());
157ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    EXPECT_FALSE(base::PathExists(kExpectedOriginFilePath));
158ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
159ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
160010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // This should set up a DOMStorageArea that is correctly backed to disk.
161ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  {
162ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
163010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        kOrigin,
164010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        temp_dir.path(),
165ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
166ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
167ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    EXPECT_TRUE(area->backing_.get());
168ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    DOMStorageDatabase* database = static_cast<LocalStorageDatabaseAdapter*>(
169ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        area->backing_.get())->db_.get();
170ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    EXPECT_FALSE(database->IsOpen());
171ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    EXPECT_FALSE(area->is_initial_import_done_);
172ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
173ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // Inject an in-memory db to speed up the test.
174ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // We will verify that something is written into the database but not
175ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // that a file is written to disk - DOMStorageDatabase unit tests cover
176010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // that.
177010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    area->backing_.reset(new LocalStorageDatabaseAdapter());
178010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
179010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // Need to write something to ensure that the database is created.
180010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    base::NullableString16 old_value;
181010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
182010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    ASSERT_TRUE(old_value.is_null());
183010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    EXPECT_TRUE(area->is_initial_import_done_);
184ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    EXPECT_TRUE(area->commit_batch_.get());
185ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    EXPECT_EQ(0, area->commit_batches_in_flight_);
186ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
187ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    base::MessageLoop::current()->RunUntilIdle();
188ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
189ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    EXPECT_FALSE(area->commit_batch_.get());
190010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    EXPECT_EQ(0, area->commit_batches_in_flight_);
191010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    database = static_cast<LocalStorageDatabaseAdapter*>(
192010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        area->backing_.get())->db_.get();
193010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    EXPECT_TRUE(database->IsOpen());
194010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    EXPECT_EQ(1u, area->Length());
195010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    EXPECT_EQ(kValue, area->GetItem(kKey).string());
196010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
197010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // Verify the content made it to the in memory database.
198ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    DOMStorageValuesMap values;
199ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    area->backing_->ReadAllValues(&values);
200ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    EXPECT_EQ(1u, values.size());
201ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    EXPECT_EQ(kValue, values[kKey].string());
202ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
203ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
204ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
205ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben MurdochTEST_F(DOMStorageAreaTest, CommitTasks) {
206ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  base::ScopedTempDir temp_dir;
207ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
208ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
209ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
210ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      kOrigin,
211ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      temp_dir.path(),
212ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
213ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Inject an in-memory db to speed up the test.
214ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  area->backing_.reset(new LocalStorageDatabaseAdapter());
215ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
216ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Unrelated to commits, but while we're here, see that querying Length()
217ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // causes the backing database to be opened and presumably read from.
218ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_FALSE(area->is_initial_import_done_);
219ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_EQ(0u, area->Length());
220ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_TRUE(area->is_initial_import_done_);
221ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
222ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  DOMStorageValuesMap values;
223ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  base::NullableString16 old_value;
224ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
225ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // See that changes are batched up.
226ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_FALSE(area->commit_batch_.get());
227ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
228ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_TRUE(area->HasUncommittedChanges());
229ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_TRUE(area->commit_batch_.get());
230ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_FALSE(area->commit_batch_->clear_all_first);
231ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_EQ(1u, area->commit_batch_->changed_values.size());
232ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_TRUE(area->SetItem(kKey2, kValue2, &old_value));
233ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_TRUE(area->commit_batch_.get());
234ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_FALSE(area->commit_batch_->clear_all_first);
235ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_EQ(2u, area->commit_batch_->changed_values.size());
236ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  base::MessageLoop::current()->RunUntilIdle();
237ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_FALSE(area->HasUncommittedChanges());
238ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_FALSE(area->commit_batch_.get());
239ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_EQ(0, area->commit_batches_in_flight_);
240ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Verify the changes made it to the database.
241ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  values.clear();
242ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  area->backing_->ReadAllValues(&values);
243ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_EQ(2u, values.size());
244ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_EQ(kValue, values[kKey].string());
245ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_EQ(kValue2, values[kKey2].string());
246ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
247ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // See that clear is handled properly.
248ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_TRUE(area->Clear());
249ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_TRUE(area->commit_batch_.get());
250ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_TRUE(area->commit_batch_->clear_all_first);
251ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_TRUE(area->commit_batch_->changed_values.empty());
252ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  base::MessageLoop::current()->RunUntilIdle();
253ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_FALSE(area->commit_batch_.get());
254ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_EQ(0, area->commit_batches_in_flight_);
255ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Verify the changes made it to the database.
256ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  values.clear();
257ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  area->backing_->ReadAllValues(&values);
258ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_TRUE(values.empty());
259ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
260ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // See that if changes accrue while a commit is "in flight"
261ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // those will also get committed.
262ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
263ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  EXPECT_TRUE(area->HasUncommittedChanges());
264ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // At this point the OnCommitTimer task has been posted. We inject
265ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // another task in the queue that will execute after the timer task,
266ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // but before the CommitChanges task. From within our injected task,
267ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // we'll make an additional SetItem() call.
268ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  base::MessageLoop::current()->PostTask(
269ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      FROM_HERE,
270      base::Bind(&DOMStorageAreaTest::InjectedCommitSequencingTask,
271                 base::Unretained(this),
272                 area));
273  base::MessageLoop::current()->RunUntilIdle();
274  EXPECT_TRUE(area->HasOneRef());
275  EXPECT_FALSE(area->HasUncommittedChanges());
276  // Verify the changes made it to the database.
277  values.clear();
278  area->backing_->ReadAllValues(&values);
279  EXPECT_EQ(2u, values.size());
280  EXPECT_EQ(kValue, values[kKey].string());
281  EXPECT_EQ(kValue2, values[kKey2].string());
282}
283
284TEST_F(DOMStorageAreaTest, CommitChangesAtShutdown) {
285  base::ScopedTempDir temp_dir;
286  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
287  scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
288      kOrigin,
289      temp_dir.path(),
290      new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
291
292  // Inject an in-memory db to speed up the test and also to verify
293  // the final changes are commited in it's dtor.
294  static_cast<LocalStorageDatabaseAdapter*>(area->backing_.get())->db_.reset(
295      new VerifyChangesCommittedDatabase());
296
297  DOMStorageValuesMap values;
298  base::NullableString16 old_value;
299  EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
300  EXPECT_TRUE(area->HasUncommittedChanges());
301  area->backing_->ReadAllValues(&values);
302  EXPECT_TRUE(values.empty());  // not committed yet
303  area->Shutdown();
304  base::MessageLoop::current()->RunUntilIdle();
305  EXPECT_TRUE(area->HasOneRef());
306  EXPECT_FALSE(area->backing_.get());
307  // The VerifyChangesCommittedDatabase destructor verifies values
308  // were committed.
309}
310
311TEST_F(DOMStorageAreaTest, DeleteOrigin) {
312  base::ScopedTempDir temp_dir;
313  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
314  scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
315      kOrigin,
316      temp_dir.path(),
317      new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
318
319  // This test puts files on disk.
320  base::FilePath db_file_path = static_cast<LocalStorageDatabaseAdapter*>(
321      area->backing_.get())->db_->file_path();
322  base::FilePath db_journal_file_path =
323      DOMStorageDatabase::GetJournalFilePath(db_file_path);
324
325  // Nothing bad should happen when invoked w/o any files on disk.
326  area->DeleteOrigin();
327  EXPECT_FALSE(base::PathExists(db_file_path));
328
329  // Commit something in the database and then delete.
330  base::NullableString16 old_value;
331  area->SetItem(kKey, kValue, &old_value);
332  base::MessageLoop::current()->RunUntilIdle();
333  EXPECT_TRUE(base::PathExists(db_file_path));
334  area->DeleteOrigin();
335  EXPECT_EQ(0u, area->Length());
336  EXPECT_FALSE(base::PathExists(db_file_path));
337  EXPECT_FALSE(base::PathExists(db_journal_file_path));
338
339  // Put some uncommitted changes to a non-existing database in
340  // and then delete. No file ever gets created in this case.
341  area->SetItem(kKey, kValue, &old_value);
342  EXPECT_TRUE(area->HasUncommittedChanges());
343  EXPECT_EQ(1u, area->Length());
344  area->DeleteOrigin();
345  EXPECT_TRUE(area->HasUncommittedChanges());
346  EXPECT_EQ(0u, area->Length());
347  base::MessageLoop::current()->RunUntilIdle();
348  EXPECT_FALSE(area->HasUncommittedChanges());
349  EXPECT_FALSE(base::PathExists(db_file_path));
350
351  // Put some uncommitted changes to a an existing database in
352  // and then delete.
353  area->SetItem(kKey, kValue, &old_value);
354  base::MessageLoop::current()->RunUntilIdle();
355  EXPECT_TRUE(base::PathExists(db_file_path));
356  area->SetItem(kKey2, kValue2, &old_value);
357  EXPECT_TRUE(area->HasUncommittedChanges());
358  EXPECT_EQ(2u, area->Length());
359  area->DeleteOrigin();
360  EXPECT_TRUE(area->HasUncommittedChanges());
361  EXPECT_EQ(0u, area->Length());
362  base::MessageLoop::current()->RunUntilIdle();
363  EXPECT_FALSE(area->HasUncommittedChanges());
364  // Since the area had uncommitted changes at the time delete
365  // was called, the file will linger until the shutdown time.
366  EXPECT_TRUE(base::PathExists(db_file_path));
367  area->Shutdown();
368  base::MessageLoop::current()->RunUntilIdle();
369  EXPECT_FALSE(base::PathExists(db_file_path));
370}
371
372TEST_F(DOMStorageAreaTest, PurgeMemory) {
373  base::ScopedTempDir temp_dir;
374  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
375  scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
376      kOrigin,
377      temp_dir.path(),
378      new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
379
380  // Inject an in-memory db to speed up the test.
381  area->backing_.reset(new LocalStorageDatabaseAdapter());
382
383  // Unowned ptrs we use to verify that 'purge' has happened.
384  DOMStorageDatabase* original_backing =
385      static_cast<LocalStorageDatabaseAdapter*>(
386          area->backing_.get())->db_.get();
387  DOMStorageMap* original_map = area->map_.get();
388
389  // Should do no harm when called on a newly constructed object.
390  EXPECT_FALSE(area->is_initial_import_done_);
391  area->PurgeMemory();
392  EXPECT_FALSE(area->is_initial_import_done_);
393  DOMStorageDatabase* new_backing = static_cast<LocalStorageDatabaseAdapter*>(
394      area->backing_.get())->db_.get();
395  EXPECT_EQ(original_backing, new_backing);
396  EXPECT_EQ(original_map, area->map_.get());
397
398  // Should not do anything when commits are pending.
399  base::NullableString16 old_value;
400  area->SetItem(kKey, kValue, &old_value);
401  EXPECT_TRUE(area->is_initial_import_done_);
402  EXPECT_TRUE(area->HasUncommittedChanges());
403  area->PurgeMemory();
404  EXPECT_TRUE(area->is_initial_import_done_);
405  EXPECT_TRUE(area->HasUncommittedChanges());
406  new_backing = static_cast<LocalStorageDatabaseAdapter*>(
407      area->backing_.get())->db_.get();
408  EXPECT_EQ(original_backing, new_backing);
409  EXPECT_EQ(original_map, area->map_.get());
410
411  // Commit the changes from above,
412  base::MessageLoop::current()->RunUntilIdle();
413  EXPECT_FALSE(area->HasUncommittedChanges());
414  new_backing = static_cast<LocalStorageDatabaseAdapter*>(
415      area->backing_.get())->db_.get();
416  EXPECT_EQ(original_backing, new_backing);
417  EXPECT_EQ(original_map, area->map_.get());
418
419  // Should drop caches and reset database connections
420  // when invoked on an area that's loaded up primed.
421  area->PurgeMemory();
422  EXPECT_FALSE(area->is_initial_import_done_);
423  new_backing = static_cast<LocalStorageDatabaseAdapter*>(
424      area->backing_.get())->db_.get();
425  EXPECT_NE(original_backing, new_backing);
426  EXPECT_NE(original_map, area->map_.get());
427}
428
429TEST_F(DOMStorageAreaTest, DatabaseFileNames) {
430  struct {
431    const char* origin;
432    const char* file_name;
433    const char* journal_file_name;
434  } kCases[] = {
435    { "https://www.google.com/",
436      "https_www.google.com_0.localstorage",
437      "https_www.google.com_0.localstorage-journal" },
438    { "http://www.google.com:8080/",
439      "http_www.google.com_8080.localstorage",
440      "http_www.google.com_8080.localstorage-journal" },
441    { "file:///",
442      "file__0.localstorage",
443      "file__0.localstorage-journal" },
444  };
445
446  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kCases); ++i) {
447    GURL origin = GURL(kCases[i].origin).GetOrigin();
448    base::FilePath file_name =
449        base::FilePath().AppendASCII(kCases[i].file_name);
450    base::FilePath journal_file_name =
451        base::FilePath().AppendASCII(kCases[i].journal_file_name);
452
453    EXPECT_EQ(file_name,
454              DOMStorageArea::DatabaseFileNameFromOrigin(origin));
455    EXPECT_EQ(origin,
456              DOMStorageArea::OriginFromDatabaseFileName(file_name));
457    EXPECT_EQ(journal_file_name,
458              DOMStorageDatabase::GetJournalFilePath(file_name));
459  }
460
461  // Also test some DOMStorageDatabase::GetJournalFilePath cases here.
462  base::FilePath parent = base::FilePath().AppendASCII("a").AppendASCII("b");
463  EXPECT_EQ(
464      parent.AppendASCII("file-journal"),
465      DOMStorageDatabase::GetJournalFilePath(parent.AppendASCII("file")));
466  EXPECT_EQ(
467      base::FilePath().AppendASCII("-journal"),
468      DOMStorageDatabase::GetJournalFilePath(base::FilePath()));
469  EXPECT_EQ(
470      base::FilePath().AppendASCII(".extensiononly-journal"),
471      DOMStorageDatabase::GetJournalFilePath(
472          base::FilePath().AppendASCII(".extensiononly")));
473}
474
475}  // namespace content
476