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 |