Popular sites on the NTP: check that experiment group StartsWith (rather than IS...
[chromium-blink-merge.git] / chrome / browser / safe_browsing / incident_reporting / last_download_finder_unittest.cc
blob4000fae890d31f094ee384438a7ba7a71a5191dc
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/last_download_finder.h"
7 #include <string>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "base/location.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/run_loop.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "base/thread_task_runner_handle.h"
21 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
22 #include "chrome/browser/history/chrome_history_client.h"
23 #include "chrome/browser/history/history_service_factory.h"
24 #include "chrome/browser/history/web_history_service_factory.h"
25 #include "chrome/browser/prefs/browser_prefs.h"
26 #include "chrome/browser/profiles/profile_manager.h"
27 #include "chrome/common/chrome_constants.h"
28 #include "chrome/common/pref_names.h"
29 #include "chrome/common/safe_browsing/csd.pb.h"
30 #include "chrome/test/base/testing_browser_process.h"
31 #include "chrome/test/base/testing_pref_service_syncable.h"
32 #include "chrome/test/base/testing_profile.h"
33 #include "chrome/test/base/testing_profile_manager.h"
34 #include "components/history/content/browser/content_visit_delegate.h"
35 #include "components/history/content/browser/download_constants_utils.h"
36 #include "components/history/content/browser/history_database_helper.h"
37 #include "components/history/core/browser/download_constants.h"
38 #include "components/history/core/browser/download_row.h"
39 #include "components/history/core/browser/history_constants.h"
40 #include "components/history/core/browser/history_database_params.h"
41 #include "components/history/core/browser/history_service.h"
42 #include "content/public/test/test_browser_thread_bundle.h"
43 #include "content/public/test/test_utils.h"
44 #include "testing/gtest/include/gtest/gtest.h"
46 namespace {
48 // A BrowserContextKeyedServiceFactory::TestingFactoryFunction that creates a
49 // HistoryService for a TestingProfile.
50 scoped_ptr<KeyedService> BuildHistoryService(content::BrowserContext* context) {
51 TestingProfile* profile = static_cast<TestingProfile*>(context);
53 // Delete the file before creating the service.
54 base::FilePath history_path(
55 profile->GetPath().Append(history::kHistoryFilename));
56 if (!base::DeleteFile(history_path, false) ||
57 base::PathExists(history_path)) {
58 ADD_FAILURE() << "failed to delete history db file "
59 << history_path.value();
60 return nullptr;
63 scoped_ptr<history::HistoryService> history_service(
64 new history::HistoryService(
65 make_scoped_ptr(new ChromeHistoryClient(
66 BookmarkModelFactory::GetForProfile(profile))),
67 scoped_ptr<history::VisitDelegate>()));
68 if (history_service->Init(
69 profile->GetPrefs()->GetString(prefs::kAcceptLanguages),
70 history::HistoryDatabaseParamsForPath(profile->GetPath()))) {
71 return history_service.Pass();
74 ADD_FAILURE() << "failed to initialize history service";
75 return nullptr;
78 #if defined(OS_WIN)
79 static const base::FilePath::CharType kBinaryFileName[] =
80 FILE_PATH_LITERAL("spam.exe");
81 static const base::FilePath::CharType kBinaryFileNameForOtherOS[] =
82 FILE_PATH_LITERAL("spam.dmg");
83 #elif defined(OS_MACOSX)
84 static const base::FilePath::CharType kBinaryFileName[] =
85 FILE_PATH_LITERAL("spam.dmg");
86 static const base::FilePath::CharType kBinaryFileNameForOtherOS[] =
87 FILE_PATH_LITERAL("spam.apk");
88 #elif defined(OS_ANDROID)
89 static const base::FilePath::CharType kBinaryFileName[] =
90 FILE_PATH_LITERAL("spam.apk");
91 static const base::FilePath::CharType kBinaryFileNameForOtherOS[] =
92 FILE_PATH_LITERAL("spam.dmg");
93 #else
94 static const base::FilePath::CharType kBinaryFileName[] =
95 FILE_PATH_LITERAL("spam.exe");
96 #endif
98 } // namespace
100 namespace safe_browsing {
102 class LastDownloadFinderTest : public testing::Test {
103 public:
104 void NeverCalled(scoped_ptr<ClientIncidentReport_DownloadDetails> download) {
105 FAIL();
108 // Creates a new profile that participates in safe browsing and adds a
109 // download to its history.
110 void CreateProfileWithDownload() {
111 TestingProfile* profile = CreateProfile(SAFE_BROWSING_OPT_IN);
112 history::HistoryService* history_service =
113 HistoryServiceFactory::GetForProfile(
114 profile, ServiceAccessType::EXPLICIT_ACCESS);
115 history_service->CreateDownload(
116 CreateTestDownloadRow(kBinaryFileName),
117 base::Bind(&LastDownloadFinderTest::OnDownloadCreated,
118 base::Unretained(this)));
121 // LastDownloadFinder::LastDownloadCallback implementation that
122 // passes the found download to |result| and then runs a closure.
123 void OnLastDownload(
124 scoped_ptr<ClientIncidentReport_DownloadDetails>* result,
125 const base::Closure& quit_closure,
126 scoped_ptr<ClientIncidentReport_DownloadDetails> download) {
127 *result = download.Pass();
128 quit_closure.Run();
131 protected:
132 // A type for specifying whether or not a profile created by CreateProfile
133 // participates in safe browsing.
134 enum SafeBrowsingDisposition {
135 SAFE_BROWSING_OPT_OUT,
136 SAFE_BROWSING_OPT_IN,
139 LastDownloadFinderTest() : profile_number_() {}
141 void SetUp() override {
142 testing::Test::SetUp();
143 profile_manager_.reset(
144 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
145 ASSERT_TRUE(profile_manager_->SetUp());
148 void TearDown() override {
149 // Shut down the history service on all profiles.
150 std::vector<Profile*> profiles(
151 profile_manager_->profile_manager()->GetLoadedProfiles());
152 for (size_t i = 0; i < profiles.size(); ++i) {
153 profiles[0]->AsTestingProfile()->DestroyHistoryService();
155 profile_manager_.reset();
156 TestingBrowserProcess::DeleteInstance();
157 testing::Test::TearDown();
160 TestingProfile* CreateProfile(SafeBrowsingDisposition safe_browsing_opt_in) {
161 std::string profile_name("profile");
162 profile_name.append(base::IntToString(++profile_number_));
164 // Set up keyed service factories.
165 TestingProfile::TestingFactories factories;
166 // Build up a custom history service.
167 factories.push_back(std::make_pair(HistoryServiceFactory::GetInstance(),
168 &BuildHistoryService));
169 // Suppress WebHistoryService since it makes network requests.
170 factories.push_back(std::make_pair(
171 WebHistoryServiceFactory::GetInstance(),
172 static_cast<BrowserContextKeyedServiceFactory::TestingFactoryFunction>(
173 NULL)));
175 // Create prefs for the profile with safe browsing enabled or not.
176 scoped_ptr<TestingPrefServiceSyncable> prefs(
177 new TestingPrefServiceSyncable);
178 chrome::RegisterUserProfilePrefs(prefs->registry());
179 prefs->SetBoolean(prefs::kSafeBrowsingEnabled,
180 safe_browsing_opt_in == SAFE_BROWSING_OPT_IN);
182 TestingProfile* profile = profile_manager_->CreateTestingProfile(
183 profile_name,
184 prefs.Pass(),
185 base::UTF8ToUTF16(profile_name), // user_name
186 0, // avatar_id
187 std::string(), // supervised_user_id
188 factories);
190 return profile;
193 LastDownloadFinder::DownloadDetailsGetter GetDownloadDetailsGetter() {
194 return base::Bind(&LastDownloadFinderTest::GetDownloadDetails,
195 base::Unretained(this));
198 void AddDownload(Profile* profile, const history::DownloadRow& download) {
199 base::RunLoop run_loop;
201 history::HistoryService* history_service =
202 HistoryServiceFactory::GetForProfile(
203 profile, ServiceAccessType::EXPLICIT_ACCESS);
204 history_service->CreateDownload(
205 download,
206 base::Bind(&LastDownloadFinderTest::ContinueOnDownloadCreated,
207 base::Unretained(this),
208 run_loop.QuitClosure()));
209 run_loop.Run();
212 // Wait for the history backend thread to process any outstanding tasks.
213 // This is needed because HistoryService::QueryDownloads uses PostTaskAndReply
214 // to do work on the backend thread and then invoke the caller's callback on
215 // the originating thread. The PostTaskAndReplyRelay holds a reference to the
216 // backend until its RunReplyAndSelfDestruct is called on the originating
217 // thread. This reference MUST be released (on the originating thread,
218 // remember) _before_ calling DestroyHistoryService in TearDown(). See the
219 // giant comment in HistoryService::Cleanup explaining where the backend's
220 // dtor must be run.
221 void FlushHistoryBackend(Profile* profile) {
222 base::RunLoop run_loop;
223 HistoryServiceFactory::GetForProfile(profile,
224 ServiceAccessType::EXPLICIT_ACCESS)
225 ->FlushForTest(run_loop.QuitClosure());
226 run_loop.Run();
227 // Then make sure anything bounced back to the main thread has been handled.
228 base::RunLoop().RunUntilIdle();
231 // Runs the last download finder on all loaded profiles, returning the found
232 // download or an empty pointer if none was found.
233 scoped_ptr<ClientIncidentReport_DownloadDetails> RunLastDownloadFinder() {
234 base::RunLoop run_loop;
236 scoped_ptr<ClientIncidentReport_DownloadDetails> last_download;
238 scoped_ptr<LastDownloadFinder> finder(LastDownloadFinder::Create(
239 GetDownloadDetailsGetter(),
240 base::Bind(&LastDownloadFinderTest::OnLastDownload,
241 base::Unretained(this),
242 &last_download,
243 run_loop.QuitClosure())));
245 if (finder)
246 run_loop.Run();
248 return last_download.Pass();
251 history::DownloadRow CreateTestDownloadRow(
252 const base::FilePath::CharType* file_path) {
253 base::Time now(base::Time::Now());
254 return history::DownloadRow(
255 base::FilePath(file_path), base::FilePath(file_path),
256 std::vector<GURL>(1, GURL("http://www.google.com")), // url_chain
257 GURL(), // referrer
258 "application/octet-stream", // mime_type
259 "application/octet-stream", // original_mime_type
260 now - base::TimeDelta::FromMinutes(10), // start
261 now - base::TimeDelta::FromMinutes(9), // end
262 std::string(), // etag
263 std::string(), // last_modified
264 47LL, // received
265 47LL, // total
266 history::DownloadState::COMPLETE, // download_state
267 history::DownloadDangerType::NOT_DANGEROUS, // danger_type
268 history::ToHistoryDownloadInterruptReason(
269 content::DOWNLOAD_INTERRUPT_REASON_NONE), // interrupt_reason,
270 1, // id
271 false, // download_opened
272 std::string(), // ext_id
273 std::string()); // ext_name
276 void ExpectNoDownloadFound(
277 scoped_ptr<ClientIncidentReport_DownloadDetails> download) {
278 EXPECT_FALSE(download);
281 void ExpectFoundTestDownload(
282 scoped_ptr<ClientIncidentReport_DownloadDetails> download) {
283 ASSERT_TRUE(download);
286 content::TestBrowserThreadBundle browser_thread_bundle_;
287 scoped_ptr<TestingProfileManager> profile_manager_;
289 private:
290 // A HistoryService::DownloadCreateCallback that asserts that the download was
291 // created and runs |closure|.
292 void ContinueOnDownloadCreated(const base::Closure& closure, bool created) {
293 ASSERT_TRUE(created);
294 closure.Run();
297 // A HistoryService::DownloadCreateCallback that asserts that the download was
298 // created.
299 void OnDownloadCreated(bool created) { ASSERT_TRUE(created); }
301 void GetDownloadDetails(
302 content::BrowserContext* context,
303 const DownloadMetadataManager::GetDownloadDetailsCallback& callback) {
304 callback.Run(scoped_ptr<ClientIncidentReport_DownloadDetails>());
307 int profile_number_;
310 // Tests that nothing happens if there are no profiles at all.
311 TEST_F(LastDownloadFinderTest, NoProfiles) {
312 ExpectNoDownloadFound(RunLastDownloadFinder());
315 // Tests that nothing happens other than the callback being invoked if there are
316 // no profiles participating in safe browsing.
317 TEST_F(LastDownloadFinderTest, NoParticipatingProfiles) {
318 // Create a profile with a history service that is opted-out
319 TestingProfile* profile = CreateProfile(SAFE_BROWSING_OPT_OUT);
321 // Add a download.
322 AddDownload(profile, CreateTestDownloadRow(kBinaryFileName));
324 ExpectNoDownloadFound(RunLastDownloadFinder());
327 // Tests that a download is found from a single profile.
328 TEST_F(LastDownloadFinderTest, SimpleEndToEnd) {
329 // Create a profile with a history service that is opted-in.
330 TestingProfile* profile = CreateProfile(SAFE_BROWSING_OPT_IN);
332 // Add a download.
333 AddDownload(profile, CreateTestDownloadRow(kBinaryFileName));
335 ExpectFoundTestDownload(RunLastDownloadFinder());
338 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_ANDROID)
339 // Tests that nothing happens if the binary is an executable for a different OS.
340 TEST_F(LastDownloadFinderTest, DownloadForDifferentOs) {
341 // Create a profile with a history service that is opted-in.
342 TestingProfile* profile = CreateProfile(SAFE_BROWSING_OPT_IN);
344 // Add a download.
345 AddDownload(profile, CreateTestDownloadRow(kBinaryFileNameForOtherOS));
347 ExpectNoDownloadFound(RunLastDownloadFinder());
349 #endif
351 // Tests that there is no crash if the finder is deleted before results arrive.
352 TEST_F(LastDownloadFinderTest, DeleteBeforeResults) {
353 // Create a profile with a history service that is opted-in.
354 TestingProfile* profile = CreateProfile(SAFE_BROWSING_OPT_IN);
356 // Add a download.
357 AddDownload(profile, CreateTestDownloadRow(kBinaryFileName));
359 // Start a finder and kill it before the search completes.
360 LastDownloadFinder::Create(GetDownloadDetailsGetter(),
361 base::Bind(&LastDownloadFinderTest::NeverCalled,
362 base::Unretained(this))).reset();
364 // Flush tasks on the history backend thread.
365 FlushHistoryBackend(profile);
368 // Tests that a download in profile added after the search is begun is found.
369 TEST_F(LastDownloadFinderTest, AddProfileAfterStarting) {
370 // Create a profile with a history service that is opted-in.
371 CreateProfile(SAFE_BROWSING_OPT_IN);
373 scoped_ptr<ClientIncidentReport_DownloadDetails> last_download;
374 base::RunLoop run_loop;
376 // Post a task that will create a second profile once the main loop is run.
377 base::ThreadTaskRunnerHandle::Get()->PostTask(
378 FROM_HERE, base::Bind(&LastDownloadFinderTest::CreateProfileWithDownload,
379 base::Unretained(this)));
381 // Create a finder that we expect will find a download in the second profile.
382 scoped_ptr<LastDownloadFinder> finder(LastDownloadFinder::Create(
383 GetDownloadDetailsGetter(),
384 base::Bind(&LastDownloadFinderTest::OnLastDownload,
385 base::Unretained(this),
386 &last_download,
387 run_loop.QuitClosure())));
389 run_loop.Run();
391 ExpectFoundTestDownload(last_download.Pass());
394 } // namespace safe_browsing