1bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h" 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/scoped_temp_dir.h" 8ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h" 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h" 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/sequenced_worker_pool.h" 12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h" 13bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "content/browser/dom_storage/dom_storage_area.h" 14bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "content/browser/dom_storage/dom_storage_context_impl.h" 15bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "content/browser/dom_storage/dom_storage_namespace.h" 16bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "content/browser/dom_storage/dom_storage_task_runner.h" 17bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "content/public/browser/local_storage_usage_info.h" 18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/public/browser/session_storage_namespace.h" 19bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "content/public/browser/session_storage_usage_info.h" 205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "content/public/test/mock_special_storage_policy.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using base::ASCIIToUTF16; 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 25bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochnamespace content { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochclass DOMStorageContextImplTest : public testing::Test { 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 29bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch DOMStorageContextImplTest() 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : kOrigin(GURL("http://dom_storage/")), 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kKey(ASCIIToUTF16("key")), 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kValue(ASCIIToUTF16("value")), 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kDontIncludeFileInfo(false), 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kDoIncludeFileInfo(true) { 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL kOrigin; 38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::string16 kKey; 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::string16 kValue; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const bool kDontIncludeFileInfo; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const bool kDoIncludeFileInfo; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void SetUp() { 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu storage_policy_ = new MockSpecialStoragePolicy; 467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) task_runner_ = 47bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get()); 48bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch context_ = new DOMStorageContextImpl(temp_dir_.path(), 49bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch base::FilePath(), 50bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch storage_policy_.get(), 51bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch task_runner_.get()); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void TearDown() { 55b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::MessageLoop::current()->RunUntilIdle(); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void VerifySingleOriginRemains(const GURL& origin) { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use a new instance to examine the contexts of temp_dir_. 60bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch scoped_refptr<DOMStorageContextImpl> context = 61bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch new DOMStorageContextImpl(temp_dir_.path(), base::FilePath(), 62bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch NULL, NULL); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<LocalStorageUsageInfo> infos; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context->GetLocalStorageUsage(&infos, kDontIncludeFileInfo); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_EQ(1u, infos.size()); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(origin, infos[0].origin); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected: 70b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::MessageLoop message_loop_; 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::ScopedTempDir temp_dir_; 725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu scoped_refptr<MockSpecialStoragePolicy> storage_policy_; 73bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch scoped_refptr<MockDOMStorageTaskRunner> task_runner_; 74bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch scoped_refptr<DOMStorageContextImpl> context_; 75bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch DISALLOW_COPY_AND_ASSIGN(DOMStorageContextImplTest); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 78bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochTEST_F(DOMStorageContextImplTest, Basics) { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This test doesn't do much, checks that the constructor 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // initializes members properly and that invoking methods 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // on a newly created object w/o any data on disk do no harm. 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(temp_dir_.path(), context_->localstorage_directory()); 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_EQ(base::FilePath(), context_->sessionstorage_directory()); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(storage_policy_.get(), context_->special_storage_policy_.get()); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->DeleteLocalStorage(GURL("http://chromium.org/")); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kFirstSessionStorageNamespaceId = 1; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(context_->GetStorageNamespace(kLocalStorageNamespaceId)); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(context_->GetStorageNamespace(kFirstSessionStorageNamespaceId)); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(kFirstSessionStorageNamespaceId, context_->AllocateSessionId()); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<LocalStorageUsageInfo> infos; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->GetLocalStorageUsage(&infos, kDontIncludeFileInfo); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(infos.empty()); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->Shutdown(); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 96bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochTEST_F(DOMStorageContextImplTest, UsageInfo) { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Should be empty initially 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<LocalStorageUsageInfo> infos; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->GetLocalStorageUsage(&infos, kDontIncludeFileInfo); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(infos.empty()); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->GetLocalStorageUsage(&infos, kDoIncludeFileInfo); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(infos.empty()); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Put some data into local storage and shutdown the context 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to ensure data is written to disk. 1067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::NullableString16 old_value; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(context_->GetStorageNamespace(kLocalStorageNamespaceId)-> 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OpenStorageArea(kOrigin)->SetItem(kKey, kValue, &old_value)); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->Shutdown(); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_ = NULL; 111b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::MessageLoop::current()->RunUntilIdle(); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create a new context that points to the same directory, see that 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // it knows about the origin that we stored data for. 115bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch context_ = new DOMStorageContextImpl(temp_dir_.path(), base::FilePath(), 116bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch NULL, NULL); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->GetLocalStorageUsage(&infos, kDontIncludeFileInfo); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(1u, infos.size()); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(kOrigin, infos[0].origin); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(0u, infos[0].data_size); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(base::Time(), infos[0].last_modified); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) infos.clear(); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->GetLocalStorageUsage(&infos, kDoIncludeFileInfo); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(1u, infos.size()); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(kOrigin, infos[0].origin); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_NE(0u, infos[0].data_size); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_NE(base::Time(), infos[0].last_modified); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 130bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochTEST_F(DOMStorageContextImplTest, SessionOnly) { 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL kSessionOnlyOrigin("http://www.sessiononly.com/"); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) storage_policy_->AddSessionOnly(kSessionOnlyOrigin); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Store data for a normal and a session-only origin and then 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // invoke Shutdown() which should delete data for session-only 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // origins. 1377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::NullableString16 old_value; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(context_->GetStorageNamespace(kLocalStorageNamespaceId)-> 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OpenStorageArea(kOrigin)->SetItem(kKey, kValue, &old_value)); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(context_->GetStorageNamespace(kLocalStorageNamespaceId)-> 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OpenStorageArea(kSessionOnlyOrigin)->SetItem(kKey, kValue, &old_value)); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->Shutdown(); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_ = NULL; 144b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::MessageLoop::current()->RunUntilIdle(); 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Verify that the session-only origin data is gone. 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerifySingleOriginRemains(kOrigin); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 150bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochTEST_F(DOMStorageContextImplTest, SetForceKeepSessionState) { 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL kSessionOnlyOrigin("http://www.sessiononly.com/"); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) storage_policy_->AddSessionOnly(kSessionOnlyOrigin); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Store data for a session-only origin, setup to save session data, then 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // shutdown. 1567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::NullableString16 old_value; 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(context_->GetStorageNamespace(kLocalStorageNamespaceId)-> 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OpenStorageArea(kSessionOnlyOrigin)->SetItem(kKey, kValue, &old_value)); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->SetForceKeepSessionState(); // Should override clear behavior. 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->Shutdown(); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_ = NULL; 162b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::MessageLoop::current()->RunUntilIdle(); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerifySingleOriginRemains(kSessionOnlyOrigin); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 167bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochTEST_F(DOMStorageContextImplTest, PersistentIds) { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kFirstSessionStorageNamespaceId = 1; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string kPersistentId = "persistent"; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->CreateSessionNamespace(kFirstSessionStorageNamespaceId, 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kPersistentId); 172bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch DOMStorageNamespace* dom_namespace = 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->GetStorageNamespace(kFirstSessionStorageNamespaceId); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(dom_namespace); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(kPersistentId, dom_namespace->persistent_namespace_id()); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Verify that the areas inherit the persistent ID. 177bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch DOMStorageArea* area = dom_namespace->OpenStorageArea(kOrigin); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(kPersistentId, area->persistent_namespace_id_); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Verify that the persistent IDs are handled correctly when cloning. 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kClonedSessionStorageNamespaceId = 2; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string kClonedPersistentId = "cloned"; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->CloneSessionNamespace(kFirstSessionStorageNamespaceId, 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kClonedSessionStorageNamespaceId, 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kClonedPersistentId); 186bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch DOMStorageNamespace* cloned_dom_namespace = 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->GetStorageNamespace(kClonedSessionStorageNamespaceId); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(dom_namespace); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(kClonedPersistentId, 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cloned_dom_namespace->persistent_namespace_id()); 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Verify that the areas inherit the persistent ID. 192bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch DOMStorageArea* cloned_area = cloned_dom_namespace->OpenStorageArea(kOrigin); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(kClonedPersistentId, cloned_area->persistent_namespace_id_); 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 196bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochTEST_F(DOMStorageContextImplTest, DeleteSessionStorage) { 197bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // Create a DOMStorageContextImpl which will save sessionStorage on disk. 198bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch context_ = new DOMStorageContextImpl(temp_dir_.path(), 199bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch temp_dir_.path(), 200bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch storage_policy_.get(), 201bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch task_runner_.get()); 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->SetSaveSessionStorageOnDisk(); 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_EQ(temp_dir_.path(), context_->sessionstorage_directory()); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Write data. 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kSessionStorageNamespaceId = 1; 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string kPersistentId = "persistent"; 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->CreateSessionNamespace(kSessionStorageNamespaceId, 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kPersistentId); 210bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch DOMStorageNamespace* dom_namespace = 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->GetStorageNamespace(kSessionStorageNamespaceId); 212bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch DOMStorageArea* area = dom_namespace->OpenStorageArea(kOrigin); 213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::string16 kKey(ASCIIToUTF16("foo")); 214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::string16 kValue(ASCIIToUTF16("bar")); 2157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::NullableString16 old_nullable_value; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) area->SetItem(kKey, kValue, &old_nullable_value); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dom_namespace->CloseStorageArea(area); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 219bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // Destroy and recreate the DOMStorageContextImpl. 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->Shutdown(); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_ = NULL; 222b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::MessageLoop::current()->RunUntilIdle(); 223bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch context_ = new DOMStorageContextImpl( 224868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) temp_dir_.path(), temp_dir_.path(), 225868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) storage_policy_.get(), task_runner_.get()); 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->SetSaveSessionStorageOnDisk(); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Read the data back. 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->CreateSessionNamespace(kSessionStorageNamespaceId, 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kPersistentId); 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dom_namespace = context_->GetStorageNamespace(kSessionStorageNamespaceId); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) area = dom_namespace->OpenStorageArea(kOrigin); 2337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::NullableString16 read_value; 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_value = area->GetItem(kKey); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(kValue, read_value.string()); 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dom_namespace->CloseStorageArea(area); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SessionStorageUsageInfo info; 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.origin = kOrigin; 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.persistent_namespace_id = kPersistentId; 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->DeleteSessionStorage(info); 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Destroy and recreate again. 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->Shutdown(); 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_ = NULL; 246b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::MessageLoop::current()->RunUntilIdle(); 247bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch context_ = new DOMStorageContextImpl( 248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) temp_dir_.path(), temp_dir_.path(), 249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) storage_policy_.get(), task_runner_.get()); 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->SetSaveSessionStorageOnDisk(); 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now there should be no data. 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->CreateSessionNamespace(kSessionStorageNamespaceId, 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kPersistentId); 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dom_namespace = context_->GetStorageNamespace(kSessionStorageNamespaceId); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) area = dom_namespace->OpenStorageArea(kOrigin); 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_value = area->GetItem(kKey); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(read_value.is_null()); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dom_namespace->CloseStorageArea(area); 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_->Shutdown(); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context_ = NULL; 262b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::MessageLoop::current()->RunUntilIdle(); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)TEST_F(DOMStorageContextImplTest, SessionStorageAlias) { 266f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const int kFirstSessionStorageNamespaceId = 1; 267f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const std::string kPersistentId = "persistent"; 268f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) context_->CreateSessionNamespace(kFirstSessionStorageNamespaceId, 269f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) kPersistentId); 270f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DOMStorageNamespace* dom_namespace1 = 271f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) context_->GetStorageNamespace(kFirstSessionStorageNamespaceId); 272f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ASSERT_TRUE(dom_namespace1); 273f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DOMStorageArea* area1 = dom_namespace1->OpenStorageArea(kOrigin); 274f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::NullableString16 old_value; 275f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) area1->SetItem(kKey, kValue, &old_value); 276f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) EXPECT_TRUE(old_value.is_null()); 277f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::NullableString16 read_value = area1->GetItem(kKey); 278f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) EXPECT_TRUE(!read_value.is_null() && read_value.string() == kValue); 279f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 280f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Create an alias. 281f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const int kAliasSessionStorageNamespaceId = 2; 282f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) context_->CreateAliasSessionNamespace(kFirstSessionStorageNamespaceId, 283f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) kAliasSessionStorageNamespaceId, 284f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) kPersistentId); 285f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DOMStorageNamespace* dom_namespace2 = 286f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) context_->GetStorageNamespace(kAliasSessionStorageNamespaceId); 287f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ASSERT_TRUE(dom_namespace2); 288f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ASSERT_TRUE(dom_namespace2->alias_master_namespace() == dom_namespace1); 289f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 290f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Verify that read values are identical. 291f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DOMStorageArea* area2 = dom_namespace2->OpenStorageArea(kOrigin); 292f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) read_value = area2->GetItem(kKey); 293f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) EXPECT_TRUE(!read_value.is_null() && read_value.string() == kValue); 294f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 295f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Verify that writes are reflected in both namespaces. 296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const base::string16 kValue2(ASCIIToUTF16("value2")); 297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) area2->SetItem(kKey, kValue2, &old_value); 298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) read_value = area1->GetItem(kKey); 299f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) EXPECT_TRUE(!read_value.is_null() && read_value.string() == kValue2); 300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) dom_namespace1->CloseStorageArea(area1); 301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) dom_namespace2->CloseStorageArea(area2); 302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 303f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // When creating an alias of an alias, ensure that the master relationship 304f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // is collapsed. 305f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const int kAlias2SessionStorageNamespaceId = 3; 306f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) context_->CreateAliasSessionNamespace(kAliasSessionStorageNamespaceId, 307f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) kAlias2SessionStorageNamespaceId, 308f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) kPersistentId); 309f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DOMStorageNamespace* dom_namespace3 = 310f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) context_->GetStorageNamespace(kAlias2SessionStorageNamespaceId); 311f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ASSERT_TRUE(dom_namespace3); 312f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ASSERT_TRUE(dom_namespace3->alias_master_namespace() == dom_namespace1); 313f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 314f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 315f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)TEST_F(DOMStorageContextImplTest, SessionStorageMerge) { 316f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Create a target namespace that we will merge into. 317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const int kTargetSessionStorageNamespaceId = 1; 318f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const std::string kTargetPersistentId = "persistent"; 319f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) context_->CreateSessionNamespace(kTargetSessionStorageNamespaceId, 320f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) kTargetPersistentId); 321f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DOMStorageNamespace* target_ns = 322f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) context_->GetStorageNamespace(kTargetSessionStorageNamespaceId); 323f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ASSERT_TRUE(target_ns); 324f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DOMStorageArea* target_ns_area = target_ns->OpenStorageArea(kOrigin); 325f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::NullableString16 old_value; 326f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const base::string16 kKey2(ASCIIToUTF16("key2")); 327f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const base::string16 kKey2Value(ASCIIToUTF16("key2value")); 328f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) target_ns_area->SetItem(kKey, kValue, &old_value); 329f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) target_ns_area->SetItem(kKey2, kKey2Value, &old_value); 330f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 331f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Create a source namespace & its alias. 332f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const int kSourceSessionStorageNamespaceId = 2; 333f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const int kAliasSessionStorageNamespaceId = 3; 334f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const std::string kSourcePersistentId = "persistent_source"; 335f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) context_->CreateSessionNamespace(kSourceSessionStorageNamespaceId, 336f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) kSourcePersistentId); 337f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) context_->CreateAliasSessionNamespace(kSourceSessionStorageNamespaceId, 338f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) kAliasSessionStorageNamespaceId, 339f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) kSourcePersistentId); 340f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DOMStorageNamespace* alias_ns = 341f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) context_->GetStorageNamespace(kAliasSessionStorageNamespaceId); 342f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ASSERT_TRUE(alias_ns); 343f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 344f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Create a transaction log that can't be merged. 345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const int kPid1 = 10; 346f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ASSERT_FALSE(alias_ns->IsLoggingRenderer(kPid1)); 347f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) alias_ns->AddTransactionLogProcessId(kPid1); 348f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ASSERT_TRUE(alias_ns->IsLoggingRenderer(kPid1)); 349f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const base::string16 kValue2(ASCIIToUTF16("value2")); 350f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DOMStorageNamespace::TransactionRecord txn; 351f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) txn.origin = kOrigin; 352f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) txn.key = kKey; 353f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) txn.value = base::NullableString16(kValue2, false); 354f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) txn.transaction_type = DOMStorageNamespace::TRANSACTION_READ; 355f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) alias_ns->AddTransaction(kPid1, txn); 356f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ASSERT_TRUE(alias_ns->Merge(false, kPid1, target_ns, NULL) == 357f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SessionStorageNamespace::MERGE_RESULT_NOT_MERGEABLE); 358f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 359f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Create a transaction log that can be merged. 360f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const int kPid2 = 20; 361f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) alias_ns->AddTransactionLogProcessId(kPid2); 362f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) txn.transaction_type = DOMStorageNamespace::TRANSACTION_WRITE; 363f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) alias_ns->AddTransaction(kPid2, txn); 364f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ASSERT_TRUE(alias_ns->Merge(true, kPid2, target_ns, NULL) == 365f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SessionStorageNamespace::MERGE_RESULT_MERGEABLE); 366f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 367f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Verify that the merge was successful. 368f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ASSERT_TRUE(alias_ns->alias_master_namespace() == target_ns); 369f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::NullableString16 read_value = target_ns_area->GetItem(kKey); 370f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) EXPECT_TRUE(!read_value.is_null() && read_value.string() == kValue2); 371f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DOMStorageArea* alias_ns_area = alias_ns->OpenStorageArea(kOrigin); 372f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) read_value = alias_ns_area->GetItem(kKey2); 373f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) EXPECT_TRUE(!read_value.is_null() && read_value.string() == kKey2Value); 374f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 375f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 376bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch} // namespace content 377