storage_api_unittest.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// found in the LICENSE file. 4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/command_line.h" 6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/files/file_path.h" 7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/memory/ref_counted.h" 8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/strings/stringprintf.h" 9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/extensions/extension_api_unittest.h" 10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/extensions/test_extension_system.h" 11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/api/storage/leveldb_settings_storage_factory.h" 12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/api/storage/settings_storage_quota_enforcer.h" 13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/api/storage/settings_test_util.h" 14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/api/storage/storage_api.h" 15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/api/storage/storage_frontend.h" 16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/event_router.h" 17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/extension_prefs.h" 18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/extension_system.h" 19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/value_store/leveldb_value_store.h" 20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/value_store/value_store.h" 21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/common/id_util.h" 22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/common/manifest.h" 23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/common/test_util.h" 24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "third_party/leveldatabase/src/include/leveldb/db.h" 25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "third_party/leveldatabase/src/include/leveldb/write_batch.h" 26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace extensions { 28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace { 30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Caller owns the returned object. 32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)KeyedService* CreateStorageFrontendForTesting( 33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) content::BrowserContext* context) { 34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return StorageFrontend::CreateForTesting(new LeveldbSettingsStorageFactory(), 35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) context); 36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} // namespace 39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class StorageApiUnittest : public ExtensionApiUnittest { 41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public: 42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) virtual void SetUp() OVERRIDE { 43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ExtensionApiUnittest::SetUp(); 44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) TestExtensionSystem* extension_system = 45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile())); 46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // StorageFrontend requires an EventRouter. 47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) extension_system->SetEventRouter(scoped_ptr<EventRouter>( 48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) new EventRouter(profile(), ExtensionPrefs::Get(profile())))); 49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) protected: 52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Runs the storage.set() API function with local storage. 53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) void RunSetFunction(const std::string& key, const std::string& value) { 54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) RunFunction( 55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) new StorageStorageAreaSetFunction(), 56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::StringPrintf( 57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) "[\"local\", {\"%s\": \"%s\"}]", key.c_str(), value.c_str())); 58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Runs the storage.get() API function with the local storage, and populates 61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // |value| with the string result. 62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) testing::AssertionResult RunGetFunction(const std::string& key, 63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) std::string* value) { 64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_ptr<base::Value> result = RunFunctionAndReturnValue( 65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) new StorageStorageAreaGetFunction(), 66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::StringPrintf("[\"local\", \"%s\"]", key.c_str())); 675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!result.get()) 685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return testing::AssertionFailure() << "No result"; 69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::DictionaryValue* dict = NULL; 70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!result->GetAsDictionary(&dict)) 71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return testing::AssertionFailure() << result << " was not a dictionary."; 72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!dict->GetString(key, value)) { 73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return testing::AssertionFailure() << " could not retrieve a string from" 74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) << dict << " at " << key; 75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return testing::AssertionSuccess(); 77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}; 79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST_F(StorageApiUnittest, RestoreCorruptedStorage) { 81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Ensure a StorageFrontend can be created on demand. The StorageFrontend 82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // will be owned by the KeyedService system. 83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) StorageFrontend::GetFactoryInstance()->SetTestingFactory( 84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) profile(), &CreateStorageFrontendForTesting); 85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const char kKey[] = "key"; 87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const char kValue[] = "value"; 88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) std::string result; 89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Do a simple set/get combo to make sure the API works. 91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) RunSetFunction(kKey, kValue); 92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_TRUE(RunGetFunction(kKey, &result)); 93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_EQ(kValue, result); 94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Corrupt the store. This is not as pretty as ideal, because we use knowledge 96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // of the underlying structure, but there's no real good way to corrupt a 97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // store other than directly modifying the files. 98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ValueStore* store = 99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) settings_test_util::GetStorage(extension_ref(), 100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) settings_namespace::LOCAL, 101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) StorageFrontend::Get(profile())); 102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ASSERT_TRUE(store); 103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SettingsStorageQuotaEnforcer* quota_store = 104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) static_cast<SettingsStorageQuotaEnforcer*>(store); 105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) LeveldbValueStore* leveldb_store = 106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) static_cast<LeveldbValueStore*>(quota_store->get_delegate_for_test()); 107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) leveldb::WriteBatch batch; 108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) batch.Put(kKey, "[{(.*+\"\'\\"); 109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_TRUE(leveldb_store->WriteToDbForTest(&batch)); 110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_TRUE(leveldb_store->Get(kKey)->IsCorrupted()); 111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Running another set should end up working (even though it will restore the 113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // store behind the scenes). 114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) RunSetFunction(kKey, kValue); 115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_TRUE(RunGetFunction(kKey, &result)); 116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EXPECT_EQ(kValue, result); 117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} // namespace extensions 120