| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 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 #include "sync/internal_api/public/model_type_store_backend.h" | |
| 6 | |
| 7 #include "testing/gtest/include/gtest/gtest.h" | |
| 8 #include "third_party/leveldatabase/src/include/leveldb/env.h" | |
| 9 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" | |
| 10 | |
| 11 namespace syncer_v2 { | |
| 12 | |
| 13 class ModelTypeStoreBackendTest : public testing::Test { | |
| 14 public: | |
| 15 scoped_refptr<ModelTypeStoreBackend> GetOrCreateBackend() { | |
| 16 std::string path = "/test_db"; | |
| 17 return GetOrCreateBackendWithPath(path); | |
| 18 } | |
| 19 | |
| 20 scoped_refptr<ModelTypeStoreBackend> GetOrCreateBackendWithPath( | |
| 21 std::string custom_path) { | |
| 22 std::unique_ptr<leveldb::Env> in_memory_env = | |
| 23 ModelTypeStoreBackend::CreateInMemoryEnv(); | |
| 24 std::string path; | |
| 25 in_memory_env->GetTestDirectory(&path); | |
| 26 path += custom_path; | |
| 27 | |
| 28 ModelTypeStore::Result result; | |
| 29 // In-memory store backend works on the same thread as test. | |
| 30 scoped_refptr<ModelTypeStoreBackend> backend = | |
| 31 ModelTypeStoreBackend::GetOrCreateBackend( | |
| 32 path, std::move(in_memory_env), &result); | |
| 33 EXPECT_TRUE(backend.get()); | |
| 34 EXPECT_EQ(result, ModelTypeStore::Result::SUCCESS); | |
| 35 return backend; | |
| 36 } | |
| 37 | |
| 38 bool BackendExistsForPath(std::string path) { | |
| 39 if (ModelTypeStoreBackend::backend_map_.Get().end() == | |
| 40 ModelTypeStoreBackend::backend_map_.Get().find(path)) { | |
| 41 return false; | |
| 42 } | |
| 43 return true; | |
| 44 } | |
| 45 | |
| 46 std::string GetBackendPath(scoped_refptr<ModelTypeStoreBackend> backend) { | |
| 47 return backend->path_; | |
| 48 } | |
| 49 }; | |
| 50 | |
| 51 // Test that after record is written to backend it can be read back even after | |
| 52 // backend is destroyed and recreated in the same environment. | |
| 53 TEST_F(ModelTypeStoreBackendTest, WriteThenRead) { | |
| 54 scoped_refptr<ModelTypeStoreBackend> backend = GetOrCreateBackend(); | |
| 55 | |
| 56 // Write record. | |
| 57 std::unique_ptr<leveldb::WriteBatch> write_batch(new leveldb::WriteBatch()); | |
| 58 write_batch->Put("prefix:id1", "data1"); | |
| 59 ModelTypeStore::Result result = | |
| 60 backend->WriteModifications(std::move(write_batch)); | |
| 61 ASSERT_EQ(ModelTypeStore::Result::SUCCESS, result); | |
| 62 | |
| 63 // Read all records with prefix. | |
| 64 ModelTypeStore::RecordList record_list; | |
| 65 result = backend->ReadAllRecordsWithPrefix("prefix:", &record_list); | |
| 66 ASSERT_EQ(ModelTypeStore::Result::SUCCESS, result); | |
| 67 ASSERT_EQ(1ul, record_list.size()); | |
| 68 ASSERT_EQ("id1", record_list[0].id); | |
| 69 ASSERT_EQ("data1", record_list[0].value); | |
| 70 record_list.clear(); | |
| 71 | |
| 72 // Recreate backend and read all records with prefix. | |
| 73 backend = GetOrCreateBackend(); | |
| 74 result = backend->ReadAllRecordsWithPrefix("prefix:", &record_list); | |
| 75 ASSERT_EQ(ModelTypeStore::Result::SUCCESS, result); | |
| 76 ASSERT_EQ(1ul, record_list.size()); | |
| 77 ASSERT_EQ("id1", record_list[0].id); | |
| 78 ASSERT_EQ("data1", record_list[0].value); | |
| 79 } | |
| 80 | |
| 81 // Test that ReadAllRecordsWithPrefix correclty filters records by prefix. | |
| 82 TEST_F(ModelTypeStoreBackendTest, ReadAllRecordsWithPrefix) { | |
| 83 scoped_refptr<ModelTypeStoreBackend> backend = GetOrCreateBackend(); | |
| 84 | |
| 85 std::unique_ptr<leveldb::WriteBatch> write_batch(new leveldb::WriteBatch()); | |
| 86 write_batch->Put("prefix1:id1", "data1"); | |
| 87 write_batch->Put("prefix2:id2", "data2"); | |
| 88 ModelTypeStore::Result result = | |
| 89 backend->WriteModifications(std::move(write_batch)); | |
| 90 ASSERT_EQ(ModelTypeStore::Result::SUCCESS, result); | |
| 91 | |
| 92 ModelTypeStore::RecordList record_list; | |
| 93 result = backend->ReadAllRecordsWithPrefix("prefix1:", &record_list); | |
| 94 ASSERT_EQ(ModelTypeStore::Result::SUCCESS, result); | |
| 95 ASSERT_EQ(1UL, record_list.size()); | |
| 96 ASSERT_EQ("id1", record_list[0].id); | |
| 97 ASSERT_EQ("data1", record_list[0].value); | |
| 98 } | |
| 99 | |
| 100 // Test that deleted records are correctly marked as milling in results of | |
| 101 // ReadRecordsWithPrefix. | |
| 102 TEST_F(ModelTypeStoreBackendTest, ReadDeletedRecord) { | |
| 103 scoped_refptr<ModelTypeStoreBackend> backend = GetOrCreateBackend(); | |
| 104 | |
| 105 // Create records, ensure they are returned by ReadRecordsWithPrefix. | |
| 106 std::unique_ptr<leveldb::WriteBatch> write_batch(new leveldb::WriteBatch()); | |
| 107 write_batch->Put("prefix:id1", "data1"); | |
| 108 write_batch->Put("prefix:id2", "data2"); | |
| 109 ModelTypeStore::Result result = | |
| 110 backend->WriteModifications(std::move(write_batch)); | |
| 111 ASSERT_EQ(ModelTypeStore::Result::SUCCESS, result); | |
| 112 | |
| 113 ModelTypeStore::IdList id_list; | |
| 114 ModelTypeStore::IdList missing_id_list; | |
| 115 ModelTypeStore::RecordList record_list; | |
| 116 id_list.push_back("id1"); | |
| 117 id_list.push_back("id2"); | |
| 118 result = backend->ReadRecordsWithPrefix("prefix:", id_list, &record_list, | |
| 119 &missing_id_list); | |
| 120 ASSERT_EQ(ModelTypeStore::Result::SUCCESS, result); | |
| 121 ASSERT_EQ(2UL, record_list.size()); | |
| 122 ASSERT_TRUE(missing_id_list.empty()); | |
| 123 | |
| 124 // Delete one record. | |
| 125 write_batch.reset(new leveldb::WriteBatch()); | |
| 126 write_batch->Delete("prefix:id2"); | |
| 127 result = backend->WriteModifications(std::move(write_batch)); | |
| 128 ASSERT_EQ(ModelTypeStore::Result::SUCCESS, result); | |
| 129 | |
| 130 // Ensure deleted record id is returned in missing_id_list. | |
| 131 record_list.clear(); | |
| 132 missing_id_list.clear(); | |
| 133 result = backend->ReadRecordsWithPrefix("prefix:", id_list, &record_list, | |
| 134 &missing_id_list); | |
| 135 ASSERT_EQ(ModelTypeStore::Result::SUCCESS, result); | |
| 136 ASSERT_EQ(1UL, record_list.size()); | |
| 137 ASSERT_EQ("id1", record_list[0].id); | |
| 138 ASSERT_EQ(1UL, missing_id_list.size()); | |
| 139 ASSERT_EQ("id2", missing_id_list[0]); | |
| 140 } | |
| 141 | |
| 142 // Test that only one backend got create when we ask two backend with same path, | |
| 143 // and after de-reference the backend, the backend will be deleted. | |
| 144 TEST_F(ModelTypeStoreBackendTest, TwoSameBackendTest) { | |
| 145 // Create two backend with same path, check if they are reference to same | |
| 146 // address. | |
| 147 scoped_refptr<ModelTypeStoreBackend> backend = GetOrCreateBackend(); | |
| 148 scoped_refptr<ModelTypeStoreBackend> backend_second = GetOrCreateBackend(); | |
| 149 std::string path = GetBackendPath(backend); | |
| 150 ASSERT_EQ(backend.get(), backend_second.get()); | |
| 151 | |
| 152 // Delete one reference, check the real backend still here. | |
| 153 backend = nullptr; | |
| 154 ASSERT_FALSE(backend.get()); | |
| 155 ASSERT_TRUE(backend_second.get()); | |
| 156 ASSERT_TRUE(backend_second->HasOneRef()); | |
| 157 | |
| 158 // Delete another reference, check the real backend is deleted. | |
| 159 backend_second = nullptr; | |
| 160 ASSERT_FALSE(backend_second.get()); | |
| 161 ASSERT_FALSE(BackendExistsForPath(path)); | |
| 162 } | |
| 163 | |
| 164 // Test that two backend got create when we ask two backend with different path, | |
| 165 // and after de-reference two backend, the both backend will be deleted. | |
| 166 TEST_F(ModelTypeStoreBackendTest, TwoDifferentBackendTest) { | |
| 167 // Create two backend with different path, check if they are reference to | |
| 168 // different address. | |
| 169 scoped_refptr<ModelTypeStoreBackend> backend = GetOrCreateBackend(); | |
| 170 scoped_refptr<ModelTypeStoreBackend> backend_second = | |
| 171 GetOrCreateBackendWithPath("/test_db2"); | |
| 172 std::string path = GetBackendPath(backend); | |
| 173 ASSERT_NE(backend.get(), backend_second.get()); | |
| 174 ASSERT_TRUE(backend->HasOneRef()); | |
| 175 ASSERT_TRUE(backend_second->HasOneRef()); | |
| 176 | |
| 177 // delete one backend, check only one got deleted. | |
| 178 backend = nullptr; | |
| 179 ASSERT_FALSE(backend.get()); | |
| 180 ASSERT_TRUE(backend_second.get()); | |
| 181 ASSERT_TRUE(backend_second->HasOneRef()); | |
| 182 ASSERT_FALSE(BackendExistsForPath(path)); | |
| 183 | |
| 184 // delete another backend. | |
| 185 backend_second = nullptr; | |
| 186 ASSERT_FALSE(backend_second.get()); | |
| 187 ASSERT_FALSE(BackendExistsForPath("/test_db2")); | |
| 188 } | |
| 189 | |
| 190 } // namespace syncer_v2 | |
| OLD | NEW |