OLD | NEW |
| (Empty) |
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. | |
4 | |
5 | |
6 #include "webkit/dom_storage/session_storage_database.h" | |
7 | |
8 #include <algorithm> | |
9 #include <map> | |
10 #include <string> | |
11 | |
12 #include "base/file_util.h" | |
13 #include "base/files/scoped_temp_dir.h" | |
14 #include "base/logging.h" | |
15 #include "base/strings/string_number_conversions.h" | |
16 #include "base/utf_string_conversions.h" | |
17 #include "googleurl/src/gurl.h" | |
18 #include "testing/gtest/include/gtest/gtest.h" | |
19 #include "third_party/leveldatabase/src/include/leveldb/db.h" | |
20 #include "third_party/leveldatabase/src/include/leveldb/iterator.h" | |
21 #include "third_party/leveldatabase/src/include/leveldb/options.h" | |
22 #include "webkit/dom_storage/dom_storage_types.h" | |
23 | |
24 namespace dom_storage { | |
25 | |
26 class SessionStorageDatabaseTest : public testing::Test { | |
27 public: | |
28 SessionStorageDatabaseTest(); | |
29 virtual ~SessionStorageDatabaseTest(); | |
30 virtual void SetUp() OVERRIDE; | |
31 | |
32 protected: | |
33 typedef std::map<std::string, std::string> DataMap; | |
34 | |
35 // Helpers. | |
36 static bool IsNamespaceKey(const std::string& key, | |
37 std::string* namespace_id); | |
38 static bool IsNamespaceOriginKey(const std::string& key, | |
39 std::string* namespace_id); | |
40 static bool IsMapRefCountKey(const std::string& key, | |
41 int64* map_id); | |
42 static bool IsMapValueKey(const std::string& key, | |
43 int64* map_id); | |
44 void ResetDatabase(); | |
45 void ReadData(DataMap* data) const; | |
46 void CheckDatabaseConsistency() const; | |
47 void CheckEmptyDatabase() const; | |
48 void DumpData() const; | |
49 void CheckAreaData(const std::string& namespace_id, | |
50 const GURL& origin, | |
51 const ValuesMap& reference) const; | |
52 void CompareValuesMaps(const ValuesMap& map1, const ValuesMap& map2) const; | |
53 void CheckNamespaceIds( | |
54 const std::set<std::string>& expected_namespace_ids) const; | |
55 void CheckOrigins( | |
56 const std::string& namespace_id, | |
57 const std::set<GURL>& expected_origins) const; | |
58 std::string GetMapForArea(const std::string& namespace_id, | |
59 const GURL& origin) const; | |
60 int64 GetMapRefCount(const std::string& map_id) const; | |
61 | |
62 base::ScopedTempDir temp_dir_; | |
63 scoped_refptr<SessionStorageDatabase> db_; | |
64 | |
65 // Test data. | |
66 const GURL kOrigin1; | |
67 const GURL kOrigin2; | |
68 const std::string kNamespace1; | |
69 const std::string kNamespace2; | |
70 const std::string kNamespaceClone; | |
71 const base::string16 kKey1; | |
72 const base::string16 kKey2; | |
73 const base::string16 kKey3; | |
74 const NullableString16 kValue1; | |
75 const NullableString16 kValue2; | |
76 const NullableString16 kValue3; | |
77 const NullableString16 kValue4; | |
78 const NullableString16 kValueNull; | |
79 | |
80 DISALLOW_COPY_AND_ASSIGN(SessionStorageDatabaseTest); | |
81 }; | |
82 | |
83 SessionStorageDatabaseTest::SessionStorageDatabaseTest() | |
84 : kOrigin1("http://www.origin1.com"), | |
85 kOrigin2("http://www.origin2.com"), | |
86 kNamespace1("namespace1"), | |
87 kNamespace2("namespace2"), | |
88 kNamespaceClone("wascloned"), | |
89 kKey1(ASCIIToUTF16("key1")), | |
90 kKey2(ASCIIToUTF16("key2")), | |
91 kKey3(ASCIIToUTF16("key3")), | |
92 kValue1(NullableString16(ASCIIToUTF16("value1"), false)), | |
93 kValue2(NullableString16(ASCIIToUTF16("value2"), false)), | |
94 kValue3(NullableString16(ASCIIToUTF16("value3"), false)), | |
95 kValue4(NullableString16(ASCIIToUTF16("value4"), false)), | |
96 kValueNull(NullableString16(true)) { } | |
97 | |
98 SessionStorageDatabaseTest::~SessionStorageDatabaseTest() { } | |
99 | |
100 void SessionStorageDatabaseTest::SetUp() { | |
101 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
102 ResetDatabase(); | |
103 } | |
104 | |
105 void SessionStorageDatabaseTest::ResetDatabase() { | |
106 db_ = new SessionStorageDatabase(temp_dir_.path()); | |
107 ASSERT_TRUE(db_->LazyOpen(true)); | |
108 } | |
109 | |
110 // static | |
111 bool SessionStorageDatabaseTest::IsNamespaceKey(const std::string& key, | |
112 std::string* namespace_id) { | |
113 std::string namespace_prefix = SessionStorageDatabase::NamespacePrefix(); | |
114 if (key.find(namespace_prefix) != 0) | |
115 return false; | |
116 if (key == namespace_prefix) | |
117 return false; | |
118 | |
119 size_t second_dash = key.find('-', namespace_prefix.length()); | |
120 if (second_dash != key.length() - 1) | |
121 return false; | |
122 | |
123 // Key is of the form "namespace-<namespaceid>-". | |
124 *namespace_id = key.substr( | |
125 namespace_prefix.length(), | |
126 second_dash - namespace_prefix.length()); | |
127 return true; | |
128 } | |
129 | |
130 // static | |
131 bool SessionStorageDatabaseTest::IsNamespaceOriginKey( | |
132 const std::string& key, | |
133 std::string* namespace_id) { | |
134 std::string namespace_prefix = SessionStorageDatabase::NamespacePrefix(); | |
135 if (key.find(namespace_prefix) != 0) | |
136 return false; | |
137 size_t second_dash = key.find('-', namespace_prefix.length()); | |
138 if (second_dash == std::string::npos || second_dash == key.length() - 1) | |
139 return false; | |
140 | |
141 // Key is of the form "namespace-<namespaceid>-<origin>", and the value | |
142 // is the map id. | |
143 *namespace_id = key.substr( | |
144 namespace_prefix.length(), | |
145 second_dash - namespace_prefix.length()); | |
146 return true; | |
147 } | |
148 | |
149 // static | |
150 bool SessionStorageDatabaseTest::IsMapRefCountKey(const std::string& key, | |
151 int64* map_id) { | |
152 std::string map_prefix = "map-"; | |
153 if (key.find(map_prefix) != 0) | |
154 return false; | |
155 size_t second_dash = key.find('-', map_prefix.length()); | |
156 if (second_dash != key.length() - 1) | |
157 return false; | |
158 // Key is of the form "map-<mapid>-" and the value is the ref count. | |
159 std::string map_id_str = key.substr(map_prefix.length(), | |
160 second_dash - map_prefix.length()); | |
161 bool conversion_ok = base::StringToInt64(map_id_str, map_id); | |
162 EXPECT_TRUE(conversion_ok); | |
163 return true; | |
164 } | |
165 | |
166 // static | |
167 bool SessionStorageDatabaseTest::IsMapValueKey(const std::string& key, | |
168 int64* map_id) { | |
169 std::string map_prefix = "map-"; | |
170 if (key.find(map_prefix) != 0) | |
171 return false; | |
172 size_t second_dash = key.find('-', map_prefix.length()); | |
173 if (second_dash == std::string::npos || second_dash == key.length() - 1) | |
174 return false; | |
175 // Key is of the form "map-<mapid>-key". | |
176 std::string map_id_str = key.substr(map_prefix.length(), | |
177 second_dash - map_prefix.length()); | |
178 bool conversion_ok = base::StringToInt64(map_id_str, map_id); | |
179 EXPECT_TRUE(conversion_ok); | |
180 return true; | |
181 } | |
182 | |
183 void SessionStorageDatabaseTest::ReadData(DataMap* data) const { | |
184 leveldb::DB* leveldb = db_->db_.get(); | |
185 scoped_ptr<leveldb::Iterator> it( | |
186 leveldb->NewIterator(leveldb::ReadOptions())); | |
187 for (it->SeekToFirst(); it->Valid(); it->Next()) { | |
188 (*data)[it->key().ToString()] = it->value().ToString(); | |
189 } | |
190 } | |
191 | |
192 void SessionStorageDatabaseTest::CheckDatabaseConsistency() const { | |
193 DataMap data; | |
194 ReadData(&data); | |
195 // Empty db is ok. | |
196 if (data.empty()) | |
197 return; | |
198 | |
199 // For detecting rubbish keys. | |
200 size_t valid_keys = 0; | |
201 | |
202 std::string next_map_id_key = SessionStorageDatabase::NextMapIdKey(); | |
203 // Check the namespace start key. | |
204 if (data.find(SessionStorageDatabase::NamespacePrefix()) == data.end()) { | |
205 // If there is no namespace start key, the database may contain only counter | |
206 // keys. | |
207 for (DataMap::const_iterator it = data.begin(); it != data.end(); ++it) { | |
208 ASSERT_TRUE(it->first == next_map_id_key); | |
209 } | |
210 return; | |
211 } | |
212 ++valid_keys; | |
213 | |
214 // Iterate the "namespace-" keys. | |
215 std::set<std::string> found_namespace_ids; | |
216 std::set<std::string> namespaces_with_areas; | |
217 std::map<int64, int64> expected_map_refcounts; | |
218 int64 max_map_id = -1; | |
219 | |
220 for (DataMap::const_iterator it = data.begin(); it != data.end(); ++it) { | |
221 std::string namespace_id; | |
222 std::string origin; | |
223 if (IsNamespaceKey(it->first, &namespace_id)) { | |
224 found_namespace_ids.insert(namespace_id); | |
225 ++valid_keys; | |
226 } else if (IsNamespaceOriginKey( | |
227 it->first, &namespace_id)) { | |
228 // Check that the corresponding "namespace-<namespaceid>-" key exists. It | |
229 // has been read by now, since the keys are stored in order. | |
230 ASSERT_TRUE(found_namespace_ids.find(namespace_id) != | |
231 found_namespace_ids.end()); | |
232 namespaces_with_areas.insert(namespace_id); | |
233 int64 map_id; | |
234 bool conversion_ok = base::StringToInt64(it->second, &map_id); | |
235 ASSERT_TRUE(conversion_ok); | |
236 ASSERT_GE(map_id, 0); | |
237 ++expected_map_refcounts[map_id]; | |
238 max_map_id = std::max(map_id, max_map_id); | |
239 ++valid_keys; | |
240 } | |
241 } | |
242 // Check that there are no leftover "namespace-namespaceid-" keys without | |
243 // associated areas. | |
244 ASSERT_EQ(found_namespace_ids.size(), namespaces_with_areas.size()); | |
245 | |
246 if (max_map_id != -1) { | |
247 // The database contains maps. | |
248 ASSERT_TRUE(data.find(next_map_id_key) != data.end()); | |
249 int64 next_map_id; | |
250 bool conversion_ok = | |
251 base::StringToInt64(data[next_map_id_key], &next_map_id); | |
252 ASSERT_TRUE(conversion_ok); | |
253 ASSERT_GT(next_map_id, max_map_id); | |
254 } | |
255 | |
256 // Iterate the "map-" keys. | |
257 std::set<int64> found_map_ids; | |
258 for (DataMap::const_iterator it = data.begin(); it != data.end(); ++it) { | |
259 int64 map_id; | |
260 if (IsMapRefCountKey(it->first, &map_id)) { | |
261 int64 ref_count; | |
262 bool conversion_ok = base::StringToInt64(it->second, &ref_count); | |
263 ASSERT_TRUE(conversion_ok); | |
264 // Check that the map is not stale. | |
265 ASSERT_GT(ref_count, 0); | |
266 ASSERT_TRUE(expected_map_refcounts.find(map_id) != | |
267 expected_map_refcounts.end()); | |
268 ASSERT_EQ(expected_map_refcounts[map_id], ref_count); | |
269 // Mark the map as existing. | |
270 expected_map_refcounts.erase(map_id); | |
271 found_map_ids.insert(map_id); | |
272 ++valid_keys; | |
273 } else if (IsMapValueKey(it->first, &map_id)) { | |
274 ASSERT_TRUE(found_map_ids.find(map_id) != found_map_ids.end()); | |
275 ++valid_keys; | |
276 } | |
277 } | |
278 // Check that all maps referred to exist. | |
279 ASSERT_TRUE(expected_map_refcounts.empty()); | |
280 | |
281 if (data.find(next_map_id_key) != data.end()) | |
282 ++valid_keys; | |
283 | |
284 ASSERT_EQ(data.size(), valid_keys); | |
285 } | |
286 | |
287 void SessionStorageDatabaseTest::CheckEmptyDatabase() const { | |
288 DataMap data; | |
289 ReadData(&data); | |
290 size_t valid_keys = 0; | |
291 if (data.find(SessionStorageDatabase::NamespacePrefix()) != data.end()) | |
292 ++valid_keys; | |
293 if (data.find(SessionStorageDatabase::NextMapIdKey()) != data.end()) | |
294 ++valid_keys; | |
295 EXPECT_EQ(valid_keys, data.size()); | |
296 } | |
297 | |
298 void SessionStorageDatabaseTest::DumpData() const { | |
299 LOG(WARNING) << "---- Session storage contents"; | |
300 scoped_ptr<leveldb::Iterator> it( | |
301 db_->db_->NewIterator(leveldb::ReadOptions())); | |
302 for (it->SeekToFirst(); it->Valid(); it->Next()) { | |
303 int64 dummy_map_id; | |
304 if (IsMapValueKey(it->key().ToString(), &dummy_map_id)) { | |
305 // Convert the value back to base::string16. | |
306 base::string16 value; | |
307 size_t len = it->value().size() / sizeof(char16); | |
308 value.resize(len); | |
309 value.assign(reinterpret_cast<const char16*>(it->value().data()), len); | |
310 LOG(WARNING) << it->key().ToString() << ": " << value; | |
311 } else { | |
312 LOG(WARNING) << it->key().ToString() << ": " << it->value().ToString(); | |
313 } | |
314 } | |
315 LOG(WARNING) << "----"; | |
316 } | |
317 | |
318 void SessionStorageDatabaseTest::CheckAreaData( | |
319 const std::string& namespace_id, const GURL& origin, | |
320 const ValuesMap& reference) const { | |
321 ValuesMap values; | |
322 db_->ReadAreaValues(namespace_id, origin, &values); | |
323 CompareValuesMaps(values, reference); | |
324 } | |
325 | |
326 void SessionStorageDatabaseTest::CompareValuesMaps( | |
327 const ValuesMap& map1, | |
328 const ValuesMap& map2) const { | |
329 ASSERT_EQ(map2.size(), map1.size()); | |
330 for (ValuesMap::const_iterator it = map1.begin(); it != map1.end(); ++it) { | |
331 base::string16 key = it->first; | |
332 ASSERT_TRUE(map2.find(key) != map2.end()); | |
333 NullableString16 val1 = it->second; | |
334 NullableString16 val2 = map2.find(key)->second; | |
335 EXPECT_EQ(val2.is_null(), val1.is_null()); | |
336 EXPECT_EQ(val2.string(), val1.string()); | |
337 } | |
338 } | |
339 | |
340 void SessionStorageDatabaseTest::CheckNamespaceIds( | |
341 const std::set<std::string>& expected_namespace_ids) const { | |
342 std::map<std::string, std::vector<GURL> > namespaces_and_origins; | |
343 EXPECT_TRUE(db_->ReadNamespacesAndOrigins(&namespaces_and_origins)); | |
344 EXPECT_EQ(expected_namespace_ids.size(), namespaces_and_origins.size()); | |
345 for (std::map<std::string, std::vector<GURL> >::const_iterator it = | |
346 namespaces_and_origins.begin(); | |
347 it != namespaces_and_origins.end(); ++it) { | |
348 EXPECT_TRUE(expected_namespace_ids.find(it->first) != | |
349 expected_namespace_ids.end()); | |
350 } | |
351 } | |
352 | |
353 void SessionStorageDatabaseTest::CheckOrigins( | |
354 const std::string& namespace_id, | |
355 const std::set<GURL>& expected_origins) const { | |
356 std::map<std::string, std::vector<GURL> > namespaces_and_origins; | |
357 EXPECT_TRUE(db_->ReadNamespacesAndOrigins(&namespaces_and_origins)); | |
358 const std::vector<GURL>& origins = namespaces_and_origins[namespace_id]; | |
359 EXPECT_EQ(expected_origins.size(), origins.size()); | |
360 for (std::vector<GURL>::const_iterator it = origins.begin(); | |
361 it != origins.end(); ++it) { | |
362 EXPECT_TRUE(expected_origins.find(*it) != expected_origins.end()); | |
363 } | |
364 } | |
365 | |
366 std::string SessionStorageDatabaseTest::GetMapForArea( | |
367 const std::string& namespace_id, const GURL& origin) const { | |
368 bool exists; | |
369 std::string map_id; | |
370 EXPECT_TRUE(db_->GetMapForArea(namespace_id, origin.spec(), | |
371 leveldb::ReadOptions(), &exists, &map_id)); | |
372 EXPECT_TRUE(exists); | |
373 return map_id; | |
374 } | |
375 | |
376 int64 SessionStorageDatabaseTest::GetMapRefCount( | |
377 const std::string& map_id) const { | |
378 int64 ref_count; | |
379 EXPECT_TRUE(db_->GetMapRefCount(map_id, &ref_count)); | |
380 return ref_count; | |
381 } | |
382 | |
383 TEST_F(SessionStorageDatabaseTest, EmptyDatabaseSanityCheck) { | |
384 // An empty database should be valid. | |
385 CheckDatabaseConsistency(); | |
386 } | |
387 | |
388 TEST_F(SessionStorageDatabaseTest, WriteDataForOneOrigin) { | |
389 // Keep track on what the values should look like. | |
390 ValuesMap reference; | |
391 // Write data. | |
392 { | |
393 ValuesMap changes; | |
394 changes[kKey1] = kValue1; | |
395 changes[kKey2] = kValue2; | |
396 changes[kKey3] = kValue3; | |
397 reference[kKey1] = kValue1; | |
398 reference[kKey2] = kValue2; | |
399 reference[kKey3] = kValue3; | |
400 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, changes)); | |
401 } | |
402 CheckDatabaseConsistency(); | |
403 CheckAreaData(kNamespace1, kOrigin1, reference); | |
404 | |
405 // Overwrite and delete values. | |
406 { | |
407 ValuesMap changes; | |
408 changes[kKey1] = kValue4; | |
409 changes[kKey3] = kValueNull; | |
410 reference[kKey1] = kValue4; | |
411 reference.erase(kKey3); | |
412 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, changes)); | |
413 } | |
414 CheckDatabaseConsistency(); | |
415 CheckAreaData(kNamespace1, kOrigin1, reference); | |
416 | |
417 // Clear data before writing. | |
418 { | |
419 ValuesMap changes; | |
420 changes[kKey2] = kValue2; | |
421 reference.erase(kKey1); | |
422 reference[kKey2] = kValue2; | |
423 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, true, changes)); | |
424 } | |
425 CheckDatabaseConsistency(); | |
426 CheckAreaData(kNamespace1, kOrigin1, reference); | |
427 } | |
428 | |
429 TEST_F(SessionStorageDatabaseTest, WriteDataForTwoOrigins) { | |
430 // Write data. | |
431 ValuesMap data1; | |
432 data1[kKey1] = kValue1; | |
433 data1[kKey2] = kValue2; | |
434 data1[kKey3] = kValue3; | |
435 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
436 | |
437 ValuesMap data2; | |
438 data2[kKey1] = kValue4; | |
439 data2[kKey2] = kValue1; | |
440 data2[kKey3] = kValue2; | |
441 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); | |
442 | |
443 CheckDatabaseConsistency(); | |
444 CheckAreaData(kNamespace1, kOrigin1, data1); | |
445 CheckAreaData(kNamespace1, kOrigin2, data2); | |
446 } | |
447 | |
448 TEST_F(SessionStorageDatabaseTest, WriteDataForTwoNamespaces) { | |
449 // Write data. | |
450 ValuesMap data11; | |
451 data11[kKey1] = kValue1; | |
452 data11[kKey2] = kValue2; | |
453 data11[kKey3] = kValue3; | |
454 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data11)); | |
455 ValuesMap data12; | |
456 data12[kKey2] = kValue4; | |
457 data12[kKey3] = kValue3; | |
458 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data12)); | |
459 ValuesMap data21; | |
460 data21[kKey1] = kValue2; | |
461 data21[kKey2] = kValue4; | |
462 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace2, kOrigin1, false, data21)); | |
463 ValuesMap data22; | |
464 data22[kKey2] = kValue1; | |
465 data22[kKey3] = kValue2; | |
466 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace2, kOrigin2, false, data22)); | |
467 CheckDatabaseConsistency(); | |
468 CheckAreaData(kNamespace1, kOrigin1, data11); | |
469 CheckAreaData(kNamespace1, kOrigin2, data12); | |
470 CheckAreaData(kNamespace2, kOrigin1, data21); | |
471 CheckAreaData(kNamespace2, kOrigin2, data22); | |
472 } | |
473 | |
474 TEST_F(SessionStorageDatabaseTest, ShallowCopy) { | |
475 // Write data for a namespace, for 2 origins. | |
476 ValuesMap data1; | |
477 data1[kKey1] = kValue1; | |
478 data1[kKey2] = kValue2; | |
479 data1[kKey3] = kValue3; | |
480 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
481 ValuesMap data2; | |
482 data2[kKey1] = kValue2; | |
483 data2[kKey3] = kValue1; | |
484 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); | |
485 // Make a shallow copy. | |
486 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); | |
487 // Now both namespaces should have the same data. | |
488 CheckDatabaseConsistency(); | |
489 CheckAreaData(kNamespace1, kOrigin1, data1); | |
490 CheckAreaData(kNamespace1, kOrigin2, data2); | |
491 CheckAreaData(kNamespaceClone, kOrigin1, data1); | |
492 CheckAreaData(kNamespaceClone, kOrigin2, data2); | |
493 // Both the namespaces refer to the same maps. | |
494 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin1), | |
495 GetMapForArea(kNamespaceClone, kOrigin1)); | |
496 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin2), | |
497 GetMapForArea(kNamespaceClone, kOrigin2)); | |
498 EXPECT_EQ(2, GetMapRefCount(GetMapForArea(kNamespace1, kOrigin1))); | |
499 EXPECT_EQ(2, GetMapRefCount(GetMapForArea(kNamespace1, kOrigin2))); | |
500 } | |
501 | |
502 TEST_F(SessionStorageDatabaseTest, WriteIntoShallowCopy) { | |
503 ValuesMap data1; | |
504 data1[kKey1] = kValue1; | |
505 data1[kKey2] = kValue2; | |
506 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
507 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); | |
508 | |
509 // Write data into a shallow copy. | |
510 ValuesMap changes; | |
511 ValuesMap reference; | |
512 changes[kKey1] = kValueNull; | |
513 changes[kKey2] = kValue4; | |
514 changes[kKey3] = kValue4; | |
515 reference[kKey2] = kValue4; | |
516 reference[kKey3] = kValue4; | |
517 EXPECT_TRUE(db_->CommitAreaChanges(kNamespaceClone, kOrigin1, false, | |
518 changes)); | |
519 | |
520 // Values in the original namespace were not changed. | |
521 CheckAreaData(kNamespace1, kOrigin1, data1); | |
522 // But values in the copy were. | |
523 CheckAreaData(kNamespaceClone, kOrigin1, reference); | |
524 | |
525 // The namespaces no longer refer to the same map. | |
526 EXPECT_NE(GetMapForArea(kNamespace1, kOrigin1), | |
527 GetMapForArea(kNamespaceClone, kOrigin1)); | |
528 EXPECT_EQ(1, GetMapRefCount(GetMapForArea(kNamespace1, kOrigin1))); | |
529 EXPECT_EQ(1, GetMapRefCount(GetMapForArea(kNamespaceClone, kOrigin1))); | |
530 } | |
531 | |
532 TEST_F(SessionStorageDatabaseTest, ManyShallowCopies) { | |
533 // Write data for a namespace, for 2 origins. | |
534 ValuesMap data1; | |
535 data1[kKey1] = kValue1; | |
536 data1[kKey2] = kValue2; | |
537 data1[kKey3] = kValue3; | |
538 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
539 ValuesMap data2; | |
540 data2[kKey1] = kValue2; | |
541 data2[kKey3] = kValue1; | |
542 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); | |
543 | |
544 // Make a two shallow copies. | |
545 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); | |
546 std::string another_clone("another_cloned"); | |
547 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, another_clone)); | |
548 | |
549 // Make a shallow copy of a shallow copy. | |
550 std::string clone_of_clone("clone_of_clone"); | |
551 EXPECT_TRUE(db_->CloneNamespace(another_clone, clone_of_clone)); | |
552 | |
553 // Now all namespaces should have the same data. | |
554 CheckDatabaseConsistency(); | |
555 CheckAreaData(kNamespace1, kOrigin1, data1); | |
556 CheckAreaData(kNamespaceClone, kOrigin1, data1); | |
557 CheckAreaData(another_clone, kOrigin1, data1); | |
558 CheckAreaData(clone_of_clone, kOrigin1, data1); | |
559 CheckAreaData(kNamespace1, kOrigin2, data2); | |
560 CheckAreaData(kNamespaceClone, kOrigin2, data2); | |
561 CheckAreaData(another_clone, kOrigin2, data2); | |
562 CheckAreaData(clone_of_clone, kOrigin2, data2); | |
563 | |
564 // All namespaces refer to the same maps. | |
565 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin1), | |
566 GetMapForArea(kNamespaceClone, kOrigin1)); | |
567 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin2), | |
568 GetMapForArea(kNamespaceClone, kOrigin2)); | |
569 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin1), | |
570 GetMapForArea(another_clone, kOrigin1)); | |
571 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin2), | |
572 GetMapForArea(another_clone, kOrigin2)); | |
573 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin1), | |
574 GetMapForArea(clone_of_clone, kOrigin1)); | |
575 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin2), | |
576 GetMapForArea(clone_of_clone, kOrigin2)); | |
577 | |
578 // Check the ref counts. | |
579 EXPECT_EQ(4, GetMapRefCount(GetMapForArea(kNamespace1, kOrigin1))); | |
580 EXPECT_EQ(4, GetMapRefCount(GetMapForArea(kNamespace1, kOrigin2))); | |
581 } | |
582 | |
583 TEST_F(SessionStorageDatabaseTest, DisassociateShallowCopy) { | |
584 ValuesMap data1; | |
585 data1[kKey1] = kValue1; | |
586 data1[kKey2] = kValue2; | |
587 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
588 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); | |
589 | |
590 // Disassoaciate the shallow copy. | |
591 EXPECT_TRUE(db_->DeleteArea(kNamespaceClone, kOrigin1)); | |
592 CheckDatabaseConsistency(); | |
593 | |
594 // Now new data can be written to that map. | |
595 ValuesMap reference; | |
596 ValuesMap changes; | |
597 changes[kKey1] = kValueNull; | |
598 changes[kKey2] = kValue4; | |
599 changes[kKey3] = kValue4; | |
600 reference[kKey2] = kValue4; | |
601 reference[kKey3] = kValue4; | |
602 EXPECT_TRUE(db_->CommitAreaChanges(kNamespaceClone, kOrigin1, false, | |
603 changes)); | |
604 | |
605 // Values in the original map were not changed. | |
606 CheckAreaData(kNamespace1, kOrigin1, data1); | |
607 | |
608 // But values in the disassociated map were. | |
609 CheckAreaData(kNamespaceClone, kOrigin1, reference); | |
610 } | |
611 | |
612 TEST_F(SessionStorageDatabaseTest, DeleteNamespace) { | |
613 ValuesMap data1; | |
614 data1[kKey1] = kValue1; | |
615 data1[kKey2] = kValue2; | |
616 data1[kKey3] = kValue3; | |
617 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
618 ValuesMap data2; | |
619 data2[kKey2] = kValue4; | |
620 data2[kKey3] = kValue3; | |
621 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); | |
622 EXPECT_TRUE(db_->DeleteNamespace(kNamespace1)); | |
623 CheckDatabaseConsistency(); | |
624 CheckEmptyDatabase(); | |
625 } | |
626 | |
627 TEST_F(SessionStorageDatabaseTest, DeleteNamespaceWithShallowCopy) { | |
628 // Write data for a namespace, for 2 origins. | |
629 ValuesMap data1; | |
630 data1[kKey1] = kValue1; | |
631 data1[kKey2] = kValue2; | |
632 data1[kKey3] = kValue3; | |
633 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
634 ValuesMap data2; | |
635 data2[kKey1] = kValue2; | |
636 data2[kKey3] = kValue1; | |
637 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); | |
638 | |
639 // Make a shallow copy and delete the original namespace. | |
640 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); | |
641 EXPECT_TRUE(db_->DeleteNamespace(kNamespace1)); | |
642 | |
643 // The original namespace has no data. | |
644 CheckDatabaseConsistency(); | |
645 CheckAreaData(kNamespace1, kOrigin1, ValuesMap()); | |
646 CheckAreaData(kNamespace1, kOrigin2, ValuesMap()); | |
647 // But the copy persists. | |
648 CheckAreaData(kNamespaceClone, kOrigin1, data1); | |
649 CheckAreaData(kNamespaceClone, kOrigin2, data2); | |
650 } | |
651 | |
652 TEST_F(SessionStorageDatabaseTest, DeleteArea) { | |
653 // Write data for a namespace, for 2 origins. | |
654 ValuesMap data1; | |
655 data1[kKey1] = kValue1; | |
656 data1[kKey2] = kValue2; | |
657 data1[kKey3] = kValue3; | |
658 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
659 ValuesMap data2; | |
660 data2[kKey1] = kValue2; | |
661 data2[kKey3] = kValue1; | |
662 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); | |
663 | |
664 EXPECT_TRUE(db_->DeleteArea(kNamespace1, kOrigin2)); | |
665 CheckDatabaseConsistency(); | |
666 // The data for the non-deleted origin persists. | |
667 CheckAreaData(kNamespace1, kOrigin1, data1); | |
668 // The data for the deleted origin is gone. | |
669 CheckAreaData(kNamespace1, kOrigin2, ValuesMap()); | |
670 } | |
671 | |
672 TEST_F(SessionStorageDatabaseTest, DeleteAreaWithShallowCopy) { | |
673 // Write data for a namespace, for 2 origins. | |
674 ValuesMap data1; | |
675 data1[kKey1] = kValue1; | |
676 data1[kKey2] = kValue2; | |
677 data1[kKey3] = kValue3; | |
678 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
679 ValuesMap data2; | |
680 data2[kKey1] = kValue2; | |
681 data2[kKey3] = kValue1; | |
682 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); | |
683 | |
684 // Make a shallow copy and delete an origin from the original namespace. | |
685 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); | |
686 EXPECT_TRUE(db_->DeleteArea(kNamespace1, kOrigin1)); | |
687 CheckDatabaseConsistency(); | |
688 | |
689 // The original namespace has data for only the non-deleted origin. | |
690 CheckAreaData(kNamespace1, kOrigin1, ValuesMap()); | |
691 CheckAreaData(kNamespace1, kOrigin2, data2); | |
692 // But the copy persists. | |
693 CheckAreaData(kNamespaceClone, kOrigin1, data1); | |
694 CheckAreaData(kNamespaceClone, kOrigin2, data2); | |
695 } | |
696 | |
697 TEST_F(SessionStorageDatabaseTest, WriteRawBytes) { | |
698 // Write data which is not valid utf8 and contains null bytes. | |
699 unsigned char raw_data[10] = {255, 0, 0, 0, 1, 2, 3, 4, 5, 0}; | |
700 ValuesMap changes; | |
701 base::string16 string_with_raw_data; | |
702 string_with_raw_data.assign(reinterpret_cast<char16*>(raw_data), 5); | |
703 changes[kKey1] = NullableString16(string_with_raw_data, false); | |
704 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, changes)); | |
705 CheckDatabaseConsistency(); | |
706 ValuesMap values; | |
707 db_->ReadAreaValues(kNamespace1, kOrigin1, &values); | |
708 const unsigned char* data = | |
709 reinterpret_cast<const unsigned char*>(values[kKey1].string().data()); | |
710 for (int i = 0; i < 10; ++i) | |
711 EXPECT_EQ(raw_data[i], data[i]); | |
712 } | |
713 | |
714 TEST_F(SessionStorageDatabaseTest, DeleteNamespaceConfusion) { | |
715 // Regression test for a bug where a namespace with id 10 prevented deleting | |
716 // the namespace with id 1. | |
717 | |
718 ValuesMap data1; | |
719 data1[kKey1] = kValue1; | |
720 ASSERT_TRUE(db_->CommitAreaChanges("foobar", kOrigin1, false, data1)); | |
721 ASSERT_TRUE(db_->CommitAreaChanges("foobarbaz", kOrigin1, false, data1)); | |
722 | |
723 // Delete the namespace with ID 1. | |
724 EXPECT_TRUE(db_->DeleteNamespace("foobar")); | |
725 } | |
726 | |
727 TEST_F(SessionStorageDatabaseTest, ReadNamespaceIds) { | |
728 ValuesMap data1; | |
729 data1[kKey1] = kValue1; | |
730 data1[kKey2] = kValue2; | |
731 data1[kKey3] = kValue3; | |
732 std::set<std::string> expected_namespace_ids; | |
733 | |
734 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
735 expected_namespace_ids.insert(kNamespace1); | |
736 CheckNamespaceIds(expected_namespace_ids); | |
737 | |
738 ASSERT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); | |
739 expected_namespace_ids.insert(kNamespaceClone); | |
740 CheckNamespaceIds(expected_namespace_ids); | |
741 | |
742 ASSERT_TRUE(db_->DeleteNamespace(kNamespace1)); | |
743 expected_namespace_ids.erase(kNamespace1); | |
744 CheckNamespaceIds(expected_namespace_ids); | |
745 | |
746 CheckDatabaseConsistency(); | |
747 } | |
748 | |
749 TEST_F(SessionStorageDatabaseTest, ReadNamespaceIdsInEmptyDatabase) { | |
750 std::set<std::string> expected_namespace_ids; | |
751 CheckNamespaceIds(expected_namespace_ids); | |
752 } | |
753 | |
754 TEST_F(SessionStorageDatabaseTest, ReadOriginsInNamespace) { | |
755 ValuesMap data1; | |
756 data1[kKey1] = kValue1; | |
757 data1[kKey2] = kValue2; | |
758 data1[kKey3] = kValue3; | |
759 | |
760 std::set<GURL> expected_origins1; | |
761 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
762 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data1)); | |
763 expected_origins1.insert(kOrigin1); | |
764 expected_origins1.insert(kOrigin2); | |
765 CheckOrigins(kNamespace1, expected_origins1); | |
766 | |
767 std::set<GURL> expected_origins2; | |
768 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace2, kOrigin2, false, data1)); | |
769 expected_origins2.insert(kOrigin2); | |
770 CheckOrigins(kNamespace2, expected_origins2); | |
771 | |
772 ASSERT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); | |
773 CheckOrigins(kNamespaceClone, expected_origins1); | |
774 | |
775 ASSERT_TRUE(db_->DeleteArea(kNamespace1, kOrigin2)); | |
776 expected_origins1.erase(kOrigin2); | |
777 CheckOrigins(kNamespace1, expected_origins1); | |
778 | |
779 CheckDatabaseConsistency(); | |
780 } | |
781 | |
782 TEST_F(SessionStorageDatabaseTest, DeleteAllOrigins) { | |
783 // Write data for a namespace, for 2 origins. | |
784 ValuesMap data1; | |
785 data1[kKey1] = kValue1; | |
786 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
787 ValuesMap data2; | |
788 data2[kKey1] = kValue2; | |
789 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); | |
790 | |
791 EXPECT_TRUE(db_->DeleteArea(kNamespace1, kOrigin1)); | |
792 EXPECT_TRUE(db_->DeleteArea(kNamespace1, kOrigin2)); | |
793 // Check that also the namespace start key was deleted. | |
794 CheckDatabaseConsistency(); | |
795 } | |
796 | |
797 | |
798 } // namespace dom_storage | |
OLD | NEW |