blob: ac7b59e5dea98747c701ca39d98a17fe26f76ccc [file] [log] [blame]
mekd51c84c2016-12-20 18:27:171// 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 Murphy3d39c5422017-11-21 03:24:077#include "base/atomic_ref_count.h"
8#include "base/bind.h"
fdorayba121422016-12-23 19:51:489#include "base/memory/ptr_util.h"
mekeea75a432016-12-21 21:31:2710#include "base/run_loop.h"
Daniel Murphy3d39c5422017-11-21 03:24:0711#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"
mekd51c84c2016-12-20 18:27:1716#include "components/leveldb/public/cpp/util.h"
Daniel Murphy3d39c5422017-11-21 03:24:0717#include "components/leveldb/public/interfaces/leveldb.mojom.h"
mekd51c84c2016-12-20 18:27:1718#include "content/public/test/test_browser_thread_bundle.h"
Daniel Murphy47b12232017-11-07 21:04:2619#include "content/test/fake_leveldb_database.h"
mekeea75a432016-12-21 21:31:2720#include "mojo/public/cpp/bindings/associated_binding.h"
meka3b1e3d2016-12-22 17:18:0821#include "mojo/public/cpp/bindings/strong_associated_binding.h"
Daniel Murphy3d39c5422017-11-21 03:24:0722#include "mojo/public/cpp/bindings/strong_binding.h"
23#include "testing/gmock/include/gmock/gmock.h"
mekd51c84c2016-12-20 18:27:1724#include "testing/gtest/include/gtest/gtest.h"
25
mekd51c84c2016-12-20 18:27:1726namespace content {
27
28namespace {
Daniel Murphy388e4c9c2017-11-14 23:10:1929using CacheMode = LevelDBWrapperImpl::CacheMode;
30using DatabaseError = leveldb::mojom::DatabaseError;
mekd51c84c2016-12-20 18:27:1731
mekd51c84c2016-12-20 18:27:1732const char* kTestSource = "source";
33const size_t kTestSizeLimit = 512;
34
Daniel Murphy388e4c9c2017-11-14 23:10:1935std::string ToString(const std::vector<uint8_t>& input) {
36 return leveldb::Uint8VectorToStdString(input);
37}
38
39std::vector<uint8_t> ToBytes(const std::string& input) {
40 return leveldb::StdStringToUint8Vector(input);
41}
42
Daniel Murphy3d39c5422017-11-21 03:24:0743class 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.
74class 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
meka3b1e3d2016-12-22 17:18:0890class GetAllCallback : public mojom::LevelDBWrapperGetAllCallback {
91 public:
92 static mojom::LevelDBWrapperGetAllCallbackAssociatedPtrInfo CreateAndBind(
meka3b1e3d2016-12-22 17:18:0893 bool* result,
Siddharthae8191ca2017-11-07 18:24:2094 base::OnceClosure callback) {
Daniel Murphy3d39c5422017-11-21 03:24:0795 mojom::LevelDBWrapperGetAllCallbackAssociatedPtr ptr;
96 auto request = mojo::MakeRequestAssociatedWithDedicatedPipe(&ptr);
meka3b1e3d2016-12-22 17:18:0897 mojo::MakeStrongAssociatedBinding(
Siddharthae8191ca2017-11-07 18:24:2098 base::WrapUnique(new GetAllCallback(result, std::move(callback))),
meka3b1e3d2016-12-22 17:18:0899 std::move(request));
Daniel Murphy3d39c5422017-11-21 03:24:07100 return ptr.PassInterface();
meka3b1e3d2016-12-22 17:18:08101 }
102
103 private:
Siddharthae8191ca2017-11-07 18:24:20104 GetAllCallback(bool* result, base::OnceClosure callback)
Daniel Murphy3d39c5422017-11-21 03:24:07105 : result_(result), callback_(std::move(callback)) {}
meka3b1e3d2016-12-22 17:18:08106 void Complete(bool success) override {
Daniel Murphy3d39c5422017-11-21 03:24:07107 *result_ = success;
108 if (callback_)
109 std::move(callback_).Run();
meka3b1e3d2016-12-22 17:18:08110 }
111
Daniel Murphy3d39c5422017-11-21 03:24:07112 bool* result_;
113 base::OnceClosure callback_;
meka3b1e3d2016-12-22 17:18:08114};
115
mek222214f2017-01-17 21:30:51116class MockDelegate : public LevelDBWrapperImpl::Delegate {
117 public:
Daniel Murphy3d39c5422017-11-21 03:24:07118 MockDelegate() {}
119 ~MockDelegate() override {}
120
mek222214f2017-01-17 21:30:51121 void OnNoBindings() override {}
122 std::vector<leveldb::mojom::BatchedOperationPtr> PrepareToCommit() override {
123 return std::vector<leveldb::mojom::BatchedOperationPtr>();
124 }
Daniel Murphy3d39c5422017-11-21 03:24:07125 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 Murphy388e4c9c2017-11-14 23:10:19131 void OnMapLoaded(DatabaseError error) override { map_load_count_++; }
Marijn Kruisselbrinke8fdb3d2017-09-26 01:33:07132 std::vector<LevelDBWrapperImpl::Change> FixUpData(
133 const LevelDBWrapperImpl::ValueMap& data) override {
Siddharthae8191ca2017-11-07 18:24:20134 return std::move(mock_changes_);
Marijn Kruisselbrinke8fdb3d2017-09-26 01:33:07135 }
mekdea811df2017-03-01 17:57:57136
137 int map_load_count() const { return map_load_count_; }
Marijn Kruisselbrinke8fdb3d2017-09-26 01:33:07138 void set_mock_changes(std::vector<LevelDBWrapperImpl::Change> changes) {
139 mock_changes_ = std::move(changes);
140 }
mekdea811df2017-03-01 17:57:57141
Daniel Murphy3d39c5422017-11-21 03:24:07142 void SetDidCommitCallback(base::OnceClosure committed) {
143 committed_ = std::move(committed);
144 }
145
mekdea811df2017-03-01 17:57:57146 private:
147 int map_load_count_ = 0;
Marijn Kruisselbrinke8fdb3d2017-09-26 01:33:07148 std::vector<LevelDBWrapperImpl::Change> mock_changes_;
Daniel Murphy3d39c5422017-11-21 03:24:07149 base::OnceClosure committed_;
mek222214f2017-01-17 21:30:51150};
mekd51c84c2016-12-20 18:27:17151
Daniel Murphy388e4c9c2017-11-14 23:10:19152void GetCallback(base::OnceClosure callback,
mekd51c84c2016-12-20 18:27:17153 bool* success_out,
154 std::vector<uint8_t>* value_out,
155 bool success,
156 const std::vector<uint8_t>& value) {
mekd51c84c2016-12-20 18:27:17157 *success_out = success;
158 *value_out = value;
Daniel Murphy388e4c9c2017-11-14 23:10:19159 std::move(callback).Run();
mekd51c84c2016-12-20 18:27:17160}
161
Daniel Murphy3d39c5422017-11-21 03:24:07162base::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
170void 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
178base::OnceCallback<void(leveldb::mojom::DatabaseError status,
179 std::vector<mojom::KeyValuePtr> data)>
180MakeGetAllCallback(leveldb::mojom::DatabaseError* status_out,
181 std::vector<mojom::KeyValuePtr>* data_out) {
182 return base::BindOnce(&GetAllDataCallback, status_out, data_out);
183}
184
Daniel Murphy388e4c9c2017-11-14 23:10:19185void SuccessCallback(base::OnceClosure callback,
mekeea75a432016-12-21 21:31:27186 bool* success_out,
187 bool success) {
mekd51c84c2016-12-20 18:27:17188 *success_out = success;
Daniel Murphy388e4c9c2017-11-14 23:10:19189 std::move(callback).Run();
mekd51c84c2016-12-20 18:27:17190}
191
Daniel Murphy3d39c5422017-11-21 03:24:07192base::OnceCallback<void(bool)> MakeSuccessCallback(base::OnceClosure callback,
193 bool* success_out) {
194 return base::BindOnce(&SuccessCallback, std::move(callback), success_out);
195}
196
meka9c2a3c12016-12-29 20:50:18197void NoOpSuccessCallback(bool success) {}
198
Daniel Murphy3d39c5422017-11-21 03:24:07199LevelDBWrapperImpl::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
mekd51c84c2016-12-20 18:27:17209} // namespace
210
mekeea75a432016-12-21 21:31:27211class LevelDBWrapperImplTest : public testing::Test,
212 public mojom::LevelDBObserver {
mekd51c84c2016-12-20 18:27:17213 public:
mekeea75a432016-12-21 21:31:27214 struct Observation {
Siddharthae8191ca2017-11-07 18:24:20215 enum { kAdd, kChange, kDelete, kDeleteAll, kSendOldValue } type;
mekeea75a432016-12-21 21:31:27216 std::string key;
217 std::string old_value;
218 std::string new_value;
219 std::string source;
Siddharthae8191ca2017-11-07 18:24:20220 bool should_send_old_value;
mekeea75a432016-12-21 21:31:27221 };
222
Daniel Murphy3d39c5422017-11-21 03:24:07223 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);
Siddharthae8191ca2017-11-07 18:24:20229 level_db_wrapper_ = std::make_unique<LevelDBWrapperImpl>(
Daniel Murphy3d39c5422017-11-21 03:24:07230 level_db_database_ptr_.get(), test_prefix_, &delegate_, options);
Siddharthae8191ca2017-11-07 18:24:20231
Daniel Murphy388e4c9c2017-11-14 23:10:19232 set_mock_data(test_prefix_ + test_key1_, test_value1_);
233 set_mock_data(test_prefix_ + test_key2_, test_value2_);
Daniel Murphy3d39c5422017-11-21 03:24:07234 set_mock_data("123", "baddata");
mekeea75a432016-12-21 21:31:27235
Siddharthae8191ca2017-11-07 18:24:20236 level_db_wrapper_->Bind(mojo::MakeRequest(&level_db_wrapper_ptr_));
mekeea75a432016-12-21 21:31:27237 mojom::LevelDBObserverAssociatedPtrInfo ptr_info;
Ken Rockot42472452017-05-12 05:37:03238 observer_binding_.Bind(mojo::MakeRequest(&ptr_info));
mekeea75a432016-12-21 21:31:27239 level_db_wrapper_ptr_->AddObserver(std::move(ptr_info));
mekd51c84c2016-12-20 18:27:17240 }
241
Daniel Murphy3d39c5422017-11-21 03:24:07242 ~LevelDBWrapperImplTest() override {}
243
mekd51c84c2016-12-20 18:27:17244 void set_mock_data(const std::string& key, const std::string& value) {
Daniel Murphy388e4c9c2017-11-14 23:10:19245 mock_data_[ToBytes(key)] = ToBytes(value);
mekd51c84c2016-12-20 18:27:17246 }
247
mekeea75a432016-12-21 21:31:27248 void set_mock_data(const std::vector<uint8_t>& key,
249 const std::vector<uint8_t>& value) {
250 mock_data_[key] = value;
251 }
252
mekd51c84c2016-12-20 18:27:17253 bool has_mock_data(const std::string& key) {
Daniel Murphy388e4c9c2017-11-14 23:10:19254 return mock_data_.find(ToBytes(key)) != mock_data_.end();
mekd51c84c2016-12-20 18:27:17255 }
256
257 std::string get_mock_data(const std::string& key) {
Daniel Murphy388e4c9c2017-11-14 23:10:19258 return has_mock_data(key) ? ToString(mock_data_[ToBytes(key)]) : "";
mekd51c84c2016-12-20 18:27:17259 }
260
mek30ff3ed2017-02-15 22:52:14261 void clear_mock_data() { mock_data_.clear(); }
262
mekeea75a432016-12-21 21:31:27263 mojom::LevelDBWrapper* wrapper() { return level_db_wrapper_ptr_.get(); }
Siddharthae8191ca2017-11-07 18:24:20264 LevelDBWrapperImpl* wrapper_impl() { return level_db_wrapper_.get(); }
mekeea75a432016-12-21 21:31:27265
Daniel Murphy3d39c5422017-11-21 03:24:07266 bool GetSync(mojom::LevelDBWrapper* wrapper,
267 const std::vector<uint8_t>& key,
268 std::vector<uint8_t>* result) {
mekeea75a432016-12-21 21:31:27269 bool success = false;
Daniel Murphy3d39c5422017-11-21 03:24:07270 base::RunLoop loop;
271 wrapper->Get(key, MakeGetCallback(loop.QuitClosure(), &success, result));
272 loop.Run();
mekeea75a432016-12-21 21:31:27273 return success;
274 }
275
Daniel Murphy3d39c5422017-11-21 03:24:07276 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
mekeea75a432016-12-21 21:31:27314 bool PutSync(const std::vector<uint8_t>& key,
315 const std::vector<uint8_t>& value,
Siddharthac0600a2a2017-10-12 22:03:02316 const base::Optional<std::vector<uint8_t>>& client_old_value,
mekeea75a432016-12-21 21:31:27317 std::string source = kTestSource) {
Daniel Murphy3d39c5422017-11-21 03:24:07318 return PutSync(wrapper(), key, value, client_old_value, source);
mekeea75a432016-12-21 21:31:27319 }
320
Siddharthac0600a2a2017-10-12 22:03:02321 bool DeleteSync(
322 const std::vector<uint8_t>& key,
323 const base::Optional<std::vector<uint8_t>>& client_old_value) {
Daniel Murphy3d39c5422017-11-21 03:24:07324 return DeleteSync(wrapper(), key, client_old_value);
mekeea75a432016-12-21 21:31:27325 }
326
Daniel Murphy3d39c5422017-11-21 03:24:07327 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 "";
mekeea75a432016-12-21 21:31:27355 }
mekd51c84c2016-12-20 18:27:17356
Daniel Murphy3d39c5422017-11-21 03:24:07357 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 }
mekd51c84c2016-12-20 18:27:17368
mekeea75a432016-12-21 21:31:27369 const std::vector<Observation>& observations() { return observations_; }
370
mekdea811df2017-03-01 17:57:57371 MockDelegate* delegate() { return &delegate_; }
372
Siddharthae8191ca2017-11-07 18:24:20373 void should_record_send_old_value_observations(bool value) {
374 should_record_send_old_value_observations_ = value;
375 }
376
Daniel Murphy388e4c9c2017-11-14 23:10:19377 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 Murphy3d39c5422017-11-21 03:24:07383 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 Murphy388e4c9c2017-11-14 23:10:19387
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 Murphy3d39c5422017-11-21 03:24:07391 const std::vector<uint8_t> test_value1_bytes_ = ToBytes(test_value1_);
Daniel Murphy388e4c9c2017-11-14 23:10:19392 const std::vector<uint8_t> test_value2_bytes_ = ToBytes(test_value2_);
393
mekd51c84c2016-12-20 18:27:17394 private:
mekeea75a432016-12-21 21:31:27395 // LevelDBObserver:
396 void KeyAdded(const std::vector<uint8_t>& key,
397 const std::vector<uint8_t>& value,
398 const std::string& source) override {
Daniel Murphy388e4c9c2017-11-14 23:10:19399 observations_.push_back(
400 {Observation::kAdd, ToString(key), "", ToString(value), source, false});
mekeea75a432016-12-21 21:31:27401 }
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 Murphy388e4c9c2017-11-14 23:10:19406 observations_.push_back({Observation::kChange, ToString(key),
407 ToString(old_value), ToString(new_value), source,
408 false});
mekeea75a432016-12-21 21:31:27409 }
410 void KeyDeleted(const std::vector<uint8_t>& key,
411 const std::vector<uint8_t>& old_value,
412 const std::string& source) override {
Daniel Murphy388e4c9c2017-11-14 23:10:19413 observations_.push_back({Observation::kDelete, ToString(key),
414 ToString(old_value), "", source, false});
mekeea75a432016-12-21 21:31:27415 }
416 void AllDeleted(const std::string& source) override {
Siddharthae8191ca2017-11-07 18:24:20417 observations_.push_back(
418 {Observation::kDeleteAll, "", "", "", source, false});
mekeea75a432016-12-21 21:31:27419 }
Siddharthae8191ca2017-11-07 18:24:20420 void ShouldSendOldValueOnMutations(bool value) override {
421 if (should_record_send_old_value_observations_)
422 observations_.push_back(
423 {Observation::kSendOldValue, "", "", "", "", value});
424 }
mekeea75a432016-12-21 21:31:27425
mekd51c84c2016-12-20 18:27:17426 TestBrowserThreadBundle thread_bundle_;
427 std::map<std::vector<uint8_t>, std::vector<uint8_t>> mock_data_;
Daniel Murphy47b12232017-11-07 21:04:26428 FakeLevelDBDatabase db_;
Daniel Murphy3d39c5422017-11-21 03:24:07429 leveldb::mojom::LevelDBDatabasePtr level_db_database_ptr_;
mek222214f2017-01-17 21:30:51430 MockDelegate delegate_;
Siddharthae8191ca2017-11-07 18:24:20431 std::unique_ptr<LevelDBWrapperImpl> level_db_wrapper_;
mekeea75a432016-12-21 21:31:27432 mojom::LevelDBWrapperPtr level_db_wrapper_ptr_;
433 mojo::AssociatedBinding<mojom::LevelDBObserver> observer_binding_;
434 std::vector<Observation> observations_;
Siddharthae8191ca2017-11-07 18:24:20435 bool should_record_send_old_value_observations_ = false;
mekd51c84c2016-12-20 18:27:17436};
437
Siddharthae8191ca2017-11-07 18:24:20438class LevelDBWrapperImplParamTest
439 : public LevelDBWrapperImplTest,
Daniel Murphy388e4c9c2017-11-14 23:10:19440 public testing::WithParamInterface<CacheMode> {
Siddharthae8191ca2017-11-07 18:24:20441 public:
442 LevelDBWrapperImplParamTest() {}
443 ~LevelDBWrapperImplParamTest() override {}
444};
445
Daniel Murphy388e4c9c2017-11-14 23:10:19446INSTANTIATE_TEST_CASE_P(LevelDBWrapperImplTest,
447 LevelDBWrapperImplParamTest,
448 testing::Values(CacheMode::KEYS_ONLY_WHEN_POSSIBLE,
449 CacheMode::KEYS_AND_VALUES));
Siddharthae8191ca2017-11-07 18:24:20450
mekd51c84c2016-12-20 18:27:17451TEST_F(LevelDBWrapperImplTest, GetLoadedFromMap) {
Daniel Murphy388e4c9c2017-11-14 23:10:19452 wrapper_impl()->SetCacheModeForTesting(CacheMode::KEYS_AND_VALUES);
mekd51c84c2016-12-20 18:27:17453 std::vector<uint8_t> result;
Daniel Murphy388e4c9c2017-11-14 23:10:19454 EXPECT_TRUE(GetSync(test_key2_bytes_, &result));
455 EXPECT_EQ(test_value2_bytes_, result);
mekd51c84c2016-12-20 18:27:17456
Daniel Murphy388e4c9c2017-11-14 23:10:19457 EXPECT_FALSE(GetSync(ToBytes("x"), &result));
mekd51c84c2016-12-20 18:27:17458}
459
460TEST_F(LevelDBWrapperImplTest, GetFromPutOverwrite) {
Daniel Murphy388e4c9c2017-11-14 23:10:19461 wrapper_impl()->SetCacheModeForTesting(CacheMode::KEYS_AND_VALUES);
462 std::vector<uint8_t> key = test_key2_bytes_;
463 std::vector<uint8_t> value = ToBytes("foo");
mekd51c84c2016-12-20 18:27:17464
Daniel Murphy3d39c5422017-11-21 03:24:07465 base::RunLoop loop;
466 bool put_success = false;
mekd51c84c2016-12-20 18:27:17467 std::vector<uint8_t> result;
Daniel Murphy3d39c5422017-11-21 03:24:07468 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
mekd51c84c2016-12-20 18:27:17480 EXPECT_EQ(value, result);
481}
482
483TEST_F(LevelDBWrapperImplTest, GetFromPutNewKey) {
Daniel Murphy388e4c9c2017-11-14 23:10:19484 wrapper_impl()->SetCacheModeForTesting(CacheMode::KEYS_AND_VALUES);
485 std::vector<uint8_t> key = ToBytes("newkey");
486 std::vector<uint8_t> value = ToBytes("foo");
mekd51c84c2016-12-20 18:27:17487
Siddharthac0600a2a2017-10-12 22:03:02488 EXPECT_TRUE(PutSync(key, value, base::nullopt));
mekd51c84c2016-12-20 18:27:17489
mekd51c84c2016-12-20 18:27:17490 std::vector<uint8_t> result;
mekeea75a432016-12-21 21:31:27491 EXPECT_TRUE(GetSync(key, &result));
mekd51c84c2016-12-20 18:27:17492 EXPECT_EQ(value, result);
493}
494
Daniel Murphy3d39c5422017-11-21 03:24:07495TEST_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
Siddharthae8191ca2017-11-07 18:24:20519TEST_P(LevelDBWrapperImplParamTest, GetAll) {
520 wrapper_impl()->SetCacheModeForTesting(GetParam());
Daniel Murphy388e4c9c2017-11-14 23:10:19521 DatabaseError status;
mekd51c84c2016-12-20 18:27:17522 std::vector<mojom::KeyValuePtr> data;
meka3b1e3d2016-12-22 17:18:08523 bool result = false;
Daniel Murphy3d39c5422017-11-21 03:24:07524
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);
mekd51c84c2016-12-20 18:27:17533 EXPECT_EQ(2u, data.size());
meka3b1e3d2016-12-22 17:18:08534 EXPECT_TRUE(result);
mekd51c84c2016-12-20 18:27:17535}
536
Siddharthae8191ca2017-11-07 18:24:20537TEST_P(LevelDBWrapperImplParamTest, CommitPutToDB) {
538 wrapper_impl()->SetCacheModeForTesting(GetParam());
Daniel Murphy388e4c9c2017-11-14 23:10:19539 std::string key1 = test_key2_;
mekd51c84c2016-12-20 18:27:17540 std::string value1 = "foo";
Daniel Murphy388e4c9c2017-11-14 23:10:19541 std::string key2 = test_prefix_;
mekd51c84c2016-12-20 18:27:17542 std::string value2 = "data abc";
543
Daniel Murphy3d39c5422017-11-21 03:24:07544 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);
mekeea75a432016-12-21 21:31:27566
Daniel Murphy388e4c9c2017-11-14 23:10:19567 EXPECT_FALSE(has_mock_data(test_prefix_ + key2));
mekd51c84c2016-12-20 18:27:17568
Daniel Murphy3d39c5422017-11-21 03:24:07569 BlockingCommit();
Daniel Murphy388e4c9c2017-11-14 23:10:19570 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));
mekd51c84c2016-12-20 18:27:17574}
575
Siddharthae8191ca2017-11-07 18:24:20576TEST_P(LevelDBWrapperImplParamTest, PutObservations) {
577 wrapper_impl()->SetCacheModeForTesting(GetParam());
mekeea75a432016-12-21 21:31:27578 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 Murphy388e4c9c2017-11-14 23:10:19584 EXPECT_TRUE(PutSync(ToBytes(key), ToBytes(value1), base::nullopt, source1));
mekeea75a432016-12-21 21:31:27585 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 Murphy388e4c9c2017-11-14 23:10:19591 EXPECT_TRUE(PutSync(ToBytes(key), ToBytes(value2), ToBytes(value1), source2));
mekeea75a432016-12-21 21:31:27592 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);
mek30ff3ed2017-02-15 22:52:14598
599 // Same put should not cause another observation.
Daniel Murphy3d39c5422017-11-21 03:24:07600 EXPECT_TRUE(PutSync(ToBytes(key), ToBytes(value2), ToBytes(value2), source2));
mek30ff3ed2017-02-15 22:52:14601 ASSERT_EQ(2u, observations().size());
mekeea75a432016-12-21 21:31:27602}
603
Siddharthae8191ca2017-11-07 18:24:20604TEST_P(LevelDBWrapperImplParamTest, DeleteNonExistingKey) {
605 wrapper_impl()->SetCacheModeForTesting(GetParam());
Daniel Murphy388e4c9c2017-11-14 23:10:19606 EXPECT_TRUE(DeleteSync(ToBytes("doesn't exist"), std::vector<uint8_t>()));
mekeea75a432016-12-21 21:31:27607 EXPECT_EQ(0u, observations().size());
608}
609
Siddharthae8191ca2017-11-07 18:24:20610TEST_P(LevelDBWrapperImplParamTest, DeleteExistingKey) {
611 wrapper_impl()->SetCacheModeForTesting(GetParam());
mekeea75a432016-12-21 21:31:27612 std::string key = "newkey";
613 std::string value = "foo";
Daniel Murphy388e4c9c2017-11-14 23:10:19614 set_mock_data(test_prefix_ + key, value);
mekeea75a432016-12-21 21:31:27615
Daniel Murphy388e4c9c2017-11-14 23:10:19616 EXPECT_TRUE(DeleteSync(ToBytes(key), ToBytes(value)));
mekeea75a432016-12-21 21:31:27617 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 Murphy3d39c5422017-11-21 03:24:07621 EXPECT_EQ(test_source_, observations()[0].source);
mekeea75a432016-12-21 21:31:27622
Daniel Murphy388e4c9c2017-11-14 23:10:19623 EXPECT_TRUE(has_mock_data(test_prefix_ + key));
mekeea75a432016-12-21 21:31:27624
Daniel Murphy3d39c5422017-11-21 03:24:07625 BlockingCommit();
Daniel Murphy388e4c9c2017-11-14 23:10:19626 EXPECT_FALSE(has_mock_data(test_prefix_ + key));
mekeea75a432016-12-21 21:31:27627}
628
Siddharthae8191ca2017-11-07 18:24:20629TEST_P(LevelDBWrapperImplParamTest, DeleteAllWithoutLoadedMap) {
630 wrapper_impl()->SetCacheModeForTesting(GetParam());
mekeea75a432016-12-21 21:31:27631 std::string key = "newkey";
632 std::string value = "foo";
633 std::string dummy_key = "foobar";
634 set_mock_data(dummy_key, value);
Daniel Murphy388e4c9c2017-11-14 23:10:19635 set_mock_data(test_prefix_ + key, value);
mekeea75a432016-12-21 21:31:27636
637 EXPECT_TRUE(DeleteAllSync());
638 ASSERT_EQ(1u, observations().size());
639 EXPECT_EQ(Observation::kDeleteAll, observations()[0].type);
Daniel Murphy3d39c5422017-11-21 03:24:07640 EXPECT_EQ(test_source_, observations()[0].source);
mekeea75a432016-12-21 21:31:27641
Daniel Murphy388e4c9c2017-11-14 23:10:19642 EXPECT_TRUE(has_mock_data(test_prefix_ + key));
mekeea75a432016-12-21 21:31:27643 EXPECT_TRUE(has_mock_data(dummy_key));
644
Daniel Murphy3d39c5422017-11-21 03:24:07645 BlockingCommit();
Daniel Murphy388e4c9c2017-11-14 23:10:19646 EXPECT_FALSE(has_mock_data(test_prefix_ + key));
mekeea75a432016-12-21 21:31:27647 EXPECT_TRUE(has_mock_data(dummy_key));
648
mek30ff3ed2017-02-15 22:52:14649 // Deleting all again should still work, but not cause an observation.
mekeea75a432016-12-21 21:31:27650 EXPECT_TRUE(DeleteAllSync());
mek30ff3ed2017-02-15 22:52:14651 ASSERT_EQ(1u, observations().size());
mekeea75a432016-12-21 21:31:27652
653 // And now we've deleted all, writing something the quota size should work.
654 EXPECT_TRUE(PutSync(std::vector<uint8_t>(kTestSizeLimit, 'b'),
Siddharthac0600a2a2017-10-12 22:03:02655 std::vector<uint8_t>(), base::nullopt));
mekeea75a432016-12-21 21:31:27656}
657
Siddharthae8191ca2017-11-07 18:24:20658TEST_P(LevelDBWrapperImplParamTest, DeleteAllWithLoadedMap) {
659 wrapper_impl()->SetCacheModeForTesting(GetParam());
meka9c2a3c12016-12-29 20:50:18660 std::string key = "newkey";
661 std::string value = "foo";
662 std::string dummy_key = "foobar";
663 set_mock_data(dummy_key, value);
664
Daniel Murphy388e4c9c2017-11-14 23:10:19665 EXPECT_TRUE(PutSync(ToBytes(key), ToBytes(value), base::nullopt));
meka9c2a3c12016-12-29 20:50:18666
667 EXPECT_TRUE(DeleteAllSync());
668 ASSERT_EQ(2u, observations().size());
669 EXPECT_EQ(Observation::kDeleteAll, observations()[1].type);
Daniel Murphy3d39c5422017-11-21 03:24:07670 EXPECT_EQ(test_source_, observations()[1].source);
meka9c2a3c12016-12-29 20:50:18671
672 EXPECT_TRUE(has_mock_data(dummy_key));
673
Daniel Murphy3d39c5422017-11-21 03:24:07674 BlockingCommit();
Daniel Murphy388e4c9c2017-11-14 23:10:19675 EXPECT_FALSE(has_mock_data(test_prefix_ + key));
meka9c2a3c12016-12-29 20:50:18676 EXPECT_TRUE(has_mock_data(dummy_key));
677}
678
Siddharthae8191ca2017-11-07 18:24:20679TEST_P(LevelDBWrapperImplParamTest, DeleteAllWithPendingMapLoad) {
680 wrapper_impl()->SetCacheModeForTesting(GetParam());
meka9c2a3c12016-12-29 20:50:18681 std::string key = "newkey";
682 std::string value = "foo";
683 std::string dummy_key = "foobar";
684 set_mock_data(dummy_key, value);
685
Daniel Murphy388e4c9c2017-11-14 23:10:19686 wrapper()->Put(ToBytes(key), ToBytes(value), base::nullopt, kTestSource,
Siddharthac0600a2a2017-10-12 22:03:02687 base::BindOnce(&NoOpSuccessCallback));
meka9c2a3c12016-12-29 20:50:18688
689 EXPECT_TRUE(DeleteAllSync());
690 ASSERT_EQ(2u, observations().size());
691 EXPECT_EQ(Observation::kDeleteAll, observations()[1].type);
Daniel Murphy3d39c5422017-11-21 03:24:07692 EXPECT_EQ(test_source_, observations()[1].source);
meka9c2a3c12016-12-29 20:50:18693
694 EXPECT_TRUE(has_mock_data(dummy_key));
695
Daniel Murphy3d39c5422017-11-21 03:24:07696 BlockingCommit();
Daniel Murphy388e4c9c2017-11-14 23:10:19697 EXPECT_FALSE(has_mock_data(test_prefix_ + key));
meka9c2a3c12016-12-29 20:50:18698 EXPECT_TRUE(has_mock_data(dummy_key));
699}
700
Siddharthae8191ca2017-11-07 18:24:20701TEST_P(LevelDBWrapperImplParamTest, DeleteAllWithoutLoadedEmptyMap) {
702 wrapper_impl()->SetCacheModeForTesting(GetParam());
mek30ff3ed2017-02-15 22:52:14703 clear_mock_data();
704
705 EXPECT_TRUE(DeleteAllSync());
706 ASSERT_EQ(0u, observations().size());
707}
708
Daniel Murphy674c3bd2017-11-17 04:21:56709TEST_F(LevelDBWrapperImplParamTest, PutOverQuotaLargeValue) {
710 wrapper_impl()->SetCacheModeForTesting(
711 LevelDBWrapperImpl::CacheMode::KEYS_AND_VALUES);
Daniel Murphy388e4c9c2017-11-14 23:10:19712 std::vector<uint8_t> key = ToBytes("newkey");
meka95ed902016-12-21 02:46:35713 std::vector<uint8_t> value(kTestSizeLimit, 4);
714
Siddharthac0600a2a2017-10-12 22:03:02715 EXPECT_FALSE(PutSync(key, value, base::nullopt));
meka95ed902016-12-21 02:46:35716
717 value.resize(kTestSizeLimit / 2);
Siddharthac0600a2a2017-10-12 22:03:02718 EXPECT_TRUE(PutSync(key, value, base::nullopt));
meka95ed902016-12-21 02:46:35719}
720
Daniel Murphy674c3bd2017-11-17 04:21:56721TEST_F(LevelDBWrapperImplParamTest, PutOverQuotaLargeKey) {
722 wrapper_impl()->SetCacheModeForTesting(
723 LevelDBWrapperImpl::CacheMode::KEYS_AND_VALUES);
meka95ed902016-12-21 02:46:35724 std::vector<uint8_t> key(kTestSizeLimit, 'a');
Daniel Murphy388e4c9c2017-11-14 23:10:19725 std::vector<uint8_t> value = ToBytes("newvalue");
meka95ed902016-12-21 02:46:35726
Siddharthac0600a2a2017-10-12 22:03:02727 EXPECT_FALSE(PutSync(key, value, base::nullopt));
meka95ed902016-12-21 02:46:35728
729 key.resize(kTestSizeLimit / 2);
Siddharthac0600a2a2017-10-12 22:03:02730 EXPECT_TRUE(PutSync(key, value, base::nullopt));
meka95ed902016-12-21 02:46:35731}
732
Daniel Murphy674c3bd2017-11-17 04:21:56733TEST_F(LevelDBWrapperImplParamTest, PutWhenAlreadyOverQuota) {
734 wrapper_impl()->SetCacheModeForTesting(
735 LevelDBWrapperImpl::CacheMode::KEYS_AND_VALUES);
meka95ed902016-12-21 02:46:35736 std::string key = "largedata";
737 std::vector<uint8_t> value(kTestSizeLimit, 4);
Siddharthac0600a2a2017-10-12 22:03:02738 std::vector<uint8_t> old_value = value;
meka95ed902016-12-21 02:46:35739
Daniel Murphy388e4c9c2017-11-14 23:10:19740 set_mock_data(test_prefix_ + key, ToString(value));
meka95ed902016-12-21 02:46:35741
742 // Put with same data should succeed.
Daniel Murphy388e4c9c2017-11-14 23:10:19743 EXPECT_TRUE(PutSync(ToBytes(key), value, base::nullopt));
meka95ed902016-12-21 02:46:35744
745 // Put with same data size should succeed.
meka95ed902016-12-21 02:46:35746 value[1] = 13;
Daniel Murphy388e4c9c2017-11-14 23:10:19747 EXPECT_TRUE(PutSync(ToBytes(key), value, old_value));
meka95ed902016-12-21 02:46:35748
749 // Adding a new key when already over quota should not succeed.
Daniel Murphy388e4c9c2017-11-14 23:10:19750 EXPECT_FALSE(PutSync(ToBytes("newkey"), {1, 2, 3}, base::nullopt));
meka95ed902016-12-21 02:46:35751
752 // Reducing size should also succeed.
Siddharthac0600a2a2017-10-12 22:03:02753 old_value = value;
meka95ed902016-12-21 02:46:35754 value.resize(kTestSizeLimit / 2);
Daniel Murphy388e4c9c2017-11-14 23:10:19755 EXPECT_TRUE(PutSync(ToBytes(key), value, old_value));
meka95ed902016-12-21 02:46:35756
757 // Increasing size again should succeed, as still under the limit.
Siddharthac0600a2a2017-10-12 22:03:02758 old_value = value;
meka95ed902016-12-21 02:46:35759 value.resize(value.size() + 1);
Daniel Murphy388e4c9c2017-11-14 23:10:19760 EXPECT_TRUE(PutSync(ToBytes(key), value, old_value));
meka95ed902016-12-21 02:46:35761
762 // But increasing back to original size should fail.
Siddharthac0600a2a2017-10-12 22:03:02763 old_value = value;
meka95ed902016-12-21 02:46:35764 value.resize(kTestSizeLimit);
Daniel Murphy388e4c9c2017-11-14 23:10:19765 EXPECT_FALSE(PutSync(ToBytes(key), value, old_value));
meka95ed902016-12-21 02:46:35766}
767
Daniel Murphy674c3bd2017-11-17 04:21:56768TEST_F(LevelDBWrapperImplParamTest, PutWhenAlreadyOverQuotaBecauseOfLargeKey) {
769 wrapper_impl()->SetCacheModeForTesting(
770 LevelDBWrapperImpl::CacheMode::KEYS_AND_VALUES);
meka95ed902016-12-21 02:46:35771 std::vector<uint8_t> key(kTestSizeLimit, 'x');
Daniel Murphy388e4c9c2017-11-14 23:10:19772 std::vector<uint8_t> value = ToBytes("value");
Siddharthac0600a2a2017-10-12 22:03:02773 std::vector<uint8_t> old_value = value;
meka95ed902016-12-21 02:46:35774
Daniel Murphy388e4c9c2017-11-14 23:10:19775 set_mock_data(test_prefix_ + ToString(key), ToString(value));
meka95ed902016-12-21 02:46:35776
777 // Put with same data size should succeed.
meka95ed902016-12-21 02:46:35778 value[0] = 'X';
Siddharthac0600a2a2017-10-12 22:03:02779 EXPECT_TRUE(PutSync(key, value, old_value));
meka95ed902016-12-21 02:46:35780
781 // Reducing size should also succeed.
Siddharthac0600a2a2017-10-12 22:03:02782 old_value = value;
meka95ed902016-12-21 02:46:35783 value.clear();
Siddharthac0600a2a2017-10-12 22:03:02784 EXPECT_TRUE(PutSync(key, value, old_value));
meka95ed902016-12-21 02:46:35785
786 // Increasing size should fail.
Siddharthac0600a2a2017-10-12 22:03:02787 old_value = value;
meka95ed902016-12-21 02:46:35788 value.resize(1, 'a');
Siddharthac0600a2a2017-10-12 22:03:02789 EXPECT_FALSE(PutSync(key, value, old_value));
meka95ed902016-12-21 02:46:35790}
791
Siddharthae8191ca2017-11-07 18:24:20792TEST_P(LevelDBWrapperImplParamTest, PutAfterPurgeMemory) {
793 wrapper_impl()->SetCacheModeForTesting(GetParam());
mekdea811df2017-03-01 17:57:57794 std::vector<uint8_t> result;
Daniel Murphy388e4c9c2017-11-14 23:10:19795 const auto key = test_key2_bytes_;
796 const auto value = test_value2_bytes_;
Siddharthae8191ca2017-11-07 18:24:20797 EXPECT_TRUE(PutSync(key, value, value));
mekdea811df2017-03-01 17:57:57798 EXPECT_EQ(delegate()->map_load_count(), 1);
799
Siddharthae8191ca2017-11-07 18:24:20800 // Adding again doesn't load map again.
801 EXPECT_TRUE(PutSync(key, value, value));
mekdea811df2017-03-01 17:57:57802 EXPECT_EQ(delegate()->map_load_count(), 1);
803
804 wrapper_impl()->PurgeMemory();
805
Siddharthae8191ca2017-11-07 18:24:20806 // Now adding should still work, and load map again.
807 EXPECT_TRUE(PutSync(key, value, value));
mekdea811df2017-03-01 17:57:57808 EXPECT_EQ(delegate()->map_load_count(), 2);
809}
810
Siddharthae8191ca2017-11-07 18:24:20811TEST_P(LevelDBWrapperImplParamTest, PurgeMemoryWithPendingChanges) {
812 wrapper_impl()->SetCacheModeForTesting(GetParam());
Daniel Murphy388e4c9c2017-11-14 23:10:19813 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_));
mekdea811df2017-03-01 17:57:57816 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
Siddharthae8191ca2017-11-07 18:24:20822 EXPECT_TRUE(PutSync(key, value, value));
mekdea811df2017-03-01 17:57:57823 EXPECT_EQ(delegate()->map_load_count(), 1);
824}
825
Siddharthae8191ca2017-11-07 18:24:20826TEST_P(LevelDBWrapperImplParamTest, FixUpData) {
827 wrapper_impl()->SetCacheModeForTesting(GetParam());
Marijn Kruisselbrinke8fdb3d2017-09-26 01:33:07828 std::vector<LevelDBWrapperImpl::Change> changes;
Daniel Murphy388e4c9c2017-11-14 23:10:19829 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 Kruisselbrinke8fdb3d2017-09-26 01:33:07832 delegate()->set_mock_changes(std::move(changes));
833
Daniel Murphy3d39c5422017-11-21 03:24:07834 leveldb::mojom::DatabaseError status;
Siddharthae8191ca2017-11-07 18:24:20835 std::vector<mojom::KeyValuePtr> data;
Daniel Murphy3d39c5422017-11-21 03:24:07836 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);
Siddharthae8191ca2017-11-07 18:24:20847 ASSERT_EQ(2u, data.size());
Daniel Murphy388e4c9c2017-11-14 23:10:19848 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 Kruisselbrinke8fdb3d2017-09-26 01:33:07852
Daniel Murphy388e4c9c2017-11-14 23:10:19853 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 Kruisselbrinke8fdb3d2017-09-26 01:33:07856}
857
Siddharthae8191ca2017-11-07 18:24:20858TEST_F(LevelDBWrapperImplTest, SetOnlyKeysWithoutDatabase) {
Daniel Murphy388e4c9c2017-11-14 23:10:19859 std::vector<uint8_t> key = test_key2_bytes_;
860 std::vector<uint8_t> value = ToBytes("foo");
Siddharthae8191ca2017-11-07 18:24:20861 MockDelegate delegate;
Daniel Murphy3d39c5422017-11-21 03:24:07862 LevelDBWrapperImpl level_db_wrapper(
863 nullptr, test_prefix_, &delegate,
864 GetDefaultTestingOptions(CacheMode::KEYS_ONLY_WHEN_POSSIBLE));
Siddharthae8191ca2017-11-07 18:24:20865 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 Murphy388e4c9c2017-11-14 23:10:19868 level_db_wrapper.SetCacheModeForTesting(CacheMode::KEYS_ONLY_WHEN_POSSIBLE);
Daniel Murphy3d39c5422017-11-21 03:24:07869
870 EXPECT_FALSE(level_db_wrapper.initialized());
871 EXPECT_EQ(CacheMode::KEYS_AND_VALUES, level_db_wrapper.cache_mode());
Siddharthae8191ca2017-11-07 18:24:20872
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 Murphy3d39c5422017-11-21 03:24:07896TEST_P(LevelDBWrapperImplParamTest, CommitOnDifferentCacheModes) {
897 wrapper_impl()->SetCacheModeForTesting(GetParam());
Daniel Murphy388e4c9c2017-11-14 23:10:19898 std::vector<uint8_t> key = test_key2_bytes_;
899 std::vector<uint8_t> value = ToBytes("foo");
900 std::vector<uint8_t> value2 = ToBytes("foobar");
Siddharthae8191ca2017-11-07 18:24:20901
Daniel Murphy3d39c5422017-11-21 03:24:07902 // The initial map always has values, so a nullopt is fine for the old value.
Siddharthae8191ca2017-11-07 18:24:20903 ASSERT_TRUE(PutSync(key, value, base::nullopt));
904 ASSERT_TRUE(wrapper_impl()->commit_batch_);
Siddharthae8191ca2017-11-07 18:24:20905
Daniel Murphy3d39c5422017-11-21 03:24:07906 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 Murphy388e4c9c2017-11-14 23:10:19922 EXPECT_EQ("foo", get_mock_data(test_prefix_ + test_key2_));
Daniel Murphy3d39c5422017-11-21 03:24:07923 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());
Siddharthae8191ca2017-11-07 18:24:20927 ASSERT_TRUE(PutSync(key, value, value));
928 EXPECT_FALSE(wrapper_impl()->commit_batch_);
929 ASSERT_TRUE(PutSync(key, value2, value));
Siddharthae8191ca2017-11-07 18:24:20930 ASSERT_TRUE(wrapper_impl()->commit_batch_);
Daniel Murphy3d39c5422017-11-21 03:24:07931
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 }
Siddharthae8191ca2017-11-07 18:24:20944
945 clear_mock_data();
Daniel Murphy3d39c5422017-11-21 03:24:07946 EXPECT_TRUE(wrapper_impl()->has_changes_to_commit());
947 BlockingCommit();
Daniel Murphy388e4c9c2017-11-14 23:10:19948 EXPECT_EQ("foobar", get_mock_data(test_prefix_ + test_key2_));
Daniel Murphy3d39c5422017-11-21 03:24:07949 EXPECT_FALSE(wrapper_impl()->has_changes_to_commit());
Siddharthae8191ca2017-11-07 18:24:20950}
951
952TEST_F(LevelDBWrapperImplTest, GetAllWhenCacheOnlyKeys) {
Daniel Murphy388e4c9c2017-11-14 23:10:19953 std::vector<uint8_t> key = test_key2_bytes_;
954 std::vector<uint8_t> value = ToBytes("foo");
955 std::vector<uint8_t> value2 = ToBytes("foobar");
Siddharthae8191ca2017-11-07 18:24:20956
957 // Go to load state only keys.
958 ASSERT_TRUE(PutSync(key, value, base::nullopt));
Daniel Murphy3d39c5422017-11-21 03:24:07959 BlockingCommit();
Siddharthae8191ca2017-11-07 18:24:20960 ASSERT_TRUE(PutSync(key, value2, value));
Daniel Murphy3d39c5422017-11-21 03:24:07961 EXPECT_TRUE(wrapper_impl()->has_changes_to_commit());
Siddharthae8191ca2017-11-07 18:24:20962
Daniel Murphy3d39c5422017-11-21 03:24:07963 leveldb::mojom::DatabaseError status;
964 std::vector<mojom::KeyValuePtr> data;
Siddharthae8191ca2017-11-07 18:24:20965 bool result = false;
Daniel Murphy3d39c5422017-11-21 03:24:07966
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
Siddharthae8191ca2017-11-07 18:24:20992 EXPECT_TRUE(result);
Daniel Murphy3d39c5422017-11-21 03:24:07993 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 Murphy388e4c9c2017-11-14 23:10:191010 EXPECT_EQ("foobar", get_mock_data(test_prefix_ + test_key2_));
Siddharthae8191ca2017-11-07 18:24:201011}
1012
1013TEST_F(LevelDBWrapperImplTest, GetAllAfterSetCacheMode) {
Daniel Murphy388e4c9c2017-11-14 23:10:191014 std::vector<uint8_t> key = test_key2_bytes_;
1015 std::vector<uint8_t> value = ToBytes("foo");
1016 std::vector<uint8_t> value2 = ToBytes("foobar");
Siddharthae8191ca2017-11-07 18:24:201017
1018 // Go to load state only keys.
1019 ASSERT_TRUE(PutSync(key, value, base::nullopt));
Daniel Murphy3d39c5422017-11-21 03:24:071020 BlockingCommit();
1021 EXPECT_TRUE(wrapper_impl()->map_state_ ==
1022 LevelDBWrapperImpl::MapState::LOADED_KEYS_ONLY);
Siddharthae8191ca2017-11-07 18:24:201023 ASSERT_TRUE(PutSync(key, value2, value));
Daniel Murphy3d39c5422017-11-21 03:24:071024 EXPECT_TRUE(wrapper_impl()->has_changes_to_commit());
Siddharthae8191ca2017-11-07 18:24:201025
Daniel Murphy388e4c9c2017-11-14 23:10:191026 wrapper_impl()->SetCacheModeForTesting(CacheMode::KEYS_AND_VALUES);
Siddharthae8191ca2017-11-07 18:24:201027
Daniel Murphy3d39c5422017-11-21 03:24:071028 // 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 Murphy388e4c9c2017-11-14 23:10:191075 EXPECT_EQ("foobar", get_mock_data(test_prefix_ + test_key2_));
Daniel Murphy3d39c5422017-11-21 03:24:071076
1077 ASSERT_TRUE(wrapper_impl()->has_changes_to_commit());
1078 BlockingCommit();
1079
1080 EXPECT_FALSE(has_mock_data(test_prefix_ + test_key2_));
Siddharthae8191ca2017-11-07 18:24:201081}
1082
1083TEST_F(LevelDBWrapperImplTest, SetCacheModeConsistent) {
Daniel Murphy388e4c9c2017-11-14 23:10:191084 std::vector<uint8_t> key = test_key2_bytes_;
1085 std::vector<uint8_t> value = ToBytes("foo");
1086 std::vector<uint8_t> value2 = ToBytes("foobar");
Siddharthae8191ca2017-11-07 18:24:201087
Daniel Murphy3d39c5422017-11-21 03:24:071088 EXPECT_FALSE(wrapper_impl()->IsMapLoaded());
1089 EXPECT_TRUE(wrapper_impl()->cache_mode() ==
1090 CacheMode::KEYS_ONLY_WHEN_POSSIBLE);
Siddharthae8191ca2017-11-07 18:24:201091
Daniel Murphy3d39c5422017-11-21 03:24:071092 // Clear the database before the wrapper loads data.
Siddharthae8191ca2017-11-07 18:24:201093 clear_mock_data();
Daniel Murphy3d39c5422017-11-21 03:24:071094
1095 EXPECT_TRUE(PutSync(key, value, base::nullopt));
1096 EXPECT_TRUE(wrapper_impl()->has_changes_to_commit());
1097 BlockingCommit();
1098
Siddharthae8191ca2017-11-07 18:24:201099 EXPECT_TRUE(PutSync(key, value2, value));
Daniel Murphy3d39c5422017-11-21 03:24:071100 EXPECT_TRUE(wrapper_impl()->has_changes_to_commit());
Siddharthae8191ca2017-11-07 18:24:201101
1102 // Setting cache mode does not reload the cache till it is required.
Daniel Murphy388e4c9c2017-11-14 23:10:191103 wrapper_impl()->SetCacheModeForTesting(CacheMode::KEYS_AND_VALUES);
Daniel Murphy3d39c5422017-11-21 03:24:071104 EXPECT_EQ(LevelDBWrapperImpl::MapState::LOADED_KEYS_ONLY,
1105 wrapper_impl()->map_state_);
Siddharthae8191ca2017-11-07 18:24:201106
Daniel Murphy3d39c5422017-11-21 03:24:071107 // Put operation should change the mode.
Siddharthae8191ca2017-11-07 18:24:201108 EXPECT_TRUE(PutSync(key, value, value2));
Daniel Murphy3d39c5422017-11-21 03:24:071109 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_);
Siddharthae8191ca2017-11-07 18:24:201117
Daniel Murphy3d39c5422017-11-21 03:24:071118 BlockingCommit();
Siddharthae8191ca2017-11-07 18:24:201119
Daniel Murphy3d39c5422017-11-21 03:24:071120 // Test that the map will unload correctly
Siddharthae8191ca2017-11-07 18:24:201121 EXPECT_TRUE(PutSync(key, value2, value));
Daniel Murphy3d39c5422017-11-21 03:24:071122 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_);
Siddharthae8191ca2017-11-07 18:24:201137}
1138
1139TEST_F(LevelDBWrapperImplTest, SendOldValueObservations) {
1140 should_record_send_old_value_observations(true);
Daniel Murphy388e4c9c2017-11-14 23:10:191141 wrapper_impl()->SetCacheModeForTesting(CacheMode::KEYS_AND_VALUES);
Siddharthae8191ca2017-11-07 18:24:201142 // Flush tasks on mojo thread to observe callback.
Daniel Murphy388e4c9c2017-11-14 23:10:191143 EXPECT_TRUE(DeleteSync(ToBytes("doesn't exist"), base::nullopt));
1144 wrapper_impl()->SetCacheModeForTesting(CacheMode::KEYS_ONLY_WHEN_POSSIBLE);
Siddharthae8191ca2017-11-07 18:24:201145 // Flush tasks on mojo thread to observe callback.
Daniel Murphy388e4c9c2017-11-14 23:10:191146 EXPECT_TRUE(DeleteSync(ToBytes("doesn't exist"), base::nullopt));
Siddharthae8191ca2017-11-07 18:24:201147
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 Murphy3d39c5422017-11-21 03:24:071155TEST_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
1240TEST_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
1261namespace {
1262std::string GetNewPrefix(int* i) {
1263 std::string prefix = "prefix-" + base::Int64ToString(*i) + "-";
1264 (*i)++;
1265 return prefix;
1266}
1267
1268struct FuzzState {
1269 base::Optional<std::vector<uint8_t>> val1;
1270 base::Optional<std::vector<uint8_t>> val2;
1271};
1272} // namespace
1273
1274TEST_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
mekd51c84c2016-12-20 18:27:171413} // namespace content