OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/bind.h" | 5 #include "base/bind.h" |
6 #include "base/file_util.h" | 6 #include "base/file_util.h" |
7 #include "base/message_loop.h" | 7 #include "base/message_loop.h" |
8 #include "base/message_loop_proxy.h" | 8 #include "base/message_loop_proxy.h" |
9 #include "base/scoped_temp_dir.h" | 9 #include "base/scoped_temp_dir.h" |
10 #include "base/threading/sequenced_worker_pool.h" | 10 #include "base/threading/sequenced_worker_pool.h" |
11 #include "base/time.h" | 11 #include "base/time.h" |
12 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
13 #include "testing/gtest/include/gtest/gtest.h" | 13 #include "testing/gtest/include/gtest/gtest.h" |
14 #include "webkit/dom_storage/dom_storage_area.h" | 14 #include "webkit/dom_storage/dom_storage_area.h" |
15 #include "webkit/dom_storage/dom_storage_task_runner.h" | 15 #include "webkit/dom_storage/dom_storage_task_runner.h" |
16 #include "webkit/dom_storage/dom_storage_types.h" | 16 #include "webkit/dom_storage/dom_storage_types.h" |
17 | 17 |
18 namespace dom_storage { | 18 namespace dom_storage { |
19 | 19 |
20 TEST(DomStorageAreaTest, DomStorageAreaBasics) { | |
21 const GURL kOrigin("http://dom_storage/"); | |
22 const string16 kKey(ASCIIToUTF16("key")); | |
23 const string16 kValue(ASCIIToUTF16("value")); | |
24 const string16 kKey2(ASCIIToUTF16("key2")); | |
25 const string16 kValue2(ASCIIToUTF16("value2")); | |
26 | 20 |
| 21 class DomStorageAreaTest : public testing::Test { |
| 22 public: |
| 23 DomStorageAreaTest() |
| 24 : kOrigin(GURL("http://dom_storage/")), |
| 25 kKey(ASCIIToUTF16("key")), |
| 26 kValue(ASCIIToUTF16("value")), |
| 27 kKey2(ASCIIToUTF16("key2")), |
| 28 kValue2(ASCIIToUTF16("value2")) { |
| 29 } |
| 30 |
| 31 const GURL kOrigin; |
| 32 const string16 kKey; |
| 33 const string16 kValue; |
| 34 const string16 kKey2; |
| 35 const string16 kValue2; |
| 36 |
| 37 // Method used in the CommitTasks test case. |
| 38 void InjectedCommitSequencingTask(DomStorageArea* area) { |
| 39 // At this point the OnCommitTimer has run. |
| 40 // Verify that it put a commit in flight. |
| 41 EXPECT_TRUE(area->in_flight_commit_batch_.get()); |
| 42 EXPECT_FALSE(area->commit_batch_.get()); |
| 43 // Make additional change and verify that a new commit batch |
| 44 // is created for that change. |
| 45 NullableString16 old_value; |
| 46 EXPECT_TRUE(area->SetItem(kKey2, kValue2, &old_value)); |
| 47 EXPECT_TRUE(area->commit_batch_.get()); |
| 48 EXPECT_TRUE(area->in_flight_commit_batch_.get()); |
| 49 } |
| 50 |
| 51 // Class used in the CommitChangesAtShutdown test case. |
| 52 class VerifyChangesCommittedDatabase : public DomStorageDatabase { |
| 53 public: |
| 54 VerifyChangesCommittedDatabase() {} |
| 55 virtual ~VerifyChangesCommittedDatabase() { |
| 56 const string16 kKey(ASCIIToUTF16("key")); |
| 57 const string16 kValue(ASCIIToUTF16("value")); |
| 58 ValuesMap values; |
| 59 ReadAllValues(&values); |
| 60 EXPECT_EQ(1u, values.size()); |
| 61 EXPECT_EQ(kValue, values[kKey].string()); |
| 62 } |
| 63 }; |
| 64 }; |
| 65 |
| 66 TEST_F(DomStorageAreaTest, DomStorageAreaBasics) { |
27 scoped_refptr<DomStorageArea> area( | 67 scoped_refptr<DomStorageArea> area( |
28 new DomStorageArea(1, kOrigin, FilePath(), NULL)); | 68 new DomStorageArea(1, kOrigin, FilePath(), NULL)); |
29 string16 old_value; | 69 string16 old_value; |
30 NullableString16 old_nullable_value; | 70 NullableString16 old_nullable_value; |
31 scoped_refptr<DomStorageArea> copy; | 71 scoped_refptr<DomStorageArea> copy; |
32 | 72 |
33 // We don't focus on the underlying DomStorageMap functionality | 73 // We don't focus on the underlying DomStorageMap functionality |
34 // since that's covered by seperate unit tests. | 74 // since that's covered by seperate unit tests. |
35 EXPECT_EQ(kOrigin, area->origin()); | 75 EXPECT_EQ(kOrigin, area->origin()); |
36 EXPECT_EQ(1, area->namespace_id()); | 76 EXPECT_EQ(1, area->namespace_id()); |
37 EXPECT_EQ(0u, area->Length()); | 77 EXPECT_EQ(0u, area->Length()); |
38 area->SetItem(kKey, kValue, &old_nullable_value); | 78 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_nullable_value)); |
39 area->SetItem(kKey2, kValue2, &old_nullable_value); | 79 EXPECT_TRUE(area->SetItem(kKey2, kValue2, &old_nullable_value)); |
40 | 80 |
41 // Verify that a copy shares the same map. | 81 // Verify that a copy shares the same map. |
42 copy = area->ShallowCopy(2); | 82 copy = area->ShallowCopy(2); |
43 EXPECT_EQ(kOrigin, copy->origin()); | 83 EXPECT_EQ(kOrigin, copy->origin()); |
44 EXPECT_EQ(2, copy->namespace_id()); | 84 EXPECT_EQ(2, copy->namespace_id()); |
45 EXPECT_EQ(area->Length(), copy->Length()); | 85 EXPECT_EQ(area->Length(), copy->Length()); |
46 EXPECT_EQ(area->GetItem(kKey).string(), copy->GetItem(kKey).string()); | 86 EXPECT_EQ(area->GetItem(kKey).string(), copy->GetItem(kKey).string()); |
47 EXPECT_EQ(area->Key(0).string(), copy->Key(0).string()); | 87 EXPECT_EQ(area->Key(0).string(), copy->Key(0).string()); |
48 EXPECT_EQ(copy->map_.get(), area->map_.get()); | 88 EXPECT_EQ(copy->map_.get(), area->map_.get()); |
49 | 89 |
50 // But will deep copy-on-write as needed. | 90 // But will deep copy-on-write as needed. |
51 EXPECT_TRUE(area->RemoveItem(kKey, &old_value)); | 91 EXPECT_TRUE(area->RemoveItem(kKey, &old_value)); |
52 EXPECT_NE(copy->map_.get(), area->map_.get()); | 92 EXPECT_NE(copy->map_.get(), area->map_.get()); |
53 copy = area->ShallowCopy(2); | 93 copy = area->ShallowCopy(2); |
54 EXPECT_EQ(copy->map_.get(), area->map_.get()); | 94 EXPECT_EQ(copy->map_.get(), area->map_.get()); |
55 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_nullable_value)); | 95 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_nullable_value)); |
56 EXPECT_NE(copy->map_.get(), area->map_.get()); | 96 EXPECT_NE(copy->map_.get(), area->map_.get()); |
57 copy = area->ShallowCopy(2); | 97 copy = area->ShallowCopy(2); |
58 EXPECT_EQ(copy->map_.get(), area->map_.get()); | 98 EXPECT_EQ(copy->map_.get(), area->map_.get()); |
59 EXPECT_NE(0u, area->Length()); | 99 EXPECT_NE(0u, area->Length()); |
60 EXPECT_TRUE(area->Clear()); | 100 EXPECT_TRUE(area->Clear()); |
61 EXPECT_EQ(0u, area->Length()); | 101 EXPECT_EQ(0u, area->Length()); |
62 EXPECT_NE(copy->map_.get(), area->map_.get()); | 102 EXPECT_NE(copy->map_.get(), area->map_.get()); |
| 103 |
| 104 // Verify that once Shutdown(), behaves that way. |
| 105 area->Shutdown(); |
| 106 EXPECT_TRUE(area->is_shutdown_); |
| 107 EXPECT_FALSE(area->map_.get()); |
| 108 EXPECT_EQ(0u, area->Length()); |
| 109 EXPECT_TRUE(area->Key(0).is_null()); |
| 110 EXPECT_TRUE(area->GetItem(kKey).is_null()); |
| 111 EXPECT_FALSE(area->SetItem(kKey, kValue, &old_nullable_value)); |
| 112 EXPECT_FALSE(area->RemoveItem(kKey, &old_value)); |
| 113 EXPECT_FALSE(area->Clear()); |
63 } | 114 } |
64 | 115 |
65 TEST(DomStorageAreaTest, BackingDatabaseOpened) { | 116 TEST_F(DomStorageAreaTest, BackingDatabaseOpened) { |
66 const int64 kSessionStorageNamespaceId = kLocalStorageNamespaceId + 1; | 117 const int64 kSessionStorageNamespaceId = kLocalStorageNamespaceId + 1; |
67 const GURL kOrigin("http://www.google.com"); | |
68 | |
69 const string16 kKey = ASCIIToUTF16("test"); | |
70 const string16 kKey2 = ASCIIToUTF16("test2"); | |
71 const string16 kValue = ASCIIToUTF16("value"); | |
72 ScopedTempDir temp_dir; | 118 ScopedTempDir temp_dir; |
73 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | 119 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
74 | |
75 const FilePath kExpectedOriginFilePath = temp_dir.path().Append( | 120 const FilePath kExpectedOriginFilePath = temp_dir.path().Append( |
76 DomStorageArea::DatabaseFileNameFromOrigin(kOrigin)); | 121 DomStorageArea::DatabaseFileNameFromOrigin(kOrigin)); |
77 | 122 |
78 // No directory, backing should be null. | 123 // No directory, backing should be null. |
79 { | 124 { |
80 scoped_refptr<DomStorageArea> area( | 125 scoped_refptr<DomStorageArea> area( |
81 new DomStorageArea(kLocalStorageNamespaceId, kOrigin, FilePath(), | 126 new DomStorageArea(kLocalStorageNamespaceId, kOrigin, FilePath(), |
82 NULL)); | 127 NULL)); |
83 EXPECT_EQ(NULL, area->backing_.get()); | 128 EXPECT_EQ(NULL, area->backing_.get()); |
84 EXPECT_TRUE(area->initial_import_done_); | 129 EXPECT_TRUE(area->is_initial_import_done_); |
85 EXPECT_FALSE(file_util::PathExists(kExpectedOriginFilePath)); | 130 EXPECT_FALSE(file_util::PathExists(kExpectedOriginFilePath)); |
86 } | 131 } |
87 | 132 |
88 // Valid directory and origin but non-local namespace id. Backing should | 133 // Valid directory and origin but non-local namespace id. Backing should |
89 // be null. | 134 // be null. |
90 { | 135 { |
91 scoped_refptr<DomStorageArea> area( | 136 scoped_refptr<DomStorageArea> area( |
92 new DomStorageArea(kSessionStorageNamespaceId, kOrigin, | 137 new DomStorageArea(kSessionStorageNamespaceId, kOrigin, |
93 temp_dir.path(), NULL)); | 138 temp_dir.path(), NULL)); |
94 EXPECT_EQ(NULL, area->backing_.get()); | 139 EXPECT_EQ(NULL, area->backing_.get()); |
95 EXPECT_TRUE(area->initial_import_done_); | 140 EXPECT_TRUE(area->is_initial_import_done_); |
96 | 141 |
97 NullableString16 old_value; | 142 NullableString16 old_value; |
98 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value)); | 143 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value)); |
99 ASSERT_TRUE(old_value.is_null()); | 144 ASSERT_TRUE(old_value.is_null()); |
100 | 145 |
101 // Check that saving a value has still left us without a backing database. | 146 // Check that saving a value has still left us without a backing database. |
102 EXPECT_EQ(NULL, area->backing_.get()); | 147 EXPECT_EQ(NULL, area->backing_.get()); |
103 EXPECT_FALSE(file_util::PathExists(kExpectedOriginFilePath)); | 148 EXPECT_FALSE(file_util::PathExists(kExpectedOriginFilePath)); |
104 } | 149 } |
105 | 150 |
106 // This should set up a DomStorageArea that is correctly backed to disk. | 151 // This should set up a DomStorageArea that is correctly backed to disk. |
107 { | 152 { |
108 scoped_refptr<DomStorageArea> area( | 153 scoped_refptr<DomStorageArea> area( |
109 new DomStorageArea(kLocalStorageNamespaceId, kOrigin, | 154 new DomStorageArea(kLocalStorageNamespaceId, kOrigin, |
110 temp_dir.path(), | 155 temp_dir.path(), |
111 new MockDomStorageTaskRunner(base::MessageLoopProxy::current()))); | 156 new MockDomStorageTaskRunner(base::MessageLoopProxy::current()))); |
112 | 157 |
113 EXPECT_TRUE(area->backing_.get()); | 158 EXPECT_TRUE(area->backing_.get()); |
114 EXPECT_FALSE(area->backing_->IsOpen()); | 159 EXPECT_FALSE(area->backing_->IsOpen()); |
115 EXPECT_FALSE(area->initial_import_done_); | 160 EXPECT_FALSE(area->is_initial_import_done_); |
116 | 161 |
117 // Switch out the file-backed db with an in-memory db to speed up the test. | 162 // Inject an in-memory db to speed up the test. |
118 // We will verify that something is written into the database but not | 163 // We will verify that something is written into the database but not |
119 // that a file is written to disk - DOMStorageDatabase unit tests cover | 164 // that a file is written to disk - DOMStorageDatabase unit tests cover |
120 // that. | 165 // that. |
121 area->backing_.reset(new DomStorageDatabase()); | 166 area->backing_.reset(new DomStorageDatabase()); |
122 | 167 |
123 // Need to write something to ensure that the database is created. | 168 // Need to write something to ensure that the database is created. |
124 NullableString16 old_value; | 169 NullableString16 old_value; |
125 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value)); | 170 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value)); |
126 ASSERT_TRUE(old_value.is_null()); | 171 ASSERT_TRUE(old_value.is_null()); |
127 EXPECT_TRUE(area->SetItem(kKey2, kValue, &old_value)); | 172 EXPECT_TRUE(area->is_initial_import_done_); |
128 ASSERT_TRUE(old_value.is_null()); | 173 EXPECT_TRUE(area->commit_batch_.get()); |
129 EXPECT_TRUE(area->initial_import_done_); | 174 EXPECT_FALSE(area->in_flight_commit_batch_.get()); |
130 EXPECT_TRUE(area->commit_in_flight_); | |
131 | 175 |
132 MessageLoop::current()->RunAllPending(); | 176 MessageLoop::current()->RunAllPending(); |
133 | 177 |
134 EXPECT_FALSE(area->commit_in_flight_); | 178 EXPECT_FALSE(area->commit_batch_.get()); |
| 179 EXPECT_FALSE(area->in_flight_commit_batch_.get()); |
135 EXPECT_TRUE(area->backing_->IsOpen()); | 180 EXPECT_TRUE(area->backing_->IsOpen()); |
136 EXPECT_EQ(2u, area->Length()); | 181 EXPECT_EQ(1u, area->Length()); |
137 EXPECT_EQ(kValue, area->GetItem(kKey).string()); | 182 EXPECT_EQ(kValue, area->GetItem(kKey).string()); |
138 | 183 |
139 // Verify the content made it to the in memory database. | 184 // Verify the content made it to the in memory database. |
140 ValuesMap values; | 185 ValuesMap values; |
141 area->backing_->ReadAllValues(&values); | 186 area->backing_->ReadAllValues(&values); |
142 EXPECT_EQ(2u, values.size()); | 187 EXPECT_EQ(1u, values.size()); |
143 EXPECT_EQ(kValue, values[kKey].string()); | 188 EXPECT_EQ(kValue, values[kKey].string()); |
144 } | 189 } |
145 } | 190 } |
146 | 191 |
147 TEST(DomStorageAreaTest, TestDatabaseFilePath) { | 192 TEST_F(DomStorageAreaTest, CommitTasks) { |
| 193 ScopedTempDir temp_dir; |
| 194 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| 195 |
| 196 scoped_refptr<DomStorageArea> area( |
| 197 new DomStorageArea(kLocalStorageNamespaceId, kOrigin, |
| 198 temp_dir.path(), |
| 199 new MockDomStorageTaskRunner(base::MessageLoopProxy::current()))); |
| 200 // Inject an in-memory db to speed up the test. |
| 201 area->backing_.reset(new DomStorageDatabase()); |
| 202 |
| 203 // Unrelated to commits, but while we're here, see that querying Length() |
| 204 // causes the backing database to be opened and presumably read from. |
| 205 EXPECT_FALSE(area->is_initial_import_done_); |
| 206 EXPECT_EQ(0u, area->Length()); |
| 207 EXPECT_TRUE(area->is_initial_import_done_); |
| 208 |
| 209 ValuesMap values; |
| 210 NullableString16 old_value; |
| 211 |
| 212 // See that changes are batched up. |
| 213 EXPECT_FALSE(area->commit_batch_.get()); |
| 214 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value)); |
| 215 EXPECT_TRUE(area->commit_batch_.get()); |
| 216 EXPECT_FALSE(area->commit_batch_->clear_all_first); |
| 217 EXPECT_EQ(1u, area->commit_batch_->changed_values.size()); |
| 218 EXPECT_TRUE(area->SetItem(kKey2, kValue2, &old_value)); |
| 219 EXPECT_TRUE(area->commit_batch_.get()); |
| 220 EXPECT_FALSE(area->commit_batch_->clear_all_first); |
| 221 EXPECT_EQ(2u, area->commit_batch_->changed_values.size()); |
| 222 MessageLoop::current()->RunAllPending(); |
| 223 EXPECT_FALSE(area->commit_batch_.get()); |
| 224 EXPECT_FALSE(area->in_flight_commit_batch_.get()); |
| 225 // Verify the changes made it to the database. |
| 226 values.clear(); |
| 227 area->backing_->ReadAllValues(&values); |
| 228 EXPECT_EQ(2u, values.size()); |
| 229 EXPECT_EQ(kValue, values[kKey].string()); |
| 230 EXPECT_EQ(kValue2, values[kKey2].string()); |
| 231 |
| 232 // See that clear is handled properly. |
| 233 EXPECT_TRUE(area->Clear()); |
| 234 EXPECT_TRUE(area->commit_batch_.get()); |
| 235 EXPECT_TRUE(area->commit_batch_->clear_all_first); |
| 236 EXPECT_TRUE(area->commit_batch_->changed_values.empty()); |
| 237 MessageLoop::current()->RunAllPending(); |
| 238 EXPECT_FALSE(area->commit_batch_.get()); |
| 239 EXPECT_FALSE(area->in_flight_commit_batch_.get()); |
| 240 // Verify the changes made it to the database. |
| 241 values.clear(); |
| 242 area->backing_->ReadAllValues(&values); |
| 243 EXPECT_TRUE(values.empty()); |
| 244 |
| 245 // See that if changes accrue while a commit is "in flight" |
| 246 // those will also get committed. |
| 247 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value)); |
| 248 EXPECT_TRUE(area->commit_batch_.get()); |
| 249 // At this point the OnCommitTimer task has been posted. We inject |
| 250 // another task in the queue that will execute after the timer task, |
| 251 // but before the CommitChanges task. From within our injected task, |
| 252 // we'll make an additional SetItem() call. |
| 253 MessageLoop::current()->PostTask( |
| 254 FROM_HERE, |
| 255 base::Bind(&DomStorageAreaTest::InjectedCommitSequencingTask, |
| 256 base::Unretained(this), area)); |
| 257 MessageLoop::current()->RunAllPending(); |
| 258 EXPECT_TRUE(area->HasOneRef()); |
| 259 EXPECT_FALSE(area->commit_batch_.get()); |
| 260 EXPECT_FALSE(area->in_flight_commit_batch_.get()); |
| 261 // Verify the changes made it to the database. |
| 262 values.clear(); |
| 263 area->backing_->ReadAllValues(&values); |
| 264 EXPECT_EQ(2u, values.size()); |
| 265 EXPECT_EQ(kValue, values[kKey].string()); |
| 266 EXPECT_EQ(kValue2, values[kKey2].string()); |
| 267 } |
| 268 |
| 269 TEST_F(DomStorageAreaTest, CommitChangesAtShutdown) { |
| 270 ScopedTempDir temp_dir; |
| 271 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| 272 scoped_refptr<DomStorageArea> area( |
| 273 new DomStorageArea(kLocalStorageNamespaceId, kOrigin, |
| 274 temp_dir.path(), |
| 275 new MockDomStorageTaskRunner(base::MessageLoopProxy::current()))); |
| 276 |
| 277 // Inject an in-memory db to speed up the test and also to verify |
| 278 // the final changes are commited in it's dtor. |
| 279 area->backing_.reset(new VerifyChangesCommittedDatabase()); |
| 280 |
| 281 ValuesMap values; |
| 282 NullableString16 old_value; |
| 283 EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value)); |
| 284 EXPECT_TRUE(area->commit_batch_.get()); |
| 285 area->backing_->ReadAllValues(&values); |
| 286 EXPECT_TRUE(values.empty()); // not committed yet |
| 287 area->Shutdown(); |
| 288 MessageLoop::current()->RunAllPending(); |
| 289 EXPECT_TRUE(area->HasOneRef()); |
| 290 EXPECT_FALSE(area->backing_.get()); |
| 291 // The VerifyChangesCommittedDatabase destructor verifies values |
| 292 // were committed. |
| 293 } |
| 294 |
| 295 TEST_F(DomStorageAreaTest, TestDatabaseFilePath) { |
148 EXPECT_EQ(FilePath().AppendASCII("file_path_to_0.localstorage"), | 296 EXPECT_EQ(FilePath().AppendASCII("file_path_to_0.localstorage"), |
149 DomStorageArea::DatabaseFileNameFromOrigin( | 297 DomStorageArea::DatabaseFileNameFromOrigin( |
150 GURL("file://path_to/index.html"))); | 298 GURL("file://path_to/index.html"))); |
151 | 299 |
152 EXPECT_EQ(FilePath().AppendASCII("https_www.google.com_0.localstorage"), | 300 EXPECT_EQ(FilePath().AppendASCII("https_www.google.com_0.localstorage"), |
153 DomStorageArea::DatabaseFileNameFromOrigin( | 301 DomStorageArea::DatabaseFileNameFromOrigin( |
154 GURL("https://www.google.com/"))); | 302 GURL("https://www.google.com/"))); |
155 | 303 |
156 EXPECT_EQ(FilePath().AppendASCII("https_www.google.com_8080.localstorage"), | 304 EXPECT_EQ(FilePath().AppendASCII("https_www.google.com_8080.localstorage"), |
157 DomStorageArea::DatabaseFileNameFromOrigin( | 305 DomStorageArea::DatabaseFileNameFromOrigin( |
158 GURL("https://www.google.com:8080"))); | 306 GURL("https://www.google.com:8080"))); |
159 } | 307 } |
160 | 308 |
161 } // namespace dom_storage | 309 } // namespace dom_storage |
OLD | NEW |