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