Check USB device path access when prompting users to select a device.
[chromium-blink-merge.git] / chrome / browser / safe_browsing / incident_reporting / download_metadata_manager_unittest.cc
blobfe60a4f3ffd5c990c8b51e3c19b29612b5f015b4
1 // Copyright 2014 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.
5 #include "chrome/browser/safe_browsing/incident_reporting/download_metadata_manager.h"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "chrome/common/safe_browsing/csd.pb.h"
17 #include "chrome/test/base/testing_profile.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/download_manager.h"
20 #include "content/public/test/mock_download_item.h"
21 #include "content/public/test/mock_download_manager.h"
22 #include "content/public/test/test_browser_thread_bundle.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
26 using ::testing::AllOf;
27 using ::testing::Eq;
28 using ::testing::IsNull;
29 using ::testing::Ne;
30 using ::testing::NiceMock;
31 using ::testing::NotNull;
32 using ::testing::ResultOf;
33 using ::testing::Return;
34 using ::testing::SaveArg;
35 using ::testing::StrEq;
37 namespace safe_browsing {
39 namespace {
41 const uint32_t kTestDownloadId = 47;
42 const uint32_t kOtherDownloadId = 48;
43 const uint32_t kCrazyDowloadId = 655;
44 const int64 kTestDownloadTimeMsec = 84;
45 const char kTestUrl[] = "http://test.test/foo";
46 const uint64_t kTestDownloadLength = 1000;
47 const double kTestDownloadEndTimeMs = 1413514824057;
49 // A utility class suitable for mocking that exposes a
50 // GetDownloadDetailsCallback.
51 class DownloadDetailsGetter {
52 public:
53 virtual ~DownloadDetailsGetter() {}
54 virtual void OnDownloadDetails(
55 ClientIncidentReport_DownloadDetails* details) = 0;
56 DownloadMetadataManager::GetDownloadDetailsCallback GetCallback() {
57 return base::Bind(&DownloadDetailsGetter::DownloadDetailsCallback,
58 base::Unretained(this));
61 private:
62 void DownloadDetailsCallback(
63 scoped_ptr<ClientIncidentReport_DownloadDetails> details) {
64 OnDownloadDetails(details.get());
68 // A mock DownloadDetailsGetter.
69 class MockDownloadDetailsGetter : public DownloadDetailsGetter {
70 public:
71 MOCK_METHOD1(OnDownloadDetails, void(ClientIncidentReport_DownloadDetails*));
74 // A mock DownloadMetadataManager that can be used to map a BrowserContext to
75 // a DownloadManager.
76 class MockDownloadMetadataManager : public DownloadMetadataManager {
77 public:
78 MockDownloadMetadataManager(
79 const scoped_refptr<base::SequencedTaskRunner>& task_runner)
80 : DownloadMetadataManager(task_runner) {}
82 MOCK_METHOD1(GetDownloadManagerForBrowserContext,
83 content::DownloadManager*(content::BrowserContext*));
86 // A helper function that returns the download URL from a DownloadDetails.
87 const std::string& GetDetailsDownloadUrl(
88 const ClientIncidentReport_DownloadDetails* details) {
89 return details->download().url();
92 // A helper function that returns the open time from a DownloadDetails.
93 int64_t GetDetailsOpenTime(
94 const ClientIncidentReport_DownloadDetails* details) {
95 return details->open_time_msec();
98 } // namespace
100 // The basis upon which unit tests of the DownloadMetadataManager are built.
101 class DownloadMetadataManagerTestBase : public ::testing::Test {
102 protected:
103 // Sets up a DownloadMetadataManager that will run tasks on the main test
104 // thread.
105 DownloadMetadataManagerTestBase()
106 : manager_(scoped_refptr<base::SequencedTaskRunner>(
107 base::ThreadTaskRunnerHandle::Get())),
108 download_manager_(),
109 dm_observer_() {}
111 // Returns the path to the test profile's DownloadMetadata file.
112 base::FilePath GetMetadataPath() const {
113 return profile_.GetPath().Append(FILE_PATH_LITERAL("DownloadMetadata"));
116 // Returns a new ClientDownloadRequest for the given download URL.
117 static scoped_ptr<ClientDownloadRequest> MakeTestRequest(const char* url) {
118 scoped_ptr<ClientDownloadRequest> request(new ClientDownloadRequest());
119 request->set_url(url);
120 request->mutable_digests();
121 request->set_length(kTestDownloadLength);
122 return request.Pass();
125 // Returns a new DownloadMetdata for the given download id.
126 static scoped_ptr<DownloadMetadata> GetTestMetadata(uint32_t download_id) {
127 scoped_ptr<DownloadMetadata> metadata(new DownloadMetadata());
128 metadata->set_download_id(download_id);
129 ClientIncidentReport_DownloadDetails* details =
130 metadata->mutable_download();
131 details->set_download_time_msec(kTestDownloadTimeMsec);
132 details->set_allocated_download(MakeTestRequest(kTestUrl).release());
133 return metadata.Pass();
136 // Writes a test DownloadMetadata file for the given download id to the
137 // test profile directory.
138 void WriteTestMetadataFileForItem(uint32_t download_id) {
139 std::string data;
140 ASSERT_TRUE(GetTestMetadata(download_id)->SerializeToString(&data));
141 ASSERT_TRUE(base::WriteFile(GetMetadataPath(), data.data(), data.size()));
144 // Writes a test DownloadMetadata file for kTestDownloadId to the test profile
145 // directory.
146 void WriteTestMetadataFile() {
147 WriteTestMetadataFileForItem(kTestDownloadId);
150 // Returns the DownloadMetadata read from the test profile's directory.
151 scoped_ptr<DownloadMetadata> ReadTestMetadataFile() const {
152 std::string data;
153 if (!base::ReadFileToString(GetMetadataPath(), &data))
154 return scoped_ptr<DownloadMetadata>();
155 scoped_ptr<DownloadMetadata> result(new DownloadMetadata);
156 EXPECT_TRUE(result->ParseFromString(data));
157 return result.Pass();
160 // Runs all tasks posted to the test thread's message loop.
161 void RunAllTasks() { base::MessageLoop::current()->RunUntilIdle(); }
163 // Adds a DownloadManager for the test profile. The DownloadMetadataManager's
164 // observer is stashed for later use. Only call once per call to
165 // ShutdownDownloadManager.
166 void AddDownloadManager() {
167 ASSERT_EQ(nullptr, dm_observer_);
168 // Shove the manager into the browser context.
169 ON_CALL(download_manager_, GetBrowserContext())
170 .WillByDefault(Return(&profile_));
171 ON_CALL(manager_, GetDownloadManagerForBrowserContext(Eq(&profile_)))
172 .WillByDefault(Return(&download_manager_));
173 // Capture the metadata manager's observer on the download manager.
174 EXPECT_CALL(download_manager_, AddObserver(&manager_))
175 .WillOnce(SaveArg<0>(&dm_observer_));
176 manager_.AddDownloadManager(&download_manager_);
179 // Shuts down the DownloadManager. Safe to call any number of times.
180 void ShutdownDownloadManager() {
181 if (dm_observer_) {
182 dm_observer_->ManagerGoingDown(&download_manager_);
183 // Note: these calls may result in "Uninteresting mock function call"
184 // warnings as a result of MockDownloadItem invoking observers in its
185 // dtor. This happens after the NiceMock wrapper has removed its niceness
186 // hook. These can safely be ignored, as they are entirely expected. The
187 // values specified by ON_CALL invocations in AddDownloadItems are
188 // returned as desired.
189 other_item_.reset();
190 test_item_.reset();
191 dm_observer_ = nullptr;
195 // Adds two test DownloadItems to the DownloadManager.
196 void AddDownloadItems() {
197 ASSERT_NE(nullptr, dm_observer_);
198 // Add the item under test.
199 test_item_.reset(new NiceMock<content::MockDownloadItem>);
200 ON_CALL(*test_item_, GetId())
201 .WillByDefault(Return(kTestDownloadId));
202 ON_CALL(*test_item_, GetBrowserContext())
203 .WillByDefault(Return(&profile_));
204 ON_CALL(*test_item_, GetEndTime())
205 .WillByDefault(Return(base::Time::FromJsTime(kTestDownloadEndTimeMs)));
206 dm_observer_->OnDownloadCreated(&download_manager_, test_item_.get());
208 // Add another item.
209 other_item_.reset(new NiceMock<content::MockDownloadItem>);
210 ON_CALL(*other_item_, GetId())
211 .WillByDefault(Return(kOtherDownloadId));
212 ON_CALL(*other_item_, GetBrowserContext())
213 .WillByDefault(Return(&profile_));
214 ON_CALL(*test_item_, GetEndTime())
215 .WillByDefault(Return(base::Time::FromJsTime(kTestDownloadEndTimeMs)));
216 dm_observer_->OnDownloadCreated(&download_manager_, other_item_.get());
219 content::TestBrowserThreadBundle thread_bundle_;
220 NiceMock<MockDownloadMetadataManager> manager_;
221 TestingProfile profile_;
222 NiceMock<content::MockDownloadManager> download_manager_;
223 scoped_ptr<content::MockDownloadItem> test_item_;
224 scoped_ptr<content::MockDownloadItem> other_item_;
225 content::DownloadManager::Observer* dm_observer_;
228 // A parameterized test that exercises GetDownloadDetails. The parameters
229 // dictate the exact state of affairs leading up to the call as follows:
230 // 0: if "present", the profile has a pre-existing DownloadMetadata file.
231 // 1: if "managed", the profile's DownloadManager has been created.
232 // 2: the state of the DownloadItem prior to the call:
233 // "not_created": the DownloadItem has not been created.
234 // "created": the DownloadItem has been created.
235 // "opened": the DownloadItem has been opened.
236 // "removed": the DownloadItem has been removed.
237 // 3: if "loaded", the task to load the DownloadMetadata file is allowed to
238 // complete.
239 // 4: if "early_shutdown", the DownloadManager is shut down before the callback
240 // is allowed to complete.
241 class GetDetailsTest
242 : public DownloadMetadataManagerTestBase,
243 public ::testing::WithParamInterface<testing::tuple<const char*,
244 const char*,
245 const char*,
246 const char*,
247 const char*>> {
248 protected:
249 enum DownloadItemAction {
250 NOT_CREATED,
251 CREATED,
252 OPENED,
253 REMOVED,
255 GetDetailsTest()
256 : metadata_file_present_(),
257 manager_added_(),
258 item_action_(NOT_CREATED),
259 details_loaded_(),
260 early_shutdown_() {}
262 void SetUp() override {
263 DownloadMetadataManagerTestBase::SetUp();
264 metadata_file_present_ =
265 (std::string(testing::get<0>(GetParam())) == "present");
266 manager_added_ = (std::string(testing::get<1>(GetParam())) == "managed");
267 const std::string item_action(testing::get<2>(GetParam()));
268 item_action_ = (item_action == "not_created" ? NOT_CREATED :
269 (item_action == "created" ? CREATED :
270 (item_action == "opened" ? OPENED : REMOVED)));
271 details_loaded_ = (std::string(testing::get<3>(GetParam())) == "loaded");
272 early_shutdown_ =
273 (std::string(testing::get<4>(GetParam())) == "early_shutdown");
275 // Fixup combinations that don't make sense.
276 if (!manager_added_)
277 item_action_ = NOT_CREATED;
280 bool metadata_file_present_;
281 bool manager_added_;
282 DownloadItemAction item_action_;
283 bool details_loaded_;
284 bool early_shutdown_;
287 // Tests that DownloadMetadataManager::GetDownloadDetails works for all
288 // combinations of states.
289 TEST_P(GetDetailsTest, GetDownloadDetails) {
290 // Optionally put a metadata file in the profile directory.
291 if (metadata_file_present_)
292 WriteTestMetadataFile();
294 // Optionally add a download manager for the profile.
295 if (manager_added_)
296 AddDownloadManager();
298 // Optionally create download items and perform actions on the one under test.
299 if (item_action_ != NOT_CREATED)
300 AddDownloadItems();
301 if (item_action_ == OPENED)
302 test_item_->NotifyObserversDownloadOpened();
303 else if (item_action_ == REMOVED)
304 test_item_->NotifyObserversDownloadRemoved();
306 // Optionally allow the task to read the file to complete.
307 if (details_loaded_)
308 RunAllTasks();
310 // In http://crbug.com/433928, open after removal during load caused a crash.
311 if (item_action_ == REMOVED)
312 test_item_->NotifyObserversDownloadOpened();
314 MockDownloadDetailsGetter details_getter;
315 if (metadata_file_present_ && item_action_ != REMOVED) {
316 // The file is present, so expect that the callback is invoked with the
317 // details of the test download data written by WriteTestMetadataFile.
318 if (item_action_ == OPENED) {
319 EXPECT_CALL(details_getter,
320 OnDownloadDetails(
321 AllOf(ResultOf(GetDetailsDownloadUrl, StrEq(kTestUrl)),
322 ResultOf(GetDetailsOpenTime, Ne(0)))));
323 } else {
324 EXPECT_CALL(details_getter,
325 OnDownloadDetails(
326 AllOf(ResultOf(GetDetailsDownloadUrl, StrEq(kTestUrl)),
327 ResultOf(GetDetailsOpenTime, Eq(0)))));
329 } else {
330 // No file on disk, so expect that the callback is invoked with null.
331 EXPECT_CALL(details_getter, OnDownloadDetails(IsNull()));
334 // Fire in the hole!
335 manager_.GetDownloadDetails(&profile_, details_getter.GetCallback());
337 // Shutdown the download manager, if relevant.
338 if (early_shutdown_)
339 ShutdownDownloadManager();
341 // Allow the read task and the response callback to run.
342 RunAllTasks();
344 // Shutdown the download manager, if relevant.
345 ShutdownDownloadManager();
348 INSTANTIATE_TEST_CASE_P(
349 DownloadMetadataManager,
350 GetDetailsTest,
351 testing::Combine(
352 testing::Values("absent", "present"),
353 testing::Values("not_managed", "managed"),
354 testing::Values("not_created", "created", "opened", "removed"),
355 testing::Values("waiting", "loaded"),
356 testing::Values("normal_shutdown", "early_shutdown")));
358 // A parameterized test that exercises SetRequest. The parameters dictate the
359 // exact state of affairs leading up to the call as follows:
360 // 0: the state of the DownloadMetadata file for the test profile:
361 // "absent": no file is present.
362 // "this": the file corresponds to the item being updated.
363 // "other": the file correponds to a different item.
364 // "unknown": the file corresponds to an item that has not been created.
365 // 1: if "pending", an operation is applied to the item being updated prior to
366 // the call.
367 // 2: if "pending", an operation is applied to a different item prior to the
368 // call.
369 // 3: if "loaded", the task to load the DownloadMetadata file is allowed to
370 // complete.
371 // 4: if "set", the call to SetRequest contains a new request; otherwise it
372 // does not, leading to removal of metadata.
373 class SetRequestTest
374 : public DownloadMetadataManagerTestBase,
375 public ::testing::WithParamInterface<testing::tuple<const char*,
376 const char*,
377 const char*,
378 const char*,
379 const char*>> {
380 protected:
381 enum MetadataFilePresent {
382 ABSENT,
383 PRESENT_FOR_THIS_ITEM,
384 PRESENT_FOR_OTHER_ITEM,
385 PRESENT_FOR_UNKNOWN_ITEM,
387 SetRequestTest()
388 : metadata_file_present_(ABSENT),
389 same_ops_(),
390 other_ops_(),
391 details_loaded_(),
392 set_request_() {}
394 void SetUp() override {
395 DownloadMetadataManagerTestBase::SetUp();
396 const std::string present(testing::get<0>(GetParam()));
397 metadata_file_present_ = (present == "absent" ? ABSENT :
398 (present == "this" ? PRESENT_FOR_THIS_ITEM :
399 (present == "other" ? PRESENT_FOR_OTHER_ITEM :
400 PRESENT_FOR_UNKNOWN_ITEM)));
401 same_ops_ = (std::string(testing::get<1>(GetParam())) == "pending");
402 other_ops_ = (std::string(testing::get<2>(GetParam())) == "pending");
403 details_loaded_ = (std::string(testing::get<3>(GetParam())) == "loaded");
404 set_request_ = (std::string(testing::get<4>(GetParam())) == "set");
407 MetadataFilePresent metadata_file_present_;
408 bool same_ops_;
409 bool other_ops_;
410 bool details_loaded_;
411 bool set_request_;
414 // Tests that DownloadMetadataManager::SetRequest works for all combinations of
415 // states.
416 TEST_P(SetRequestTest, SetRequest) {
417 // Optionally put a metadata file in the profile directory.
418 switch (metadata_file_present_) {
419 case ABSENT:
420 break;
421 case PRESENT_FOR_THIS_ITEM:
422 WriteTestMetadataFile();
423 break;
424 case PRESENT_FOR_OTHER_ITEM:
425 WriteTestMetadataFileForItem(kOtherDownloadId);
426 break;
427 case PRESENT_FOR_UNKNOWN_ITEM:
428 WriteTestMetadataFileForItem(kCrazyDowloadId);
429 break;
432 AddDownloadManager();
433 AddDownloadItems();
435 // Optionally allow the task to read the file to complete.
436 if (details_loaded_) {
437 RunAllTasks();
438 } else {
439 // Optionally add pending operations if the load is outstanding.
440 if (same_ops_)
441 test_item_->NotifyObserversDownloadOpened();
442 if (other_ops_)
443 other_item_->NotifyObserversDownloadOpened();
446 static const char kNewUrl[] = "http://blorf";
447 scoped_ptr<ClientDownloadRequest> request;
448 if (set_request_)
449 request = MakeTestRequest(kNewUrl).Pass();
450 else
451 request.reset();
452 manager_.SetRequest(test_item_.get(), request.get());
454 // Allow the write or remove task to run.
455 RunAllTasks();
457 MockDownloadDetailsGetter details_getter;
458 if (set_request_) {
459 // Expect that the callback is invoked with details for this item.
460 EXPECT_CALL(
461 details_getter,
462 OnDownloadDetails(ResultOf(GetDetailsDownloadUrl, StrEq(kNewUrl))));
463 } else {
464 // Expect that the callback is invoked with null to clear stale metadata.
465 EXPECT_CALL(details_getter, OnDownloadDetails(IsNull()));
467 manager_.GetDownloadDetails(&profile_, details_getter.GetCallback());
469 // In http://crbug.com/433928, open after SetRequest(nullpr) caused a crash.
470 test_item_->NotifyObserversDownloadOpened();
472 ShutdownDownloadManager();
474 scoped_ptr<DownloadMetadata> metadata(ReadTestMetadataFile());
475 if (set_request_) {
476 // Expect that the file contains metadata for the download.
477 ASSERT_TRUE(metadata);
478 EXPECT_EQ(kTestDownloadId, metadata->download_id());
479 EXPECT_STREQ(kNewUrl, metadata->download().download().url().c_str());
480 } else {
481 // Expect that the file is not present.
482 ASSERT_FALSE(metadata);
486 INSTANTIATE_TEST_CASE_P(
487 DownloadMetadataManager,
488 SetRequestTest,
489 testing::Combine(testing::Values("absent", "this", "other", "unknown"),
490 testing::Values("none", "pending"),
491 testing::Values("none", "pending"),
492 testing::Values("waiting", "loaded"),
493 testing::Values("clear", "set")));
495 } // namespace safe_browsing