Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2017 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 "components/download/internal/model_impl.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/guid.h" | |
| 9 #include "base/test/test_mock_time_task_runner.h" | |
| 10 #include "base/threading/thread_task_runner_handle.h" | |
| 11 #include "components/download/internal/entry.h" | |
| 12 #include "components/download/internal/noop_store.h" | |
| 13 #include "components/download/internal/test_support/mock_model_client.h" | |
| 14 #include "components/download/internal/test_support/mock_store.h" | |
| 15 #include "testing/gmock/include/gmock/gmock.h" | |
| 16 #include "testing/gtest/include/gtest/gtest.h" | |
| 17 | |
| 18 using testing::Return; | |
| 19 using testing::_; | |
| 20 | |
| 21 namespace download { | |
| 22 namespace { | |
| 23 | |
| 24 class BadStore : public Store { | |
| 25 public: | |
| 26 BadStore() = default; | |
| 27 ~BadStore() override = default; | |
| 28 | |
| 29 // Store implementation. | |
| 30 MOCK_METHOD0(IsInitialized, bool()); | |
| 31 void Initialize(const InitCallback& callback) override { | |
| 32 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 33 FROM_HERE, base::Bind(callback, false, nullptr)); | |
| 34 } | |
| 35 | |
| 36 void Destroy(const StoreCallback& callback) override { | |
| 37 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, | |
| 38 base::Bind(callback, false)); | |
| 39 } | |
| 40 | |
| 41 void Update(const Entry& entry, const StoreCallback& callback) override { | |
| 42 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, | |
| 43 base::Bind(callback, false)); | |
| 44 } | |
| 45 | |
| 46 void Remove(const std::string& guid, const StoreCallback& callback) override { | |
| 47 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, | |
| 48 base::Bind(callback, false)); | |
| 49 } | |
| 50 }; | |
| 51 | |
| 52 struct CompareByGuid { | |
| 53 bool operator()(const Entry* a, const Entry* b) const { | |
| 54 return a->guid < b->guid; | |
| 55 } | |
| 56 }; | |
| 57 | |
| 58 template <typename T> | |
| 59 bool VectorContentsEq(const std::vector<T>& list1, | |
| 60 const std::vector<T>& list2) { | |
| 61 if (list1.size() != list2.size()) | |
| 62 return false; | |
| 63 | |
| 64 std::map<T, int, CompareByGuid> occurance_counts; | |
| 65 for (auto it = list1.begin(); it != list1.end(); it++) | |
| 66 occurance_counts[*it]++; | |
| 67 | |
| 68 for (auto it = list2.begin(); it != list2.end(); it++) | |
| 69 occurance_counts[*it]--; | |
| 70 | |
| 71 for (auto it = occurance_counts.begin(); it != occurance_counts.end(); it++) { | |
| 72 if (it->second != 0) | |
| 73 return false; | |
| 74 } | |
| 75 | |
| 76 return true; | |
|
Peter Beverloo
2017/05/10 12:44:45
I think you could *significantly* simplify this (a
David Trainor- moved to gerrit
2017/05/15 15:59:51
O_o! Yeah way better :).
| |
| 77 } | |
| 78 | |
| 79 Entry BuildEntry(DownloadClient client, const std::string& guid) { | |
| 80 Entry entry; | |
| 81 entry.client = client; | |
| 82 entry.guid = guid; | |
| 83 | |
| 84 return entry; | |
| 85 } | |
| 86 | |
| 87 bool CompareEntryBasics(const Entry& expected, const Entry* const actual) { | |
| 88 return actual != nullptr && expected.client == actual->client && | |
| 89 expected.guid == actual->guid && expected.state == actual->state; | |
| 90 } | |
| 91 | |
| 92 class ModelImplStoreTestBase : public testing::Test { | |
| 93 public: | |
| 94 ModelImplStoreTestBase(Store* store) | |
| 95 : task_runner_(new base::TestMockTimeTaskRunner), | |
|
Peter Beverloo
2017/05/10 12:44:45
qq: would TestSimpleTaskRunner suffice? why is tim
David Trainor- moved to gerrit
2017/05/15 15:59:51
Good call. Done.
| |
| 96 handle_(task_runner_), | |
| 97 store_(store), | |
| 98 model_(base::MakeUnique<ModelImpl>(&client_, | |
| 99 base::WrapUnique<Store>(store))) {} | |
| 100 | |
| 101 ~ModelImplStoreTestBase() override = default; | |
| 102 | |
| 103 protected: | |
| 104 scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; | |
| 105 base::ThreadTaskRunnerHandle handle_; | |
| 106 MockModelClient client_; | |
| 107 Store* store_; | |
| 108 std::unique_ptr<ModelImpl> model_; | |
| 109 }; | |
| 110 | |
| 111 class ModelImplNoopStoreTest : public ModelImplStoreTestBase { | |
| 112 public: | |
| 113 ModelImplNoopStoreTest() : ModelImplStoreTestBase(new NoopStore) {} | |
| 114 }; | |
| 115 | |
| 116 class ModelImplMockStoreTest : public ModelImplStoreTestBase { | |
| 117 public: | |
| 118 ModelImplMockStoreTest() | |
| 119 : ModelImplStoreTestBase(new MockStore), | |
| 120 mocked_store_(static_cast<MockStore*>(store_)) {} | |
| 121 | |
| 122 protected: | |
| 123 MockStore* mocked_store_; | |
| 124 }; | |
| 125 | |
| 126 class ModelImplBadStoreTest : public ModelImplStoreTestBase { | |
| 127 public: | |
| 128 ModelImplBadStoreTest() | |
| 129 : ModelImplStoreTestBase(new BadStore), | |
| 130 mocked_store_(static_cast<BadStore*>(store_)) {} | |
| 131 | |
| 132 protected: | |
| 133 BadStore* mocked_store_; | |
| 134 }; | |
| 135 | |
| 136 TEST_F(ModelImplNoopStoreTest, Lifecycle) { | |
| 137 EXPECT_CALL(client_, OnInitialized(true)).Times(1); | |
| 138 model_->Initialize(); | |
| 139 task_runner_->RunUntilIdle(); | |
| 140 | |
| 141 EXPECT_CALL(client_, OnDestroyed(true)).Times(1); | |
| 142 model_->Destroy(); | |
| 143 task_runner_->RunUntilIdle(); | |
| 144 } | |
| 145 | |
| 146 TEST_F(ModelImplNoopStoreTest, Add) { | |
| 147 EXPECT_CALL(client_, OnInitialized(true)).Times(1); | |
| 148 model_->Initialize(); | |
| 149 task_runner_->RunUntilIdle(); | |
| 150 | |
| 151 std::string guid1 = base::GenerateGUID(); | |
| 152 std::string guid2 = base::GenerateGUID(); | |
| 153 | |
| 154 DownloadClient client1 = DownloadClient::TEST_1; | |
| 155 DownloadClient client2 = DownloadClient::TEST_2; | |
| 156 | |
| 157 Entry entry1 = BuildEntry(client1, guid1); | |
| 158 Entry entry2 = BuildEntry(client2, guid2); | |
| 159 | |
| 160 EXPECT_CALL(client_, OnItemAdded(true, client1, guid1)).Times(1); | |
| 161 EXPECT_CALL(client_, OnItemAdded(true, client2, guid2)).Times(1); | |
| 162 | |
| 163 EXPECT_EQ(nullptr, model_->Get(guid1)); | |
| 164 EXPECT_EQ(nullptr, model_->Get(guid2)); | |
| 165 | |
| 166 model_->Add(entry1); | |
| 167 model_->Add(entry2); | |
| 168 | |
| 169 // Validate that the new item is available immediately after adding. | |
| 170 EXPECT_TRUE(CompareEntryBasics(entry1, model_->Get(guid1))); | |
| 171 EXPECT_TRUE(CompareEntryBasics(entry2, model_->Get(guid2))); | |
| 172 | |
| 173 task_runner_->RunUntilIdle(); | |
| 174 } | |
| 175 | |
| 176 TEST_F(ModelImplNoopStoreTest, Update) { | |
| 177 EXPECT_CALL(client_, OnInitialized(true)).Times(1); | |
| 178 model_->Initialize(); | |
| 179 task_runner_->RunUntilIdle(); | |
| 180 | |
| 181 std::string guid = base::GenerateGUID(); | |
| 182 DownloadClient client = DownloadClient::TEST_1; | |
| 183 | |
| 184 Entry entry1 = BuildEntry(client, guid); | |
| 185 Entry entry2(entry1); | |
| 186 | |
| 187 entry1.state = Entry::State::NEW; | |
| 188 entry2.state = Entry::State::ACTIVE; | |
| 189 | |
| 190 EXPECT_CALL(client_, OnItemAdded(true, client, guid)).Times(1); | |
| 191 | |
| 192 EXPECT_EQ(nullptr, model_->Get(guid)); | |
| 193 | |
| 194 model_->Add(entry1); | |
| 195 task_runner_->RunUntilIdle(); | |
| 196 | |
| 197 EXPECT_TRUE(CompareEntryBasics(entry1, model_->Get(guid))); | |
| 198 | |
| 199 model_->Update(entry2); | |
| 200 | |
| 201 // Validate that the updated item is available immediately after updating. | |
| 202 EXPECT_TRUE(CompareEntryBasics(entry2, model_->Get(guid))); | |
| 203 | |
| 204 task_runner_->RunUntilIdle(); | |
| 205 } | |
| 206 | |
| 207 TEST_F(ModelImplNoopStoreTest, Remove) { | |
| 208 EXPECT_CALL(client_, OnInitialized(true)).Times(1); | |
| 209 model_->Initialize(); | |
| 210 task_runner_->RunUntilIdle(); | |
| 211 | |
| 212 std::string guid = base::GenerateGUID(); | |
| 213 | |
| 214 DownloadClient client = DownloadClient::TEST_1; | |
| 215 | |
| 216 Entry entry = BuildEntry(client, guid); | |
| 217 | |
| 218 EXPECT_CALL(client_, OnItemAdded(true, client, guid)).Times(1); | |
| 219 | |
| 220 EXPECT_EQ(nullptr, model_->Get(guid)); | |
| 221 | |
| 222 model_->Add(entry); | |
| 223 task_runner_->RunUntilIdle(); | |
| 224 | |
| 225 EXPECT_TRUE(CompareEntryBasics(entry, model_->Get(guid))); | |
| 226 | |
| 227 model_->Remove(guid); | |
| 228 | |
| 229 // Validate that the removed item is unavailable immediately after updating. | |
| 230 EXPECT_EQ(nullptr, model_->Get(guid)); | |
| 231 | |
| 232 task_runner_->RunUntilIdle(); | |
| 233 } | |
| 234 | |
| 235 TEST_F(ModelImplNoopStoreTest, Get) { | |
| 236 model_->Initialize(); | |
| 237 task_runner_->RunUntilIdle(); | |
| 238 | |
| 239 std::string guid = base::GenerateGUID(); | |
| 240 Entry entry = BuildEntry(DownloadClient::TEST_1, guid); | |
| 241 | |
| 242 model_->Add(entry); | |
| 243 task_runner_->RunUntilIdle(); | |
| 244 | |
| 245 EXPECT_TRUE(CompareEntryBasics(entry, model_->Get(guid))); | |
| 246 } | |
| 247 | |
| 248 TEST_F(ModelImplNoopStoreTest, PeekEntries) { | |
| 249 model_->Initialize(); | |
| 250 task_runner_->RunUntilIdle(); | |
| 251 | |
| 252 std::string guid1 = base::GenerateGUID(); | |
| 253 std::string guid2 = base::GenerateGUID(); | |
| 254 std::string guid3 = base::GenerateGUID(); | |
| 255 | |
| 256 Entry entry1 = BuildEntry(DownloadClient::TEST_1, guid1); | |
| 257 Entry entry2 = BuildEntry(DownloadClient::TEST_2, guid2); | |
| 258 Entry entry3 = BuildEntry(DownloadClient::TEST_3, guid3); | |
| 259 | |
| 260 Model::EntryList entries = {&entry1, &entry2, &entry3}; | |
| 261 | |
| 262 model_->Add(entry1); | |
| 263 model_->Add(entry2); | |
| 264 model_->Add(entry3); | |
| 265 task_runner_->RunUntilIdle(); | |
| 266 | |
| 267 EXPECT_TRUE(VectorContentsEq(entries, model_->PeekEntries())); | |
| 268 } | |
| 269 | |
| 270 TEST_F(ModelImplMockStoreTest, TestStoreCalls) { | |
| 271 { | |
| 272 EXPECT_CALL(*mocked_store_, IsInitialized()).WillRepeatedly(Return(false)); | |
| 273 EXPECT_CALL(*mocked_store_, Initialize(_)).Times(1); | |
| 274 model_->Initialize(); | |
| 275 } | |
| 276 | |
| 277 EXPECT_CALL(*mocked_store_, IsInitialized()).WillRepeatedly(Return(true)); | |
| 278 | |
| 279 std::string guid = base::GenerateGUID(); | |
| 280 Entry entry = BuildEntry(DownloadClient::TEST_1, guid); | |
| 281 | |
| 282 EXPECT_CALL(*mocked_store_, Update(_, _)).Times(2); | |
| 283 EXPECT_CALL(*mocked_store_, Remove(guid, _)).Times(1); | |
| 284 EXPECT_CALL(*mocked_store_, Destroy(_)).Times(1); | |
| 285 | |
| 286 model_->Add(entry); | |
| 287 model_->Update(entry); | |
| 288 model_->Remove(guid); | |
| 289 model_->Destroy(); | |
| 290 } | |
| 291 | |
| 292 TEST_F(ModelImplBadStoreTest, ModelUpdatesFailed) { | |
| 293 { | |
| 294 EXPECT_CALL(*mocked_store_, IsInitialized()).WillRepeatedly(Return(false)); | |
| 295 EXPECT_CALL(client_, OnInitialized(false)).Times(1); | |
| 296 model_->Initialize(); | |
| 297 } | |
| 298 | |
| 299 EXPECT_CALL(*mocked_store_, IsInitialized()).WillRepeatedly(Return(true)); | |
| 300 | |
| 301 std::string guid = base::GenerateGUID(); | |
| 302 DownloadClient client = DownloadClient::TEST_1; | |
| 303 Entry entry = BuildEntry(client, guid); | |
| 304 | |
| 305 EXPECT_CALL(client_, OnItemAdded(false, client, guid)).Times(1); | |
| 306 EXPECT_CALL(client_, OnStoreUpdateFailed(client, guid)).Times(2); | |
| 307 EXPECT_CALL(client_, OnDestroyed(false)); | |
| 308 | |
| 309 model_->Add(entry); | |
| 310 model_->Update(entry); | |
| 311 model_->Remove(guid); | |
| 312 model_->Destroy(); | |
| 313 | |
| 314 task_runner_->RunUntilIdle(); | |
| 315 } | |
| 316 | |
| 317 } // namespace | |
| 318 } // namespace download | |
| OLD | NEW |