mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 1 | // Copyright 2016 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 "content/browser/leveldb_wrapper_impl.h" |
| 6 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 7 | #include "base/atomic_ref_count.h" |
| 8 | #include "base/bind.h" |
fdoray | ba12142 | 2016-12-23 19:51:48 | [diff] [blame] | 9 | #include "base/memory/ptr_util.h" |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 10 | #include "base/run_loop.h" |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 11 | #include "base/strings/string_number_conversions.h" |
| 12 | #include "base/task_runner_util.h" |
| 13 | #include "base/task_scheduler/post_task.h" |
| 14 | #include "base/test/test_simple_task_runner.h" |
| 15 | #include "base/threading/thread.h" |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 16 | #include "components/leveldb/public/cpp/util.h" |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 17 | #include "components/leveldb/public/interfaces/leveldb.mojom.h" |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 18 | #include "content/public/test/test_browser_thread_bundle.h" |
Daniel Murphy | 47b1223 | 2017-11-07 21:04:26 | [diff] [blame] | 19 | #include "content/test/fake_leveldb_database.h" |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 20 | #include "mojo/public/cpp/bindings/associated_binding.h" |
mek | a3b1e3d | 2016-12-22 17:18:08 | [diff] [blame] | 21 | #include "mojo/public/cpp/bindings/strong_associated_binding.h" |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 22 | #include "mojo/public/cpp/bindings/strong_binding.h" |
| 23 | #include "testing/gmock/include/gmock/gmock.h" |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 24 | #include "testing/gtest/include/gtest/gtest.h" |
| 25 | |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 26 | namespace content { |
| 27 | |
| 28 | namespace { |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 29 | using CacheMode = LevelDBWrapperImpl::CacheMode; |
| 30 | using DatabaseError = leveldb::mojom::DatabaseError; |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 31 | |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 32 | const char* kTestSource = "source"; |
| 33 | const size_t kTestSizeLimit = 512; |
| 34 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 35 | std::string ToString(const std::vector<uint8_t>& input) { |
| 36 | return leveldb::Uint8VectorToStdString(input); |
| 37 | } |
| 38 | |
| 39 | std::vector<uint8_t> ToBytes(const std::string& input) { |
| 40 | return leveldb::StdStringToUint8Vector(input); |
| 41 | } |
| 42 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 43 | class InternalIncrementalBarrier { |
| 44 | public: |
| 45 | InternalIncrementalBarrier(base::OnceClosure done_closure) |
| 46 | : num_callbacks_left_(1), done_closure_(std::move(done_closure)) {} |
| 47 | |
| 48 | void Dec() { |
| 49 | // This is the same as in BarrierClosure. |
| 50 | DCHECK(!num_callbacks_left_.IsZero()); |
| 51 | if (!num_callbacks_left_.Decrement()) { |
| 52 | base::OnceClosure done = std::move(done_closure_); |
| 53 | delete this; |
| 54 | std::move(done).Run(); |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | base::OnceClosure Inc() { |
| 59 | num_callbacks_left_.Increment(); |
| 60 | return base::BindOnce(&InternalIncrementalBarrier::Dec, |
| 61 | base::Unretained(this)); |
| 62 | } |
| 63 | |
| 64 | private: |
| 65 | base::AtomicRefCount num_callbacks_left_; |
| 66 | base::OnceClosure done_closure_; |
| 67 | |
| 68 | DISALLOW_COPY_AND_ASSIGN(InternalIncrementalBarrier); |
| 69 | }; |
| 70 | |
| 71 | // The callbacks returned by Get might get called after destruction of this |
| 72 | // class (and thus the done_closure), so there needs to be an internal class |
| 73 | // to hold the final callback & manage the refcount. |
| 74 | class IncrementalBarrier { |
| 75 | public: |
| 76 | explicit IncrementalBarrier(base::OnceClosure done_closure) |
| 77 | : internal_barrier_( |
| 78 | new InternalIncrementalBarrier(std::move(done_closure))) {} |
| 79 | |
| 80 | ~IncrementalBarrier() { internal_barrier_->Dec(); } |
| 81 | |
| 82 | base::OnceClosure Get() { return internal_barrier_->Inc(); } |
| 83 | |
| 84 | private: |
| 85 | InternalIncrementalBarrier* internal_barrier_; // self-deleting |
| 86 | |
| 87 | DISALLOW_COPY_AND_ASSIGN(IncrementalBarrier); |
| 88 | }; |
| 89 | |
mek | a3b1e3d | 2016-12-22 17:18:08 | [diff] [blame] | 90 | class GetAllCallback : public mojom::LevelDBWrapperGetAllCallback { |
| 91 | public: |
| 92 | static mojom::LevelDBWrapperGetAllCallbackAssociatedPtrInfo CreateAndBind( |
mek | a3b1e3d | 2016-12-22 17:18:08 | [diff] [blame] | 93 | bool* result, |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 94 | base::OnceClosure callback) { |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 95 | mojom::LevelDBWrapperGetAllCallbackAssociatedPtr ptr; |
| 96 | auto request = mojo::MakeRequestAssociatedWithDedicatedPipe(&ptr); |
mek | a3b1e3d | 2016-12-22 17:18:08 | [diff] [blame] | 97 | mojo::MakeStrongAssociatedBinding( |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 98 | base::WrapUnique(new GetAllCallback(result, std::move(callback))), |
mek | a3b1e3d | 2016-12-22 17:18:08 | [diff] [blame] | 99 | std::move(request)); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 100 | return ptr.PassInterface(); |
mek | a3b1e3d | 2016-12-22 17:18:08 | [diff] [blame] | 101 | } |
| 102 | |
| 103 | private: |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 104 | GetAllCallback(bool* result, base::OnceClosure callback) |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 105 | : result_(result), callback_(std::move(callback)) {} |
mek | a3b1e3d | 2016-12-22 17:18:08 | [diff] [blame] | 106 | void Complete(bool success) override { |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 107 | *result_ = success; |
| 108 | if (callback_) |
| 109 | std::move(callback_).Run(); |
mek | a3b1e3d | 2016-12-22 17:18:08 | [diff] [blame] | 110 | } |
| 111 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 112 | bool* result_; |
| 113 | base::OnceClosure callback_; |
mek | a3b1e3d | 2016-12-22 17:18:08 | [diff] [blame] | 114 | }; |
| 115 | |
mek | 222214f | 2017-01-17 21:30:51 | [diff] [blame] | 116 | class MockDelegate : public LevelDBWrapperImpl::Delegate { |
| 117 | public: |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 118 | MockDelegate() {} |
| 119 | ~MockDelegate() override {} |
| 120 | |
mek | 222214f | 2017-01-17 21:30:51 | [diff] [blame] | 121 | void OnNoBindings() override {} |
| 122 | std::vector<leveldb::mojom::BatchedOperationPtr> PrepareToCommit() override { |
| 123 | return std::vector<leveldb::mojom::BatchedOperationPtr>(); |
| 124 | } |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 125 | void DidCommit(DatabaseError error) override { |
| 126 | if (error != DatabaseError::OK) |
| 127 | LOG(ERROR) << "error committing!"; |
| 128 | if (committed_) |
| 129 | std::move(committed_).Run(); |
| 130 | } |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 131 | void OnMapLoaded(DatabaseError error) override { map_load_count_++; } |
Marijn Kruisselbrink | e8fdb3d | 2017-09-26 01:33:07 | [diff] [blame] | 132 | std::vector<LevelDBWrapperImpl::Change> FixUpData( |
| 133 | const LevelDBWrapperImpl::ValueMap& data) override { |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 134 | return std::move(mock_changes_); |
Marijn Kruisselbrink | e8fdb3d | 2017-09-26 01:33:07 | [diff] [blame] | 135 | } |
mek | dea811df | 2017-03-01 17:57:57 | [diff] [blame] | 136 | |
| 137 | int map_load_count() const { return map_load_count_; } |
Marijn Kruisselbrink | e8fdb3d | 2017-09-26 01:33:07 | [diff] [blame] | 138 | void set_mock_changes(std::vector<LevelDBWrapperImpl::Change> changes) { |
| 139 | mock_changes_ = std::move(changes); |
| 140 | } |
mek | dea811df | 2017-03-01 17:57:57 | [diff] [blame] | 141 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 142 | void SetDidCommitCallback(base::OnceClosure committed) { |
| 143 | committed_ = std::move(committed); |
| 144 | } |
| 145 | |
mek | dea811df | 2017-03-01 17:57:57 | [diff] [blame] | 146 | private: |
| 147 | int map_load_count_ = 0; |
Marijn Kruisselbrink | e8fdb3d | 2017-09-26 01:33:07 | [diff] [blame] | 148 | std::vector<LevelDBWrapperImpl::Change> mock_changes_; |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 149 | base::OnceClosure committed_; |
mek | 222214f | 2017-01-17 21:30:51 | [diff] [blame] | 150 | }; |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 151 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 152 | void GetCallback(base::OnceClosure callback, |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 153 | bool* success_out, |
| 154 | std::vector<uint8_t>* value_out, |
| 155 | bool success, |
| 156 | const std::vector<uint8_t>& value) { |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 157 | *success_out = success; |
| 158 | *value_out = value; |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 159 | std::move(callback).Run(); |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 160 | } |
| 161 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 162 | base::OnceCallback<void(bool, const std::vector<uint8_t>&)> MakeGetCallback( |
| 163 | base::OnceClosure callback, |
| 164 | bool* success_out, |
| 165 | std::vector<uint8_t>* value_out) { |
| 166 | return base::BindOnce(&GetCallback, std::move(callback), success_out, |
| 167 | value_out); |
| 168 | } |
| 169 | |
| 170 | void GetAllDataCallback(leveldb::mojom::DatabaseError* status_out, |
| 171 | std::vector<mojom::KeyValuePtr>* data_out, |
| 172 | leveldb::mojom::DatabaseError status, |
| 173 | std::vector<mojom::KeyValuePtr> data) { |
| 174 | *status_out = status; |
| 175 | *data_out = std::move(data); |
| 176 | } |
| 177 | |
| 178 | base::OnceCallback<void(leveldb::mojom::DatabaseError status, |
| 179 | std::vector<mojom::KeyValuePtr> data)> |
| 180 | MakeGetAllCallback(leveldb::mojom::DatabaseError* status_out, |
| 181 | std::vector<mojom::KeyValuePtr>* data_out) { |
| 182 | return base::BindOnce(&GetAllDataCallback, status_out, data_out); |
| 183 | } |
| 184 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 185 | void SuccessCallback(base::OnceClosure callback, |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 186 | bool* success_out, |
| 187 | bool success) { |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 188 | *success_out = success; |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 189 | std::move(callback).Run(); |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 190 | } |
| 191 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 192 | base::OnceCallback<void(bool)> MakeSuccessCallback(base::OnceClosure callback, |
| 193 | bool* success_out) { |
| 194 | return base::BindOnce(&SuccessCallback, std::move(callback), success_out); |
| 195 | } |
| 196 | |
mek | a9c2a3c1 | 2016-12-29 20:50:18 | [diff] [blame] | 197 | void NoOpSuccessCallback(bool success) {} |
| 198 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 199 | LevelDBWrapperImpl::Options GetDefaultTestingOptions(CacheMode cache_mode) { |
| 200 | LevelDBWrapperImpl::Options options; |
| 201 | options.max_size = kTestSizeLimit; |
| 202 | options.default_commit_delay = base::TimeDelta::FromSeconds(5); |
| 203 | options.max_bytes_per_hour = 10 * 1024 * 1024; |
| 204 | options.max_commits_per_hour = 60; |
| 205 | options.cache_mode = cache_mode; |
| 206 | return options; |
| 207 | } |
| 208 | |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 209 | } // namespace |
| 210 | |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 211 | class LevelDBWrapperImplTest : public testing::Test, |
| 212 | public mojom::LevelDBObserver { |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 213 | public: |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 214 | struct Observation { |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 215 | enum { kAdd, kChange, kDelete, kDeleteAll, kSendOldValue } type; |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 216 | std::string key; |
| 217 | std::string old_value; |
| 218 | std::string new_value; |
| 219 | std::string source; |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 220 | bool should_send_old_value; |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 221 | }; |
| 222 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 223 | LevelDBWrapperImplTest() : db_(&mock_data_), observer_binding_(this) { |
| 224 | auto request = mojo::MakeRequest(&level_db_database_ptr_); |
| 225 | db_.Bind(std::move(request)); |
| 226 | |
| 227 | LevelDBWrapperImpl::Options options = |
| 228 | GetDefaultTestingOptions(CacheMode::KEYS_ONLY_WHEN_POSSIBLE); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 229 | level_db_wrapper_ = std::make_unique<LevelDBWrapperImpl>( |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 230 | level_db_database_ptr_.get(), test_prefix_, &delegate_, options); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 231 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 232 | set_mock_data(test_prefix_ + test_key1_, test_value1_); |
| 233 | set_mock_data(test_prefix_ + test_key2_, test_value2_); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 234 | set_mock_data("123", "baddata"); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 235 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 236 | level_db_wrapper_->Bind(mojo::MakeRequest(&level_db_wrapper_ptr_)); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 237 | mojom::LevelDBObserverAssociatedPtrInfo ptr_info; |
Ken Rockot | 4247245 | 2017-05-12 05:37:03 | [diff] [blame] | 238 | observer_binding_.Bind(mojo::MakeRequest(&ptr_info)); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 239 | level_db_wrapper_ptr_->AddObserver(std::move(ptr_info)); |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 240 | } |
| 241 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 242 | ~LevelDBWrapperImplTest() override {} |
| 243 | |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 244 | void set_mock_data(const std::string& key, const std::string& value) { |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 245 | mock_data_[ToBytes(key)] = ToBytes(value); |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 246 | } |
| 247 | |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 248 | void set_mock_data(const std::vector<uint8_t>& key, |
| 249 | const std::vector<uint8_t>& value) { |
| 250 | mock_data_[key] = value; |
| 251 | } |
| 252 | |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 253 | bool has_mock_data(const std::string& key) { |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 254 | return mock_data_.find(ToBytes(key)) != mock_data_.end(); |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 255 | } |
| 256 | |
| 257 | std::string get_mock_data(const std::string& key) { |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 258 | return has_mock_data(key) ? ToString(mock_data_[ToBytes(key)]) : ""; |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 259 | } |
| 260 | |
mek | 30ff3ed | 2017-02-15 22:52:14 | [diff] [blame] | 261 | void clear_mock_data() { mock_data_.clear(); } |
| 262 | |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 263 | mojom::LevelDBWrapper* wrapper() { return level_db_wrapper_ptr_.get(); } |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 264 | LevelDBWrapperImpl* wrapper_impl() { return level_db_wrapper_.get(); } |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 265 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 266 | bool GetSync(mojom::LevelDBWrapper* wrapper, |
| 267 | const std::vector<uint8_t>& key, |
| 268 | std::vector<uint8_t>* result) { |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 269 | bool success = false; |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 270 | base::RunLoop loop; |
| 271 | wrapper->Get(key, MakeGetCallback(loop.QuitClosure(), &success, result)); |
| 272 | loop.Run(); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 273 | return success; |
| 274 | } |
| 275 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 276 | bool PutSync(mojom::LevelDBWrapper* wrapper, |
| 277 | const std::vector<uint8_t>& key, |
| 278 | const std::vector<uint8_t>& value, |
| 279 | const base::Optional<std::vector<uint8_t>>& client_old_value, |
| 280 | std::string source = kTestSource) { |
| 281 | bool success = false; |
| 282 | base::RunLoop loop; |
| 283 | wrapper->Put(key, value, client_old_value, source, |
| 284 | MakeSuccessCallback(loop.QuitClosure(), &success)); |
| 285 | loop.Run(); |
| 286 | return success; |
| 287 | } |
| 288 | |
| 289 | bool DeleteSync( |
| 290 | mojom::LevelDBWrapper* wrapper, |
| 291 | const std::vector<uint8_t>& key, |
| 292 | const base::Optional<std::vector<uint8_t>>& client_old_value) { |
| 293 | bool success = false; |
| 294 | base::RunLoop loop; |
| 295 | wrapper->Delete(key, client_old_value, test_source_, |
| 296 | MakeSuccessCallback(loop.QuitClosure(), &success)); |
| 297 | loop.Run(); |
| 298 | return success; |
| 299 | } |
| 300 | |
| 301 | bool DeleteAllSync(mojom::LevelDBWrapper* wrapper) { |
| 302 | bool success = false; |
| 303 | base::RunLoop loop; |
| 304 | wrapper->DeleteAll(test_source_, |
| 305 | MakeSuccessCallback(loop.QuitClosure(), &success)); |
| 306 | loop.Run(); |
| 307 | return success; |
| 308 | } |
| 309 | |
| 310 | bool GetSync(const std::vector<uint8_t>& key, std::vector<uint8_t>* result) { |
| 311 | return GetSync(wrapper(), key, result); |
| 312 | } |
| 313 | |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 314 | bool PutSync(const std::vector<uint8_t>& key, |
| 315 | const std::vector<uint8_t>& value, |
Siddhartha | c0600a2a | 2017-10-12 22:03:02 | [diff] [blame] | 316 | const base::Optional<std::vector<uint8_t>>& client_old_value, |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 317 | std::string source = kTestSource) { |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 318 | return PutSync(wrapper(), key, value, client_old_value, source); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 319 | } |
| 320 | |
Siddhartha | c0600a2a | 2017-10-12 22:03:02 | [diff] [blame] | 321 | bool DeleteSync( |
| 322 | const std::vector<uint8_t>& key, |
| 323 | const base::Optional<std::vector<uint8_t>>& client_old_value) { |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 324 | return DeleteSync(wrapper(), key, client_old_value); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 325 | } |
| 326 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 327 | bool DeleteAllSync() { return DeleteAllSync(wrapper()); } |
| 328 | |
| 329 | std::string GetSyncStrUsingGetAll(LevelDBWrapperImpl* wrapper_impl, |
| 330 | const std::string& key) { |
| 331 | leveldb::mojom::DatabaseError status; |
| 332 | std::vector<mojom::KeyValuePtr> data; |
| 333 | bool done = false; |
| 334 | |
| 335 | base::RunLoop loop; |
| 336 | // Testing the 'Sync' mojo version is a big headache involving 3 threads, so |
| 337 | // just test the async version. |
| 338 | wrapper_impl->GetAll( |
| 339 | GetAllCallback::CreateAndBind(&done, loop.QuitClosure()), |
| 340 | MakeGetAllCallback(&status, &data)); |
| 341 | loop.Run(); |
| 342 | |
| 343 | if (!done) |
| 344 | return ""; |
| 345 | |
| 346 | if (status != leveldb::mojom::DatabaseError::OK) |
| 347 | return ""; |
| 348 | |
| 349 | for (const auto& key_value : data) { |
| 350 | if (key_value->key == ToBytes(key)) { |
| 351 | return ToString(key_value->value); |
| 352 | } |
| 353 | } |
| 354 | return ""; |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 355 | } |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 356 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 357 | void BlockingCommit() { BlockingCommit(&delegate_, level_db_wrapper_.get()); } |
| 358 | |
| 359 | void BlockingCommit(MockDelegate* delegate, LevelDBWrapperImpl* wrapper) { |
| 360 | while (wrapper->has_pending_load_tasks() || |
| 361 | wrapper->has_changes_to_commit()) { |
| 362 | base::RunLoop loop; |
| 363 | delegate->SetDidCommitCallback(loop.QuitClosure()); |
| 364 | wrapper->ScheduleImmediateCommit(); |
| 365 | loop.Run(); |
| 366 | } |
| 367 | } |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 368 | |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 369 | const std::vector<Observation>& observations() { return observations_; } |
| 370 | |
mek | dea811df | 2017-03-01 17:57:57 | [diff] [blame] | 371 | MockDelegate* delegate() { return &delegate_; } |
| 372 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 373 | void should_record_send_old_value_observations(bool value) { |
| 374 | should_record_send_old_value_observations_ = value; |
| 375 | } |
| 376 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 377 | protected: |
| 378 | const std::string test_prefix_ = "abc"; |
| 379 | const std::string test_key1_ = "def"; |
| 380 | const std::string test_key2_ = "123"; |
| 381 | const std::string test_value1_ = "defdata"; |
| 382 | const std::string test_value2_ = "123data"; |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 383 | const std::string test_copy_prefix1_ = "www"; |
| 384 | const std::string test_copy_prefix2_ = "xxx"; |
| 385 | const std::string test_copy_prefix3_ = "yyy"; |
| 386 | const std::string test_source_ = kTestSource; |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 387 | |
| 388 | const std::vector<uint8_t> test_prefix_bytes_ = ToBytes(test_prefix_); |
| 389 | const std::vector<uint8_t> test_key1_bytes_ = ToBytes(test_key1_); |
| 390 | const std::vector<uint8_t> test_key2_bytes_ = ToBytes(test_key2_); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 391 | const std::vector<uint8_t> test_value1_bytes_ = ToBytes(test_value1_); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 392 | const std::vector<uint8_t> test_value2_bytes_ = ToBytes(test_value2_); |
| 393 | |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 394 | private: |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 395 | // LevelDBObserver: |
| 396 | void KeyAdded(const std::vector<uint8_t>& key, |
| 397 | const std::vector<uint8_t>& value, |
| 398 | const std::string& source) override { |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 399 | observations_.push_back( |
| 400 | {Observation::kAdd, ToString(key), "", ToString(value), source, false}); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 401 | } |
| 402 | void KeyChanged(const std::vector<uint8_t>& key, |
| 403 | const std::vector<uint8_t>& new_value, |
| 404 | const std::vector<uint8_t>& old_value, |
| 405 | const std::string& source) override { |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 406 | observations_.push_back({Observation::kChange, ToString(key), |
| 407 | ToString(old_value), ToString(new_value), source, |
| 408 | false}); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 409 | } |
| 410 | void KeyDeleted(const std::vector<uint8_t>& key, |
| 411 | const std::vector<uint8_t>& old_value, |
| 412 | const std::string& source) override { |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 413 | observations_.push_back({Observation::kDelete, ToString(key), |
| 414 | ToString(old_value), "", source, false}); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 415 | } |
| 416 | void AllDeleted(const std::string& source) override { |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 417 | observations_.push_back( |
| 418 | {Observation::kDeleteAll, "", "", "", source, false}); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 419 | } |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 420 | void ShouldSendOldValueOnMutations(bool value) override { |
| 421 | if (should_record_send_old_value_observations_) |
| 422 | observations_.push_back( |
| 423 | {Observation::kSendOldValue, "", "", "", "", value}); |
| 424 | } |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 425 | |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 426 | TestBrowserThreadBundle thread_bundle_; |
| 427 | std::map<std::vector<uint8_t>, std::vector<uint8_t>> mock_data_; |
Daniel Murphy | 47b1223 | 2017-11-07 21:04:26 | [diff] [blame] | 428 | FakeLevelDBDatabase db_; |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 429 | leveldb::mojom::LevelDBDatabasePtr level_db_database_ptr_; |
mek | 222214f | 2017-01-17 21:30:51 | [diff] [blame] | 430 | MockDelegate delegate_; |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 431 | std::unique_ptr<LevelDBWrapperImpl> level_db_wrapper_; |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 432 | mojom::LevelDBWrapperPtr level_db_wrapper_ptr_; |
| 433 | mojo::AssociatedBinding<mojom::LevelDBObserver> observer_binding_; |
| 434 | std::vector<Observation> observations_; |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 435 | bool should_record_send_old_value_observations_ = false; |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 436 | }; |
| 437 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 438 | class LevelDBWrapperImplParamTest |
| 439 | : public LevelDBWrapperImplTest, |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 440 | public testing::WithParamInterface<CacheMode> { |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 441 | public: |
| 442 | LevelDBWrapperImplParamTest() {} |
| 443 | ~LevelDBWrapperImplParamTest() override {} |
| 444 | }; |
| 445 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 446 | INSTANTIATE_TEST_CASE_P(LevelDBWrapperImplTest, |
| 447 | LevelDBWrapperImplParamTest, |
| 448 | testing::Values(CacheMode::KEYS_ONLY_WHEN_POSSIBLE, |
| 449 | CacheMode::KEYS_AND_VALUES)); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 450 | |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 451 | TEST_F(LevelDBWrapperImplTest, GetLoadedFromMap) { |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 452 | wrapper_impl()->SetCacheModeForTesting(CacheMode::KEYS_AND_VALUES); |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 453 | std::vector<uint8_t> result; |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 454 | EXPECT_TRUE(GetSync(test_key2_bytes_, &result)); |
| 455 | EXPECT_EQ(test_value2_bytes_, result); |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 456 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 457 | EXPECT_FALSE(GetSync(ToBytes("x"), &result)); |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 458 | } |
| 459 | |
| 460 | TEST_F(LevelDBWrapperImplTest, GetFromPutOverwrite) { |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 461 | wrapper_impl()->SetCacheModeForTesting(CacheMode::KEYS_AND_VALUES); |
| 462 | std::vector<uint8_t> key = test_key2_bytes_; |
| 463 | std::vector<uint8_t> value = ToBytes("foo"); |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 464 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 465 | base::RunLoop loop; |
| 466 | bool put_success = false; |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 467 | std::vector<uint8_t> result; |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 468 | bool get_success = false; |
| 469 | { |
| 470 | IncrementalBarrier barrier(loop.QuitClosure()); |
| 471 | wrapper()->Put(key, value, test_value2_bytes_, test_source_, |
| 472 | MakeSuccessCallback(barrier.Get(), &put_success)); |
| 473 | wrapper()->Get(key, MakeGetCallback(barrier.Get(), &get_success, &result)); |
| 474 | } |
| 475 | |
| 476 | loop.Run(); |
| 477 | EXPECT_TRUE(put_success); |
| 478 | EXPECT_TRUE(get_success); |
| 479 | |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 480 | EXPECT_EQ(value, result); |
| 481 | } |
| 482 | |
| 483 | TEST_F(LevelDBWrapperImplTest, GetFromPutNewKey) { |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 484 | wrapper_impl()->SetCacheModeForTesting(CacheMode::KEYS_AND_VALUES); |
| 485 | std::vector<uint8_t> key = ToBytes("newkey"); |
| 486 | std::vector<uint8_t> value = ToBytes("foo"); |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 487 | |
Siddhartha | c0600a2a | 2017-10-12 22:03:02 | [diff] [blame] | 488 | EXPECT_TRUE(PutSync(key, value, base::nullopt)); |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 489 | |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 490 | std::vector<uint8_t> result; |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 491 | EXPECT_TRUE(GetSync(key, &result)); |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 492 | EXPECT_EQ(value, result); |
| 493 | } |
| 494 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 495 | TEST_F(LevelDBWrapperImplTest, PutLoadsValuesAfterCacheModeUpgrade) { |
| 496 | std::vector<uint8_t> key = ToBytes("newkey"); |
| 497 | std::vector<uint8_t> value1 = ToBytes("foo"); |
| 498 | std::vector<uint8_t> value2 = ToBytes("bar"); |
| 499 | |
| 500 | ASSERT_EQ(CacheMode::KEYS_ONLY_WHEN_POSSIBLE, wrapper_impl()->cache_mode()); |
| 501 | |
| 502 | // Do a put to load the key-only cache. |
| 503 | EXPECT_TRUE(PutSync(key, value1, base::nullopt)); |
| 504 | EXPECT_EQ(LevelDBWrapperImpl::MapState::LOADED_KEYS_ONLY, |
| 505 | wrapper_impl()->map_state_); |
| 506 | |
| 507 | // Change cache mode. |
| 508 | wrapper_impl()->SetCacheModeForTesting(CacheMode::KEYS_AND_VALUES); |
| 509 | // Loading new map isn't necessary yet. |
| 510 | EXPECT_EQ(LevelDBWrapperImpl::MapState::LOADED_KEYS_ONLY, |
| 511 | wrapper_impl()->map_state_); |
| 512 | |
| 513 | // Do another put and check that the map has been upgraded |
| 514 | EXPECT_TRUE(PutSync(key, value2, value1)); |
| 515 | EXPECT_EQ(LevelDBWrapperImpl::MapState::LOADED_KEYS_AND_VALUES, |
| 516 | wrapper_impl()->map_state_); |
| 517 | } |
| 518 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 519 | TEST_P(LevelDBWrapperImplParamTest, GetAll) { |
| 520 | wrapper_impl()->SetCacheModeForTesting(GetParam()); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 521 | DatabaseError status; |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 522 | std::vector<mojom::KeyValuePtr> data; |
mek | a3b1e3d | 2016-12-22 17:18:08 | [diff] [blame] | 523 | bool result = false; |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 524 | |
| 525 | base::RunLoop loop; |
| 526 | // Testing the 'Sync' mojo version is a big headache involving 3 threads, so |
| 527 | // just test the async version. |
| 528 | wrapper_impl()->GetAll( |
| 529 | GetAllCallback::CreateAndBind(&result, loop.QuitClosure()), |
| 530 | MakeGetAllCallback(&status, &data)); |
| 531 | loop.Run(); |
| 532 | EXPECT_EQ(leveldb::mojom::DatabaseError::OK, status); |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 533 | EXPECT_EQ(2u, data.size()); |
mek | a3b1e3d | 2016-12-22 17:18:08 | [diff] [blame] | 534 | EXPECT_TRUE(result); |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 535 | } |
| 536 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 537 | TEST_P(LevelDBWrapperImplParamTest, CommitPutToDB) { |
| 538 | wrapper_impl()->SetCacheModeForTesting(GetParam()); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 539 | std::string key1 = test_key2_; |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 540 | std::string value1 = "foo"; |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 541 | std::string key2 = test_prefix_; |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 542 | std::string value2 = "data abc"; |
| 543 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 544 | base::RunLoop loop; |
| 545 | bool put_success1 = false; |
| 546 | bool put_success2 = false; |
| 547 | bool put_success3 = false; |
| 548 | { |
| 549 | IncrementalBarrier barrier(loop.QuitClosure()); |
| 550 | |
| 551 | wrapper()->Put(ToBytes(key1), ToBytes(value1), test_value2_bytes_, |
| 552 | test_source_, |
| 553 | MakeSuccessCallback(barrier.Get(), &put_success1)); |
| 554 | wrapper()->Put(ToBytes(key2), ToBytes("old value"), base::nullopt, |
| 555 | test_source_, |
| 556 | MakeSuccessCallback(barrier.Get(), &put_success2)); |
| 557 | wrapper()->Put(ToBytes(key2), ToBytes(value2), ToBytes("old value"), |
| 558 | test_source_, |
| 559 | MakeSuccessCallback(barrier.Get(), &put_success3)); |
| 560 | } |
| 561 | |
| 562 | loop.Run(); |
| 563 | EXPECT_TRUE(put_success1); |
| 564 | EXPECT_TRUE(put_success2); |
| 565 | EXPECT_TRUE(put_success3); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 566 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 567 | EXPECT_FALSE(has_mock_data(test_prefix_ + key2)); |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 568 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 569 | BlockingCommit(); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 570 | EXPECT_TRUE(has_mock_data(test_prefix_ + key1)); |
| 571 | EXPECT_EQ(value1, get_mock_data(test_prefix_ + key1)); |
| 572 | EXPECT_TRUE(has_mock_data(test_prefix_ + key2)); |
| 573 | EXPECT_EQ(value2, get_mock_data(test_prefix_ + key2)); |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 574 | } |
| 575 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 576 | TEST_P(LevelDBWrapperImplParamTest, PutObservations) { |
| 577 | wrapper_impl()->SetCacheModeForTesting(GetParam()); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 578 | std::string key = "new_key"; |
| 579 | std::string value1 = "foo"; |
| 580 | std::string value2 = "data abc"; |
| 581 | std::string source1 = "source1"; |
| 582 | std::string source2 = "source2"; |
| 583 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 584 | EXPECT_TRUE(PutSync(ToBytes(key), ToBytes(value1), base::nullopt, source1)); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 585 | ASSERT_EQ(1u, observations().size()); |
| 586 | EXPECT_EQ(Observation::kAdd, observations()[0].type); |
| 587 | EXPECT_EQ(key, observations()[0].key); |
| 588 | EXPECT_EQ(value1, observations()[0].new_value); |
| 589 | EXPECT_EQ(source1, observations()[0].source); |
| 590 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 591 | EXPECT_TRUE(PutSync(ToBytes(key), ToBytes(value2), ToBytes(value1), source2)); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 592 | ASSERT_EQ(2u, observations().size()); |
| 593 | EXPECT_EQ(Observation::kChange, observations()[1].type); |
| 594 | EXPECT_EQ(key, observations()[1].key); |
| 595 | EXPECT_EQ(value1, observations()[1].old_value); |
| 596 | EXPECT_EQ(value2, observations()[1].new_value); |
| 597 | EXPECT_EQ(source2, observations()[1].source); |
mek | 30ff3ed | 2017-02-15 22:52:14 | [diff] [blame] | 598 | |
| 599 | // Same put should not cause another observation. |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 600 | EXPECT_TRUE(PutSync(ToBytes(key), ToBytes(value2), ToBytes(value2), source2)); |
mek | 30ff3ed | 2017-02-15 22:52:14 | [diff] [blame] | 601 | ASSERT_EQ(2u, observations().size()); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 602 | } |
| 603 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 604 | TEST_P(LevelDBWrapperImplParamTest, DeleteNonExistingKey) { |
| 605 | wrapper_impl()->SetCacheModeForTesting(GetParam()); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 606 | EXPECT_TRUE(DeleteSync(ToBytes("doesn't exist"), std::vector<uint8_t>())); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 607 | EXPECT_EQ(0u, observations().size()); |
| 608 | } |
| 609 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 610 | TEST_P(LevelDBWrapperImplParamTest, DeleteExistingKey) { |
| 611 | wrapper_impl()->SetCacheModeForTesting(GetParam()); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 612 | std::string key = "newkey"; |
| 613 | std::string value = "foo"; |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 614 | set_mock_data(test_prefix_ + key, value); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 615 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 616 | EXPECT_TRUE(DeleteSync(ToBytes(key), ToBytes(value))); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 617 | ASSERT_EQ(1u, observations().size()); |
| 618 | EXPECT_EQ(Observation::kDelete, observations()[0].type); |
| 619 | EXPECT_EQ(key, observations()[0].key); |
| 620 | EXPECT_EQ(value, observations()[0].old_value); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 621 | EXPECT_EQ(test_source_, observations()[0].source); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 622 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 623 | EXPECT_TRUE(has_mock_data(test_prefix_ + key)); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 624 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 625 | BlockingCommit(); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 626 | EXPECT_FALSE(has_mock_data(test_prefix_ + key)); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 627 | } |
| 628 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 629 | TEST_P(LevelDBWrapperImplParamTest, DeleteAllWithoutLoadedMap) { |
| 630 | wrapper_impl()->SetCacheModeForTesting(GetParam()); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 631 | std::string key = "newkey"; |
| 632 | std::string value = "foo"; |
| 633 | std::string dummy_key = "foobar"; |
| 634 | set_mock_data(dummy_key, value); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 635 | set_mock_data(test_prefix_ + key, value); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 636 | |
| 637 | EXPECT_TRUE(DeleteAllSync()); |
| 638 | ASSERT_EQ(1u, observations().size()); |
| 639 | EXPECT_EQ(Observation::kDeleteAll, observations()[0].type); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 640 | EXPECT_EQ(test_source_, observations()[0].source); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 641 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 642 | EXPECT_TRUE(has_mock_data(test_prefix_ + key)); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 643 | EXPECT_TRUE(has_mock_data(dummy_key)); |
| 644 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 645 | BlockingCommit(); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 646 | EXPECT_FALSE(has_mock_data(test_prefix_ + key)); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 647 | EXPECT_TRUE(has_mock_data(dummy_key)); |
| 648 | |
mek | 30ff3ed | 2017-02-15 22:52:14 | [diff] [blame] | 649 | // Deleting all again should still work, but not cause an observation. |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 650 | EXPECT_TRUE(DeleteAllSync()); |
mek | 30ff3ed | 2017-02-15 22:52:14 | [diff] [blame] | 651 | ASSERT_EQ(1u, observations().size()); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 652 | |
| 653 | // And now we've deleted all, writing something the quota size should work. |
| 654 | EXPECT_TRUE(PutSync(std::vector<uint8_t>(kTestSizeLimit, 'b'), |
Siddhartha | c0600a2a | 2017-10-12 22:03:02 | [diff] [blame] | 655 | std::vector<uint8_t>(), base::nullopt)); |
mek | eea75a43 | 2016-12-21 21:31:27 | [diff] [blame] | 656 | } |
| 657 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 658 | TEST_P(LevelDBWrapperImplParamTest, DeleteAllWithLoadedMap) { |
| 659 | wrapper_impl()->SetCacheModeForTesting(GetParam()); |
mek | a9c2a3c1 | 2016-12-29 20:50:18 | [diff] [blame] | 660 | std::string key = "newkey"; |
| 661 | std::string value = "foo"; |
| 662 | std::string dummy_key = "foobar"; |
| 663 | set_mock_data(dummy_key, value); |
| 664 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 665 | EXPECT_TRUE(PutSync(ToBytes(key), ToBytes(value), base::nullopt)); |
mek | a9c2a3c1 | 2016-12-29 20:50:18 | [diff] [blame] | 666 | |
| 667 | EXPECT_TRUE(DeleteAllSync()); |
| 668 | ASSERT_EQ(2u, observations().size()); |
| 669 | EXPECT_EQ(Observation::kDeleteAll, observations()[1].type); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 670 | EXPECT_EQ(test_source_, observations()[1].source); |
mek | a9c2a3c1 | 2016-12-29 20:50:18 | [diff] [blame] | 671 | |
| 672 | EXPECT_TRUE(has_mock_data(dummy_key)); |
| 673 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 674 | BlockingCommit(); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 675 | EXPECT_FALSE(has_mock_data(test_prefix_ + key)); |
mek | a9c2a3c1 | 2016-12-29 20:50:18 | [diff] [blame] | 676 | EXPECT_TRUE(has_mock_data(dummy_key)); |
| 677 | } |
| 678 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 679 | TEST_P(LevelDBWrapperImplParamTest, DeleteAllWithPendingMapLoad) { |
| 680 | wrapper_impl()->SetCacheModeForTesting(GetParam()); |
mek | a9c2a3c1 | 2016-12-29 20:50:18 | [diff] [blame] | 681 | std::string key = "newkey"; |
| 682 | std::string value = "foo"; |
| 683 | std::string dummy_key = "foobar"; |
| 684 | set_mock_data(dummy_key, value); |
| 685 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 686 | wrapper()->Put(ToBytes(key), ToBytes(value), base::nullopt, kTestSource, |
Siddhartha | c0600a2a | 2017-10-12 22:03:02 | [diff] [blame] | 687 | base::BindOnce(&NoOpSuccessCallback)); |
mek | a9c2a3c1 | 2016-12-29 20:50:18 | [diff] [blame] | 688 | |
| 689 | EXPECT_TRUE(DeleteAllSync()); |
| 690 | ASSERT_EQ(2u, observations().size()); |
| 691 | EXPECT_EQ(Observation::kDeleteAll, observations()[1].type); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 692 | EXPECT_EQ(test_source_, observations()[1].source); |
mek | a9c2a3c1 | 2016-12-29 20:50:18 | [diff] [blame] | 693 | |
| 694 | EXPECT_TRUE(has_mock_data(dummy_key)); |
| 695 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 696 | BlockingCommit(); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 697 | EXPECT_FALSE(has_mock_data(test_prefix_ + key)); |
mek | a9c2a3c1 | 2016-12-29 20:50:18 | [diff] [blame] | 698 | EXPECT_TRUE(has_mock_data(dummy_key)); |
| 699 | } |
| 700 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 701 | TEST_P(LevelDBWrapperImplParamTest, DeleteAllWithoutLoadedEmptyMap) { |
| 702 | wrapper_impl()->SetCacheModeForTesting(GetParam()); |
mek | 30ff3ed | 2017-02-15 22:52:14 | [diff] [blame] | 703 | clear_mock_data(); |
| 704 | |
| 705 | EXPECT_TRUE(DeleteAllSync()); |
| 706 | ASSERT_EQ(0u, observations().size()); |
| 707 | } |
| 708 | |
Daniel Murphy | 674c3bd | 2017-11-17 04:21:56 | [diff] [blame] | 709 | TEST_F(LevelDBWrapperImplParamTest, PutOverQuotaLargeValue) { |
| 710 | wrapper_impl()->SetCacheModeForTesting( |
| 711 | LevelDBWrapperImpl::CacheMode::KEYS_AND_VALUES); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 712 | std::vector<uint8_t> key = ToBytes("newkey"); |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 713 | std::vector<uint8_t> value(kTestSizeLimit, 4); |
| 714 | |
Siddhartha | c0600a2a | 2017-10-12 22:03:02 | [diff] [blame] | 715 | EXPECT_FALSE(PutSync(key, value, base::nullopt)); |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 716 | |
| 717 | value.resize(kTestSizeLimit / 2); |
Siddhartha | c0600a2a | 2017-10-12 22:03:02 | [diff] [blame] | 718 | EXPECT_TRUE(PutSync(key, value, base::nullopt)); |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 719 | } |
| 720 | |
Daniel Murphy | 674c3bd | 2017-11-17 04:21:56 | [diff] [blame] | 721 | TEST_F(LevelDBWrapperImplParamTest, PutOverQuotaLargeKey) { |
| 722 | wrapper_impl()->SetCacheModeForTesting( |
| 723 | LevelDBWrapperImpl::CacheMode::KEYS_AND_VALUES); |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 724 | std::vector<uint8_t> key(kTestSizeLimit, 'a'); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 725 | std::vector<uint8_t> value = ToBytes("newvalue"); |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 726 | |
Siddhartha | c0600a2a | 2017-10-12 22:03:02 | [diff] [blame] | 727 | EXPECT_FALSE(PutSync(key, value, base::nullopt)); |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 728 | |
| 729 | key.resize(kTestSizeLimit / 2); |
Siddhartha | c0600a2a | 2017-10-12 22:03:02 | [diff] [blame] | 730 | EXPECT_TRUE(PutSync(key, value, base::nullopt)); |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 731 | } |
| 732 | |
Daniel Murphy | 674c3bd | 2017-11-17 04:21:56 | [diff] [blame] | 733 | TEST_F(LevelDBWrapperImplParamTest, PutWhenAlreadyOverQuota) { |
| 734 | wrapper_impl()->SetCacheModeForTesting( |
| 735 | LevelDBWrapperImpl::CacheMode::KEYS_AND_VALUES); |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 736 | std::string key = "largedata"; |
| 737 | std::vector<uint8_t> value(kTestSizeLimit, 4); |
Siddhartha | c0600a2a | 2017-10-12 22:03:02 | [diff] [blame] | 738 | std::vector<uint8_t> old_value = value; |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 739 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 740 | set_mock_data(test_prefix_ + key, ToString(value)); |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 741 | |
| 742 | // Put with same data should succeed. |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 743 | EXPECT_TRUE(PutSync(ToBytes(key), value, base::nullopt)); |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 744 | |
| 745 | // Put with same data size should succeed. |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 746 | value[1] = 13; |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 747 | EXPECT_TRUE(PutSync(ToBytes(key), value, old_value)); |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 748 | |
| 749 | // Adding a new key when already over quota should not succeed. |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 750 | EXPECT_FALSE(PutSync(ToBytes("newkey"), {1, 2, 3}, base::nullopt)); |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 751 | |
| 752 | // Reducing size should also succeed. |
Siddhartha | c0600a2a | 2017-10-12 22:03:02 | [diff] [blame] | 753 | old_value = value; |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 754 | value.resize(kTestSizeLimit / 2); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 755 | EXPECT_TRUE(PutSync(ToBytes(key), value, old_value)); |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 756 | |
| 757 | // Increasing size again should succeed, as still under the limit. |
Siddhartha | c0600a2a | 2017-10-12 22:03:02 | [diff] [blame] | 758 | old_value = value; |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 759 | value.resize(value.size() + 1); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 760 | EXPECT_TRUE(PutSync(ToBytes(key), value, old_value)); |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 761 | |
| 762 | // But increasing back to original size should fail. |
Siddhartha | c0600a2a | 2017-10-12 22:03:02 | [diff] [blame] | 763 | old_value = value; |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 764 | value.resize(kTestSizeLimit); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 765 | EXPECT_FALSE(PutSync(ToBytes(key), value, old_value)); |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 766 | } |
| 767 | |
Daniel Murphy | 674c3bd | 2017-11-17 04:21:56 | [diff] [blame] | 768 | TEST_F(LevelDBWrapperImplParamTest, PutWhenAlreadyOverQuotaBecauseOfLargeKey) { |
| 769 | wrapper_impl()->SetCacheModeForTesting( |
| 770 | LevelDBWrapperImpl::CacheMode::KEYS_AND_VALUES); |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 771 | std::vector<uint8_t> key(kTestSizeLimit, 'x'); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 772 | std::vector<uint8_t> value = ToBytes("value"); |
Siddhartha | c0600a2a | 2017-10-12 22:03:02 | [diff] [blame] | 773 | std::vector<uint8_t> old_value = value; |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 774 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 775 | set_mock_data(test_prefix_ + ToString(key), ToString(value)); |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 776 | |
| 777 | // Put with same data size should succeed. |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 778 | value[0] = 'X'; |
Siddhartha | c0600a2a | 2017-10-12 22:03:02 | [diff] [blame] | 779 | EXPECT_TRUE(PutSync(key, value, old_value)); |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 780 | |
| 781 | // Reducing size should also succeed. |
Siddhartha | c0600a2a | 2017-10-12 22:03:02 | [diff] [blame] | 782 | old_value = value; |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 783 | value.clear(); |
Siddhartha | c0600a2a | 2017-10-12 22:03:02 | [diff] [blame] | 784 | EXPECT_TRUE(PutSync(key, value, old_value)); |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 785 | |
| 786 | // Increasing size should fail. |
Siddhartha | c0600a2a | 2017-10-12 22:03:02 | [diff] [blame] | 787 | old_value = value; |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 788 | value.resize(1, 'a'); |
Siddhartha | c0600a2a | 2017-10-12 22:03:02 | [diff] [blame] | 789 | EXPECT_FALSE(PutSync(key, value, old_value)); |
mek | a95ed90 | 2016-12-21 02:46:35 | [diff] [blame] | 790 | } |
| 791 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 792 | TEST_P(LevelDBWrapperImplParamTest, PutAfterPurgeMemory) { |
| 793 | wrapper_impl()->SetCacheModeForTesting(GetParam()); |
mek | dea811df | 2017-03-01 17:57:57 | [diff] [blame] | 794 | std::vector<uint8_t> result; |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 795 | const auto key = test_key2_bytes_; |
| 796 | const auto value = test_value2_bytes_; |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 797 | EXPECT_TRUE(PutSync(key, value, value)); |
mek | dea811df | 2017-03-01 17:57:57 | [diff] [blame] | 798 | EXPECT_EQ(delegate()->map_load_count(), 1); |
| 799 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 800 | // Adding again doesn't load map again. |
| 801 | EXPECT_TRUE(PutSync(key, value, value)); |
mek | dea811df | 2017-03-01 17:57:57 | [diff] [blame] | 802 | EXPECT_EQ(delegate()->map_load_count(), 1); |
| 803 | |
| 804 | wrapper_impl()->PurgeMemory(); |
| 805 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 806 | // Now adding should still work, and load map again. |
| 807 | EXPECT_TRUE(PutSync(key, value, value)); |
mek | dea811df | 2017-03-01 17:57:57 | [diff] [blame] | 808 | EXPECT_EQ(delegate()->map_load_count(), 2); |
| 809 | } |
| 810 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 811 | TEST_P(LevelDBWrapperImplParamTest, PurgeMemoryWithPendingChanges) { |
| 812 | wrapper_impl()->SetCacheModeForTesting(GetParam()); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 813 | std::vector<uint8_t> key = test_key2_bytes_; |
| 814 | std::vector<uint8_t> value = ToBytes("foo"); |
| 815 | EXPECT_TRUE(PutSync(key, value, test_value2_bytes_)); |
mek | dea811df | 2017-03-01 17:57:57 | [diff] [blame] | 816 | EXPECT_EQ(delegate()->map_load_count(), 1); |
| 817 | |
| 818 | // Purge memory, and read. Should not actually have purged, so should not have |
| 819 | // triggered a load. |
| 820 | wrapper_impl()->PurgeMemory(); |
| 821 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 822 | EXPECT_TRUE(PutSync(key, value, value)); |
mek | dea811df | 2017-03-01 17:57:57 | [diff] [blame] | 823 | EXPECT_EQ(delegate()->map_load_count(), 1); |
| 824 | } |
| 825 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 826 | TEST_P(LevelDBWrapperImplParamTest, FixUpData) { |
| 827 | wrapper_impl()->SetCacheModeForTesting(GetParam()); |
Marijn Kruisselbrink | e8fdb3d | 2017-09-26 01:33:07 | [diff] [blame] | 828 | std::vector<LevelDBWrapperImpl::Change> changes; |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 829 | changes.push_back(std::make_pair(test_key1_bytes_, ToBytes("foo"))); |
| 830 | changes.push_back(std::make_pair(test_key2_bytes_, base::nullopt)); |
| 831 | changes.push_back(std::make_pair(test_prefix_bytes_, ToBytes("bla"))); |
Marijn Kruisselbrink | e8fdb3d | 2017-09-26 01:33:07 | [diff] [blame] | 832 | delegate()->set_mock_changes(std::move(changes)); |
| 833 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 834 | leveldb::mojom::DatabaseError status; |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 835 | std::vector<mojom::KeyValuePtr> data; |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 836 | bool result = false; |
| 837 | |
| 838 | base::RunLoop loop; |
| 839 | // Testing the 'Sync' mojo version is a big headache involving 3 threads, so |
| 840 | // just test the async version. |
| 841 | wrapper_impl()->GetAll( |
| 842 | GetAllCallback::CreateAndBind(&result, loop.QuitClosure()), |
| 843 | MakeGetAllCallback(&status, &data)); |
| 844 | loop.Run(); |
| 845 | |
| 846 | EXPECT_EQ(leveldb::mojom::DatabaseError::OK, status); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 847 | ASSERT_EQ(2u, data.size()); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 848 | EXPECT_EQ(test_prefix_, ToString(data[0]->key)); |
| 849 | EXPECT_EQ("bla", ToString(data[0]->value)); |
| 850 | EXPECT_EQ(test_key1_, ToString(data[1]->key)); |
| 851 | EXPECT_EQ("foo", ToString(data[1]->value)); |
Marijn Kruisselbrink | e8fdb3d | 2017-09-26 01:33:07 | [diff] [blame] | 852 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 853 | EXPECT_FALSE(has_mock_data(test_prefix_ + test_key2_)); |
| 854 | EXPECT_EQ("foo", get_mock_data(test_prefix_ + test_key1_)); |
| 855 | EXPECT_EQ("bla", get_mock_data(test_prefix_ + test_prefix_)); |
Marijn Kruisselbrink | e8fdb3d | 2017-09-26 01:33:07 | [diff] [blame] | 856 | } |
| 857 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 858 | TEST_F(LevelDBWrapperImplTest, SetOnlyKeysWithoutDatabase) { |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 859 | std::vector<uint8_t> key = test_key2_bytes_; |
| 860 | std::vector<uint8_t> value = ToBytes("foo"); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 861 | MockDelegate delegate; |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 862 | LevelDBWrapperImpl level_db_wrapper( |
| 863 | nullptr, test_prefix_, &delegate, |
| 864 | GetDefaultTestingOptions(CacheMode::KEYS_ONLY_WHEN_POSSIBLE)); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 865 | mojom::LevelDBWrapperPtr level_db_wrapper_ptr; |
| 866 | level_db_wrapper.Bind(mojo::MakeRequest(&level_db_wrapper_ptr)); |
| 867 | // Setting only keys mode is noop. |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 868 | level_db_wrapper.SetCacheModeForTesting(CacheMode::KEYS_ONLY_WHEN_POSSIBLE); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 869 | |
| 870 | EXPECT_FALSE(level_db_wrapper.initialized()); |
| 871 | EXPECT_EQ(CacheMode::KEYS_AND_VALUES, level_db_wrapper.cache_mode()); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 872 | |
| 873 | // Put and Get can work synchronously without reload. |
| 874 | bool put_callback_called = false; |
| 875 | level_db_wrapper.Put(key, value, base::nullopt, "source", |
| 876 | base::BindOnce( |
| 877 | [](bool* put_callback_called, bool success) { |
| 878 | EXPECT_TRUE(success); |
| 879 | *put_callback_called = true; |
| 880 | }, |
| 881 | &put_callback_called)); |
| 882 | EXPECT_TRUE(put_callback_called); |
| 883 | |
| 884 | std::vector<uint8_t> expected_value; |
| 885 | level_db_wrapper.Get( |
| 886 | key, base::BindOnce( |
| 887 | [](std::vector<uint8_t>* expected_value, bool success, |
| 888 | const std::vector<uint8_t>& value) { |
| 889 | EXPECT_TRUE(success); |
| 890 | *expected_value = value; |
| 891 | }, |
| 892 | &expected_value)); |
| 893 | EXPECT_EQ(expected_value, value); |
| 894 | } |
| 895 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 896 | TEST_P(LevelDBWrapperImplParamTest, CommitOnDifferentCacheModes) { |
| 897 | wrapper_impl()->SetCacheModeForTesting(GetParam()); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 898 | std::vector<uint8_t> key = test_key2_bytes_; |
| 899 | std::vector<uint8_t> value = ToBytes("foo"); |
| 900 | std::vector<uint8_t> value2 = ToBytes("foobar"); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 901 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 902 | // The initial map always has values, so a nullopt is fine for the old value. |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 903 | ASSERT_TRUE(PutSync(key, value, base::nullopt)); |
| 904 | ASSERT_TRUE(wrapper_impl()->commit_batch_); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 905 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 906 | if (GetParam() == CacheMode::KEYS_AND_VALUES) { |
| 907 | EXPECT_TRUE(wrapper_impl()->commit_batch_->changed_values.empty()); |
| 908 | auto* changes = &wrapper_impl()->commit_batch_->changed_keys; |
| 909 | ASSERT_EQ(1u, changes->size()); |
| 910 | EXPECT_EQ(key, *changes->begin()); |
| 911 | } else { |
| 912 | EXPECT_TRUE(wrapper_impl()->commit_batch_->changed_keys.empty()); |
| 913 | auto* changes = &wrapper_impl()->commit_batch_->changed_values; |
| 914 | ASSERT_EQ(1u, changes->size()); |
| 915 | auto it = changes->begin(); |
| 916 | EXPECT_EQ(key, it->first); |
| 917 | EXPECT_EQ(value, it->second); |
| 918 | } |
| 919 | |
| 920 | BlockingCommit(); |
| 921 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 922 | EXPECT_EQ("foo", get_mock_data(test_prefix_ + test_key2_)); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 923 | if (GetParam() == CacheMode::KEYS_AND_VALUES) |
| 924 | EXPECT_EQ(2u, wrapper_impl()->keys_values_map_.size()); |
| 925 | else |
| 926 | EXPECT_EQ(2u, wrapper_impl()->keys_only_map_.size()); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 927 | ASSERT_TRUE(PutSync(key, value, value)); |
| 928 | EXPECT_FALSE(wrapper_impl()->commit_batch_); |
| 929 | ASSERT_TRUE(PutSync(key, value2, value)); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 930 | ASSERT_TRUE(wrapper_impl()->commit_batch_); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 931 | |
| 932 | if (GetParam() == CacheMode::KEYS_AND_VALUES) { |
| 933 | auto* changes = &wrapper_impl()->commit_batch_->changed_keys; |
| 934 | EXPECT_EQ(1u, changes->size()); |
| 935 | auto it = changes->find(key); |
| 936 | ASSERT_NE(it, changes->end()); |
| 937 | } else { |
| 938 | auto* changes = &wrapper_impl()->commit_batch_->changed_values; |
| 939 | EXPECT_EQ(1u, changes->size()); |
| 940 | auto it = changes->find(key); |
| 941 | ASSERT_NE(it, changes->end()); |
| 942 | EXPECT_EQ(value2, it->second); |
| 943 | } |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 944 | |
| 945 | clear_mock_data(); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 946 | EXPECT_TRUE(wrapper_impl()->has_changes_to_commit()); |
| 947 | BlockingCommit(); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 948 | EXPECT_EQ("foobar", get_mock_data(test_prefix_ + test_key2_)); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 949 | EXPECT_FALSE(wrapper_impl()->has_changes_to_commit()); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 950 | } |
| 951 | |
| 952 | TEST_F(LevelDBWrapperImplTest, GetAllWhenCacheOnlyKeys) { |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 953 | std::vector<uint8_t> key = test_key2_bytes_; |
| 954 | std::vector<uint8_t> value = ToBytes("foo"); |
| 955 | std::vector<uint8_t> value2 = ToBytes("foobar"); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 956 | |
| 957 | // Go to load state only keys. |
| 958 | ASSERT_TRUE(PutSync(key, value, base::nullopt)); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 959 | BlockingCommit(); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 960 | ASSERT_TRUE(PutSync(key, value2, value)); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 961 | EXPECT_TRUE(wrapper_impl()->has_changes_to_commit()); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 962 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 963 | leveldb::mojom::DatabaseError status; |
| 964 | std::vector<mojom::KeyValuePtr> data; |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 965 | bool result = false; |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 966 | |
| 967 | base::RunLoop loop; |
| 968 | |
| 969 | bool put_result1 = false; |
| 970 | bool put_result2 = false; |
| 971 | { |
| 972 | IncrementalBarrier barrier(loop.QuitClosure()); |
| 973 | |
| 974 | wrapper_impl()->Put(key, value, value2, test_source_, |
| 975 | MakeSuccessCallback(barrier.Get(), &put_result1)); |
| 976 | |
| 977 | wrapper_impl()->GetAll( |
| 978 | GetAllCallback::CreateAndBind(&result, barrier.Get()), |
| 979 | MakeGetAllCallback(&status, &data)); |
| 980 | wrapper_impl()->Put(key, value2, value, test_source_, |
| 981 | MakeSuccessCallback(barrier.Get(), &put_result2)); |
| 982 | } |
| 983 | |
| 984 | // GetAll triggers a commit when it's switching map types. |
| 985 | EXPECT_TRUE(put_result1); |
| 986 | EXPECT_EQ("foo", get_mock_data(test_prefix_ + test_key2_)); |
| 987 | |
| 988 | EXPECT_FALSE(put_result2); |
| 989 | EXPECT_FALSE(result); |
| 990 | loop.Run(); |
| 991 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 992 | EXPECT_TRUE(result); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 993 | EXPECT_TRUE(put_result1); |
| 994 | |
| 995 | EXPECT_EQ(2u, data.size()); |
| 996 | EXPECT_TRUE( |
| 997 | data[1]->Equals(mojom::KeyValue(test_key1_bytes_, test_value1_bytes_))) |
| 998 | << ToString(data[1]->value) << " vs expected " << test_value1_; |
| 999 | EXPECT_TRUE(data[0]->Equals(mojom::KeyValue(key, value))) |
| 1000 | << ToString(data[0]->value) << " vs expected " << ToString(value); |
| 1001 | |
| 1002 | EXPECT_EQ(leveldb::mojom::DatabaseError::OK, status); |
| 1003 | |
| 1004 | // The last "put" isn't committed yet. |
| 1005 | EXPECT_EQ("foo", get_mock_data(test_prefix_ + test_key2_)); |
| 1006 | |
| 1007 | ASSERT_TRUE(wrapper_impl()->has_changes_to_commit()); |
| 1008 | BlockingCommit(); |
| 1009 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 1010 | EXPECT_EQ("foobar", get_mock_data(test_prefix_ + test_key2_)); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 1011 | } |
| 1012 | |
| 1013 | TEST_F(LevelDBWrapperImplTest, GetAllAfterSetCacheMode) { |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 1014 | std::vector<uint8_t> key = test_key2_bytes_; |
| 1015 | std::vector<uint8_t> value = ToBytes("foo"); |
| 1016 | std::vector<uint8_t> value2 = ToBytes("foobar"); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 1017 | |
| 1018 | // Go to load state only keys. |
| 1019 | ASSERT_TRUE(PutSync(key, value, base::nullopt)); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 1020 | BlockingCommit(); |
| 1021 | EXPECT_TRUE(wrapper_impl()->map_state_ == |
| 1022 | LevelDBWrapperImpl::MapState::LOADED_KEYS_ONLY); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 1023 | ASSERT_TRUE(PutSync(key, value2, value)); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 1024 | EXPECT_TRUE(wrapper_impl()->has_changes_to_commit()); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 1025 | |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 1026 | wrapper_impl()->SetCacheModeForTesting(CacheMode::KEYS_AND_VALUES); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 1027 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 1028 | // Cache isn't cleared when commit batch exists. |
| 1029 | EXPECT_TRUE(wrapper_impl()->map_state_ == |
| 1030 | LevelDBWrapperImpl::MapState::LOADED_KEYS_ONLY); |
| 1031 | |
| 1032 | base::RunLoop loop; |
| 1033 | |
| 1034 | bool put_success = false; |
| 1035 | leveldb::mojom::DatabaseError status; |
| 1036 | std::vector<mojom::KeyValuePtr> data; |
| 1037 | bool get_all_success = false; |
| 1038 | bool delete_success = false; |
| 1039 | { |
| 1040 | IncrementalBarrier barrier(loop.QuitClosure()); |
| 1041 | |
| 1042 | wrapper_impl()->Put(key, value, value2, test_source_, |
| 1043 | MakeSuccessCallback(barrier.Get(), &put_success)); |
| 1044 | |
| 1045 | // Put task triggers database upgrade, so there are no more changes |
| 1046 | // to commit. |
| 1047 | EXPECT_FALSE(wrapper_impl()->has_changes_to_commit()); |
| 1048 | EXPECT_TRUE(wrapper_impl()->has_pending_load_tasks()); |
| 1049 | |
| 1050 | wrapper_impl()->GetAll( |
| 1051 | GetAllCallback::CreateAndBind(&get_all_success, barrier.Get()), |
| 1052 | MakeGetAllCallback(&status, &data)); |
| 1053 | |
| 1054 | // This Delete() should not affect the value returned by GetAll(). |
| 1055 | wrapper_impl()->Delete(key, value, test_source_, |
| 1056 | MakeSuccessCallback(barrier.Get(), &delete_success)); |
| 1057 | } |
| 1058 | loop.Run(); |
| 1059 | |
| 1060 | EXPECT_EQ(2u, data.size()); |
| 1061 | EXPECT_TRUE( |
| 1062 | data[1]->Equals(mojom::KeyValue(test_key1_bytes_, test_value1_bytes_))) |
| 1063 | << ToString(data[1]->value) << " vs expected " << test_value1_; |
| 1064 | EXPECT_TRUE(data[0]->Equals(mojom::KeyValue(key, value))) |
| 1065 | << ToString(data[0]->value) << " vs expected " << ToString(value2); |
| 1066 | |
| 1067 | EXPECT_EQ(leveldb::mojom::DatabaseError::OK, status); |
| 1068 | |
| 1069 | EXPECT_TRUE(put_success); |
| 1070 | EXPECT_TRUE(get_all_success); |
| 1071 | EXPECT_TRUE(delete_success); |
| 1072 | |
| 1073 | // GetAll shouldn't trigger a commit before it runs now because the value |
| 1074 | // map should be loading. |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 1075 | EXPECT_EQ("foobar", get_mock_data(test_prefix_ + test_key2_)); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 1076 | |
| 1077 | ASSERT_TRUE(wrapper_impl()->has_changes_to_commit()); |
| 1078 | BlockingCommit(); |
| 1079 | |
| 1080 | EXPECT_FALSE(has_mock_data(test_prefix_ + test_key2_)); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 1081 | } |
| 1082 | |
| 1083 | TEST_F(LevelDBWrapperImplTest, SetCacheModeConsistent) { |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 1084 | std::vector<uint8_t> key = test_key2_bytes_; |
| 1085 | std::vector<uint8_t> value = ToBytes("foo"); |
| 1086 | std::vector<uint8_t> value2 = ToBytes("foobar"); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 1087 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 1088 | EXPECT_FALSE(wrapper_impl()->IsMapLoaded()); |
| 1089 | EXPECT_TRUE(wrapper_impl()->cache_mode() == |
| 1090 | CacheMode::KEYS_ONLY_WHEN_POSSIBLE); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 1091 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 1092 | // Clear the database before the wrapper loads data. |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 1093 | clear_mock_data(); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 1094 | |
| 1095 | EXPECT_TRUE(PutSync(key, value, base::nullopt)); |
| 1096 | EXPECT_TRUE(wrapper_impl()->has_changes_to_commit()); |
| 1097 | BlockingCommit(); |
| 1098 | |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 1099 | EXPECT_TRUE(PutSync(key, value2, value)); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 1100 | EXPECT_TRUE(wrapper_impl()->has_changes_to_commit()); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 1101 | |
| 1102 | // Setting cache mode does not reload the cache till it is required. |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 1103 | wrapper_impl()->SetCacheModeForTesting(CacheMode::KEYS_AND_VALUES); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 1104 | EXPECT_EQ(LevelDBWrapperImpl::MapState::LOADED_KEYS_ONLY, |
| 1105 | wrapper_impl()->map_state_); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 1106 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 1107 | // Put operation should change the mode. |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 1108 | EXPECT_TRUE(PutSync(key, value, value2)); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 1109 | EXPECT_TRUE(wrapper_impl()->has_changes_to_commit()); |
| 1110 | EXPECT_EQ(LevelDBWrapperImpl::MapState::LOADED_KEYS_AND_VALUES, |
| 1111 | wrapper_impl()->map_state_); |
| 1112 | std::vector<uint8_t> result; |
| 1113 | EXPECT_TRUE(GetSync(key, &result)); |
| 1114 | EXPECT_EQ(value, result); |
| 1115 | EXPECT_EQ(LevelDBWrapperImpl::MapState::LOADED_KEYS_AND_VALUES, |
| 1116 | wrapper_impl()->map_state_); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 1117 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 1118 | BlockingCommit(); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 1119 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 1120 | // Test that the map will unload correctly |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 1121 | EXPECT_TRUE(PutSync(key, value2, value)); |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 1122 | wrapper_impl()->SetCacheModeForTesting(CacheMode::KEYS_ONLY_WHEN_POSSIBLE); |
| 1123 | EXPECT_EQ(LevelDBWrapperImpl::MapState::LOADED_KEYS_ONLY, |
| 1124 | wrapper_impl()->map_state_); |
| 1125 | BlockingCommit(); |
| 1126 | EXPECT_EQ(LevelDBWrapperImpl::MapState::LOADED_KEYS_ONLY, |
| 1127 | wrapper_impl()->map_state_); |
| 1128 | |
| 1129 | // Test the map will unload right away when there are no changes. |
| 1130 | wrapper_impl()->SetCacheModeForTesting(CacheMode::KEYS_AND_VALUES); |
| 1131 | EXPECT_TRUE(GetSync(key, &result)); |
| 1132 | EXPECT_EQ(LevelDBWrapperImpl::MapState::LOADED_KEYS_AND_VALUES, |
| 1133 | wrapper_impl()->map_state_); |
| 1134 | wrapper_impl()->SetCacheModeForTesting(CacheMode::KEYS_ONLY_WHEN_POSSIBLE); |
| 1135 | EXPECT_EQ(LevelDBWrapperImpl::MapState::LOADED_KEYS_ONLY, |
| 1136 | wrapper_impl()->map_state_); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 1137 | } |
| 1138 | |
| 1139 | TEST_F(LevelDBWrapperImplTest, SendOldValueObservations) { |
| 1140 | should_record_send_old_value_observations(true); |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 1141 | wrapper_impl()->SetCacheModeForTesting(CacheMode::KEYS_AND_VALUES); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 1142 | // Flush tasks on mojo thread to observe callback. |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 1143 | EXPECT_TRUE(DeleteSync(ToBytes("doesn't exist"), base::nullopt)); |
| 1144 | wrapper_impl()->SetCacheModeForTesting(CacheMode::KEYS_ONLY_WHEN_POSSIBLE); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 1145 | // Flush tasks on mojo thread to observe callback. |
Daniel Murphy | 388e4c9c | 2017-11-14 23:10:19 | [diff] [blame] | 1146 | EXPECT_TRUE(DeleteSync(ToBytes("doesn't exist"), base::nullopt)); |
Siddhartha | e8191ca | 2017-11-07 18:24:20 | [diff] [blame] | 1147 | |
| 1148 | ASSERT_EQ(2u, observations().size()); |
| 1149 | EXPECT_EQ(Observation::kSendOldValue, observations()[0].type); |
| 1150 | EXPECT_FALSE(observations()[0].should_send_old_value); |
| 1151 | EXPECT_EQ(Observation::kSendOldValue, observations()[1].type); |
| 1152 | EXPECT_TRUE(observations()[1].should_send_old_value); |
| 1153 | } |
| 1154 | |
Daniel Murphy | 3d39c542 | 2017-11-21 03:24:07 | [diff] [blame] | 1155 | TEST_P(LevelDBWrapperImplParamTest, PrefixForking) { |
| 1156 | std::string value3 = "value3"; |
| 1157 | std::string value4 = "value4"; |
| 1158 | std::string value5 = "value5"; |
| 1159 | |
| 1160 | // In order to test the interaction between forking and mojo calls where |
| 1161 | // forking can happen in between a request and reply to the wrapper mojo |
| 1162 | // service, all calls are done on the 'impl' object itself. |
| 1163 | |
| 1164 | // Operations in the same run cycle: |
| 1165 | // Fork 1 created from original |
| 1166 | // Put on fork 1 |
| 1167 | // Fork 2 create from fork 1 |
| 1168 | // Put on fork 1 |
| 1169 | // Put on original |
| 1170 | // Fork 3 created from original |
| 1171 | std::unique_ptr<LevelDBWrapperImpl> fork1; |
| 1172 | MockDelegate fork1_delegate; |
| 1173 | std::unique_ptr<LevelDBWrapperImpl> fork2; |
| 1174 | MockDelegate fork2_delegate; |
| 1175 | std::unique_ptr<LevelDBWrapperImpl> fork3; |
| 1176 | MockDelegate fork3_delegate; |
| 1177 | |
| 1178 | auto options = GetDefaultTestingOptions(GetParam()); |
| 1179 | bool put_success1 = false; |
| 1180 | bool put_success2 = false; |
| 1181 | bool put_success3 = false; |
| 1182 | base::RunLoop loop; |
| 1183 | { |
| 1184 | IncrementalBarrier barrier(loop.QuitClosure()); |
| 1185 | |
| 1186 | // Create fork 1. |
| 1187 | fork1 = wrapper_impl()->ForkToNewPrefix(test_copy_prefix1_, &fork1_delegate, |
| 1188 | options); |
| 1189 | |
| 1190 | // Do a put on fork 1 and create fork 2. |
| 1191 | // Note - these are 'skipping' the mojo layer, which is why the fork isn't |
| 1192 | // scheduled. |
| 1193 | fork1->Put(test_key2_bytes_, ToBytes(value4), test_value2_bytes_, |
| 1194 | test_source_, MakeSuccessCallback(barrier.Get(), &put_success1)); |
| 1195 | fork2 = |
| 1196 | fork1->ForkToNewPrefix(test_copy_prefix2_, &fork2_delegate, options); |
| 1197 | fork1->Put(test_key2_bytes_, ToBytes(value5), ToBytes(value4), test_source_, |
| 1198 | MakeSuccessCallback(barrier.Get(), &put_success2)); |
| 1199 | |
| 1200 | // Do a put on original and create fork 3, which is key-only. |
| 1201 | wrapper_impl()->Put(test_key1_bytes_, ToBytes(value3), test_value1_bytes_, |
| 1202 | test_source_, |
| 1203 | MakeSuccessCallback(barrier.Get(), &put_success3)); |
| 1204 | fork3 = wrapper_impl()->ForkToNewPrefix( |
| 1205 | test_copy_prefix3_, &fork3_delegate, |
| 1206 | GetDefaultTestingOptions(CacheMode::KEYS_ONLY_WHEN_POSSIBLE)); |
| 1207 | } |
| 1208 | loop.Run(); |
| 1209 | EXPECT_TRUE(put_success1); |
| 1210 | EXPECT_TRUE(put_success2); |
| 1211 | EXPECT_TRUE(fork2.get()); |
| 1212 | EXPECT_TRUE(fork3.get()); |
| 1213 | |
| 1214 | EXPECT_EQ(value3, GetSyncStrUsingGetAll(wrapper_impl(), test_key1_)); |
| 1215 | EXPECT_EQ(test_value1_, GetSyncStrUsingGetAll(fork1.get(), test_key1_)); |
| 1216 | EXPECT_EQ(test_value1_, GetSyncStrUsingGetAll(fork2.get(), test_key1_)); |
| 1217 | EXPECT_EQ(value3, GetSyncStrUsingGetAll(fork3.get(), test_key1_)); |
| 1218 | |
| 1219 | EXPECT_EQ(test_value2_, GetSyncStrUsingGetAll(wrapper_impl(), test_key2_)); |
| 1220 | EXPECT_EQ(value5, GetSyncStrUsingGetAll(fork1.get(), test_key2_)); |
| 1221 | EXPECT_EQ(value4, GetSyncStrUsingGetAll(fork2.get(), test_key2_)); |
| 1222 | EXPECT_EQ(test_value2_, GetSyncStrUsingGetAll(fork3.get(), test_key2_)); |
| 1223 | |
| 1224 | BlockingCommit(delegate(), wrapper_impl()); |
| 1225 | BlockingCommit(&fork1_delegate, fork1.get()); |
| 1226 | |
| 1227 | // test_key1_ values. |
| 1228 | EXPECT_EQ(value3, get_mock_data(test_prefix_ + test_key1_)); |
| 1229 | EXPECT_EQ(test_value1_, get_mock_data(test_copy_prefix1_ + test_key1_)); |
| 1230 | EXPECT_EQ(test_value1_, get_mock_data(test_copy_prefix2_ + test_key1_)); |
| 1231 | EXPECT_EQ(value3, get_mock_data(test_copy_prefix3_ + test_key1_)); |
| 1232 | |
| 1233 | // test_key2_ values. |
| 1234 | EXPECT_EQ(test_value2_, get_mock_data(test_prefix_ + test_key2_)); |
| 1235 | EXPECT_EQ(value5, get_mock_data(test_copy_prefix1_ + test_key2_)); |
| 1236 | EXPECT_EQ(value4, get_mock_data(test_copy_prefix2_ + test_key2_)); |
| 1237 | EXPECT_EQ(test_value2_, get_mock_data(test_copy_prefix3_ + test_key2_)); |
| 1238 | } |
| 1239 | |
| 1240 | TEST_P(LevelDBWrapperImplParamTest, PrefixForkAfterLoad) { |
| 1241 | const std::string kValue = "foo"; |
| 1242 | const std::vector<uint8_t> kValueVec = ToBytes(kValue); |
| 1243 | |
| 1244 | // Do a sync put so the map loads. |
| 1245 | EXPECT_TRUE(PutSync(test_key1_bytes_, kValueVec, base::nullopt)); |
| 1246 | |
| 1247 | // Execute the fork. |
| 1248 | MockDelegate fork1_delegate; |
| 1249 | std::unique_ptr<LevelDBWrapperImpl> fork1 = |
| 1250 | wrapper_impl()->ForkToNewPrefix(test_copy_prefix1_, &fork1_delegate, |
| 1251 | GetDefaultTestingOptions(GetParam())); |
| 1252 | |
| 1253 | // Check our forked state. |
| 1254 | EXPECT_EQ(kValue, GetSyncStrUsingGetAll(fork1.get(), test_key1_)); |
| 1255 | |
| 1256 | BlockingCommit(delegate(), wrapper_impl()); |
| 1257 | |
| 1258 | EXPECT_EQ(kValue, get_mock_data(test_copy_prefix1_ + test_key1_)); |
| 1259 | } |
| 1260 | |
| 1261 | namespace { |
| 1262 | std::string GetNewPrefix(int* i) { |
| 1263 | std::string prefix = "prefix-" + base::Int64ToString(*i) + "-"; |
| 1264 | (*i)++; |
| 1265 | return prefix; |
| 1266 | } |
| 1267 | |
| 1268 | struct FuzzState { |
| 1269 | base::Optional<std::vector<uint8_t>> val1; |
| 1270 | base::Optional<std::vector<uint8_t>> val2; |
| 1271 | }; |
| 1272 | } // namespace |
| 1273 | |
| 1274 | TEST_F(LevelDBWrapperImplTest, PrefixForkingPsuedoFuzzer) { |
| 1275 | const std::string kKey1 = "key1"; |
| 1276 | const std::vector<uint8_t> kKey1Vec = ToBytes(kKey1); |
| 1277 | const std::string kKey2 = "key2"; |
| 1278 | const std::vector<uint8_t> kKey2Vec = ToBytes(kKey2); |
| 1279 | const int kTotalWrappers = 1000; |
| 1280 | |
| 1281 | // This tests tries to throw all possible enumartions of operations and |
| 1282 | // forking at wrappers. The purpose is to hit all edge cases possible to |
| 1283 | // expose any loading bugs. |
| 1284 | |
| 1285 | std::vector<FuzzState> states(kTotalWrappers); |
| 1286 | std::vector<std::unique_ptr<LevelDBWrapperImpl>> wrappers(kTotalWrappers); |
| 1287 | std::vector<MockDelegate> delegates(kTotalWrappers); |
| 1288 | std::list<bool> successes; |
| 1289 | int curr_prefix = 0; |
| 1290 | |
| 1291 | base::RunLoop loop; |
| 1292 | { |
| 1293 | IncrementalBarrier barrier(loop.QuitClosure()); |
| 1294 | for (int64_t i = 0; i < kTotalWrappers; i++) { |
| 1295 | FuzzState& state = states[i]; |
| 1296 | if (!wrappers[i]) { |
| 1297 | wrappers[i] = wrapper_impl()->ForkToNewPrefix( |
| 1298 | GetNewPrefix(&curr_prefix), &delegates[i], |
| 1299 | GetDefaultTestingOptions(CacheMode::KEYS_ONLY_WHEN_POSSIBLE)); |
| 1300 | } |
| 1301 | int64_t forks = i; |
| 1302 | if ((i % 5 == 0 || i % 6 == 0) && forks + 1 < kTotalWrappers) { |
| 1303 | forks++; |
| 1304 | states[forks] = state; |
| 1305 | wrappers[forks] = wrappers[i]->ForkToNewPrefix( |
| 1306 | GetNewPrefix(&curr_prefix), &delegates[forks], |
| 1307 | GetDefaultTestingOptions(CacheMode::KEYS_AND_VALUES)); |
| 1308 | } |
| 1309 | if (i % 13 == 0) { |
| 1310 | FuzzState old_state = state; |
| 1311 | state.val1 = base::nullopt; |
| 1312 | successes.push_back(false); |
| 1313 | wrappers[i]->Delete( |
| 1314 | kKey1Vec, old_state.val1, test_source_, |
| 1315 | MakeSuccessCallback(barrier.Get(), &successes.back())); |
| 1316 | } |
| 1317 | if (i % 4 == 0) { |
| 1318 | FuzzState old_state = state; |
| 1319 | state.val2 = base::make_optional<std::vector<uint8_t>>( |
| 1320 | {static_cast<uint8_t>(i)}); |
| 1321 | successes.push_back(false); |
| 1322 | wrappers[i]->Put(kKey2Vec, state.val2.value(), old_state.val2, |
| 1323 | test_source_, |
| 1324 | MakeSuccessCallback(barrier.Get(), &successes.back())); |
| 1325 | } |
| 1326 | if (i % 3 == 0) { |
| 1327 | FuzzState old_state = state; |
| 1328 | state.val1 = base::make_optional<std::vector<uint8_t>>( |
| 1329 | {static_cast<uint8_t>(i + 5)}); |
| 1330 | successes.push_back(false); |
| 1331 | wrappers[i]->Put(kKey1Vec, state.val1.value(), old_state.val1, |
| 1332 | test_source_, |
| 1333 | MakeSuccessCallback(barrier.Get(), &successes.back())); |
| 1334 | } |
| 1335 | if (i % 11 == 0) { |
| 1336 | state.val1 = base::nullopt; |
| 1337 | state.val2 = base::nullopt; |
| 1338 | successes.push_back(false); |
| 1339 | wrappers[i]->DeleteAll( |
| 1340 | test_source_, |
| 1341 | MakeSuccessCallback(barrier.Get(), &successes.back())); |
| 1342 | } |
| 1343 | if (i % 2 == 0 && forks + 1 < kTotalWrappers) { |
| 1344 | CacheMode mode = i % 3 == 0 ? CacheMode::KEYS_AND_VALUES |
| 1345 | : CacheMode::KEYS_ONLY_WHEN_POSSIBLE; |
| 1346 | forks++; |
| 1347 | states[forks] = state; |
| 1348 | wrappers[forks] = wrappers[i]->ForkToNewPrefix( |
| 1349 | GetNewPrefix(&curr_prefix), &delegates[forks], |
| 1350 | GetDefaultTestingOptions(mode)); |
| 1351 | } |
| 1352 | if (i % 3 == 0) { |
| 1353 | FuzzState old_state = state; |
| 1354 | state.val1 = base::make_optional<std::vector<uint8_t>>( |
| 1355 | {static_cast<uint8_t>(i + 9)}); |
| 1356 | successes.push_back(false); |
| 1357 | wrappers[i]->Put(kKey1Vec, state.val1.value(), old_state.val1, |
| 1358 | test_source_, |
| 1359 | MakeSuccessCallback(barrier.Get(), &successes.back())); |
| 1360 | } |
| 1361 | } |
| 1362 | } |
| 1363 | loop.Run(); |
| 1364 | |
| 1365 | // This section checks that we get the correct values when we query the |
| 1366 | // wrappers (which may or may not be maintaining their own cache). |
| 1367 | for (size_t i = 0; i < kTotalWrappers; i++) { |
| 1368 | FuzzState& state = states[i]; |
| 1369 | std::vector<uint8_t> result; |
| 1370 | |
| 1371 | // Note: this will cause all keys-only wrappers to commit. |
| 1372 | std::string result1 = GetSyncStrUsingGetAll(wrappers[i].get(), kKey1); |
| 1373 | std::string result2 = GetSyncStrUsingGetAll(wrappers[i].get(), kKey2); |
| 1374 | EXPECT_EQ(!!state.val1, !result1.empty()) << i; |
| 1375 | if (state.val1) |
| 1376 | EXPECT_EQ(state.val1.value(), ToBytes(result1)); |
| 1377 | EXPECT_EQ(!!state.val2, !result2.empty()) << i; |
| 1378 | if (state.val2) |
| 1379 | EXPECT_EQ(state.val2.value(), ToBytes(result2)) << i; |
| 1380 | } |
| 1381 | |
| 1382 | // This section verifies that all wrappers have committed their changes to |
| 1383 | // the database. |
| 1384 | ASSERT_EQ(wrappers.size(), delegates.size()); |
| 1385 | size_t half = kTotalWrappers / 2; |
| 1386 | for (size_t i = 0; i < half; i++) { |
| 1387 | BlockingCommit(&delegates[i], wrappers[i].get()); |
| 1388 | } |
| 1389 | |
| 1390 | for (size_t i = kTotalWrappers - 1; i >= half; i--) { |
| 1391 | BlockingCommit(&delegates[i], wrappers[i].get()); |
| 1392 | } |
| 1393 | |
| 1394 | // This section checks the data in the database itself to verify all wrappers |
| 1395 | // committed changes correctly. |
| 1396 | for (size_t i = 0; i < kTotalWrappers; ++i) { |
| 1397 | FuzzState& state = states[i]; |
| 1398 | |
| 1399 | std::vector<uint8_t> prefix = wrappers[i]->prefix(); |
| 1400 | std::string key1 = ToString(prefix) + kKey1; |
| 1401 | std::string key2 = ToString(prefix) + kKey2; |
| 1402 | EXPECT_EQ(!!state.val1, has_mock_data(key1)); |
| 1403 | if (state.val1) |
| 1404 | EXPECT_EQ(ToString(state.val1.value()), get_mock_data(key1)); |
| 1405 | EXPECT_EQ(!!state.val2, has_mock_data(key2)); |
| 1406 | if (state.val2) |
| 1407 | EXPECT_EQ(ToString(state.val2.value()), get_mock_data(key2)); |
| 1408 | |
| 1409 | EXPECT_FALSE(wrappers[i]->has_pending_load_tasks()) << i; |
| 1410 | } |
| 1411 | } |
| 1412 | |
mek | d51c84c | 2016-12-20 18:27:17 | [diff] [blame] | 1413 | } // namespace content |