| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "chrome/browser/safe_browsing/last_download_finder.h" | |
| 6 | |
| 7 #include <string> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/bind.h" | |
| 11 #include "base/callback.h" | |
| 12 #include "base/file_util.h" | |
| 13 #include "base/run_loop.h" | |
| 14 #include "base/strings/string_number_conversions.h" | |
| 15 #include "base/strings/utf_string_conversions.h" | |
| 16 #include "chrome/browser/history/chrome_history_client.h" | |
| 17 #include "chrome/browser/history/chrome_history_client_factory.h" | |
| 18 #include "chrome/browser/history/download_row.h" | |
| 19 #include "chrome/browser/history/history_service.h" | |
| 20 #include "chrome/browser/history/history_service_factory.h" | |
| 21 #include "chrome/browser/history/web_history_service_factory.h" | |
| 22 #include "chrome/browser/prefs/browser_prefs.h" | |
| 23 #include "chrome/browser/profiles/profile_manager.h" | |
| 24 #include "chrome/common/chrome_constants.h" | |
| 25 #include "chrome/common/pref_names.h" | |
| 26 #include "chrome/common/safe_browsing/csd.pb.h" | |
| 27 #include "chrome/test/base/testing_browser_process.h" | |
| 28 #include "chrome/test/base/testing_pref_service_syncable.h" | |
| 29 #include "chrome/test/base/testing_profile.h" | |
| 30 #include "chrome/test/base/testing_profile_manager.h" | |
| 31 #include "content/public/test/test_browser_thread_bundle.h" | |
| 32 #include "content/public/test/test_utils.h" | |
| 33 #include "testing/gtest/include/gtest/gtest.h" | |
| 34 | |
| 35 namespace { | |
| 36 | |
| 37 // A BrowserContextKeyedServiceFactory::TestingFactoryFunction that creates a | |
| 38 // HistoryService for a TestingProfile. | |
| 39 KeyedService* BuildHistoryService(content::BrowserContext* context) { | |
| 40 TestingProfile* profile = static_cast<TestingProfile*>(context); | |
| 41 | |
| 42 // Delete the file before creating the service. | |
| 43 base::FilePath history_path( | |
| 44 profile->GetPath().Append(chrome::kHistoryFilename)); | |
| 45 if (!base::DeleteFile(history_path, false) || | |
| 46 base::PathExists(history_path)) { | |
| 47 ADD_FAILURE() << "failed to delete history db file " | |
| 48 << history_path.value(); | |
| 49 return NULL; | |
| 50 } | |
| 51 | |
| 52 HistoryService* history_service = new HistoryService( | |
| 53 ChromeHistoryClientFactory::GetForProfile(profile), profile); | |
| 54 if (history_service->Init(profile->GetPath())) | |
| 55 return history_service; | |
| 56 | |
| 57 ADD_FAILURE() << "failed to initialize history service"; | |
| 58 delete history_service; | |
| 59 return NULL; | |
| 60 } | |
| 61 | |
| 62 } // namespace | |
| 63 | |
| 64 class LastDownloadFinderTest : public testing::Test { | |
| 65 public: | |
| 66 void NeverCalled(scoped_ptr< | |
| 67 safe_browsing::ClientIncidentReport_DownloadDetails> download) { | |
| 68 FAIL(); | |
| 69 } | |
| 70 | |
| 71 // Creates a new profile that participates in safe browsing and adds a | |
| 72 // download to its history. | |
| 73 void CreateProfileWithDownload() { | |
| 74 TestingProfile* profile = CreateProfile(SAFE_BROWSING_OPT_IN); | |
| 75 HistoryService* history_service = | |
| 76 HistoryServiceFactory::GetForProfile(profile, Profile::EXPLICIT_ACCESS); | |
| 77 history_service->CreateDownload( | |
| 78 CreateTestDownloadRow(), | |
| 79 base::Bind(&LastDownloadFinderTest::OnDownloadCreated, | |
| 80 base::Unretained(this))); | |
| 81 } | |
| 82 | |
| 83 // safe_browsing::LastDownloadFinder::LastDownloadCallback implementation that | |
| 84 // passes the found download to |result| and then runs a closure. | |
| 85 void OnLastDownload( | |
| 86 scoped_ptr<safe_browsing::ClientIncidentReport_DownloadDetails>* result, | |
| 87 const base::Closure& quit_closure, | |
| 88 scoped_ptr<safe_browsing::ClientIncidentReport_DownloadDetails> | |
| 89 download) { | |
| 90 *result = download.Pass(); | |
| 91 quit_closure.Run(); | |
| 92 } | |
| 93 | |
| 94 protected: | |
| 95 // A type for specifying whether or not a profile created by CreateProfile | |
| 96 // participates in safe browsing. | |
| 97 enum SafeBrowsingDisposition { | |
| 98 SAFE_BROWSING_OPT_OUT, | |
| 99 SAFE_BROWSING_OPT_IN, | |
| 100 }; | |
| 101 | |
| 102 LastDownloadFinderTest() : profile_number_() {} | |
| 103 | |
| 104 virtual void SetUp() OVERRIDE { | |
| 105 testing::Test::SetUp(); | |
| 106 profile_manager_.reset( | |
| 107 new TestingProfileManager(TestingBrowserProcess::GetGlobal())); | |
| 108 ASSERT_TRUE(profile_manager_->SetUp()); | |
| 109 } | |
| 110 | |
| 111 virtual void TearDown() OVERRIDE { | |
| 112 // Shut down the history service on all profiles. | |
| 113 std::vector<Profile*> profiles( | |
| 114 profile_manager_->profile_manager()->GetLoadedProfiles()); | |
| 115 for (size_t i = 0; i < profiles.size(); ++i) { | |
| 116 profiles[0]->AsTestingProfile()->DestroyHistoryService(); | |
| 117 } | |
| 118 profile_manager_.reset(); | |
| 119 TestingBrowserProcess::DeleteInstance(); | |
| 120 testing::Test::TearDown(); | |
| 121 } | |
| 122 | |
| 123 TestingProfile* CreateProfile(SafeBrowsingDisposition safe_browsing_opt_in) { | |
| 124 std::string profile_name("profile"); | |
| 125 profile_name.append(base::IntToString(++profile_number_)); | |
| 126 | |
| 127 // Set up keyed service factories. | |
| 128 TestingProfile::TestingFactories factories; | |
| 129 // Build up a custom history service. | |
| 130 factories.push_back(std::make_pair(HistoryServiceFactory::GetInstance(), | |
| 131 &BuildHistoryService)); | |
| 132 // Suppress WebHistoryService since it makes network requests. | |
| 133 factories.push_back(std::make_pair( | |
| 134 WebHistoryServiceFactory::GetInstance(), | |
| 135 static_cast<BrowserContextKeyedServiceFactory::TestingFactoryFunction>( | |
| 136 NULL))); | |
| 137 | |
| 138 // Create prefs for the profile with safe browsing enabled or not. | |
| 139 scoped_ptr<TestingPrefServiceSyncable> prefs( | |
| 140 new TestingPrefServiceSyncable); | |
| 141 chrome::RegisterUserProfilePrefs(prefs->registry()); | |
| 142 prefs->SetBoolean(prefs::kSafeBrowsingEnabled, | |
| 143 safe_browsing_opt_in == SAFE_BROWSING_OPT_IN); | |
| 144 | |
| 145 TestingProfile* profile = profile_manager_->CreateTestingProfile( | |
| 146 profile_name, | |
| 147 prefs.PassAs<PrefServiceSyncable>(), | |
| 148 base::UTF8ToUTF16(profile_name), // user_name | |
| 149 0, // avatar_id | |
| 150 std::string(), // supervised_user_id | |
| 151 factories); | |
| 152 | |
| 153 return profile; | |
| 154 } | |
| 155 | |
| 156 void AddDownload(Profile* profile, const history::DownloadRow& download) { | |
| 157 base::RunLoop run_loop; | |
| 158 | |
| 159 HistoryService* history_service = | |
| 160 HistoryServiceFactory::GetForProfile(profile, Profile::EXPLICIT_ACCESS); | |
| 161 history_service->CreateDownload( | |
| 162 download, | |
| 163 base::Bind(&LastDownloadFinderTest::ContinueOnDownloadCreated, | |
| 164 base::Unretained(this), | |
| 165 run_loop.QuitClosure())); | |
| 166 run_loop.Run(); | |
| 167 } | |
| 168 | |
| 169 // Wait for the history backend thread to process any outstanding tasks. | |
| 170 // This is needed because HistoryService::QueryDownloads uses PostTaskAndReply | |
| 171 // to do work on the backend thread and then invoke the caller's callback on | |
| 172 // the originating thread. The PostTaskAndReplyRelay holds a reference to the | |
| 173 // backend until its RunReplyAndSelfDestruct is called on the originating | |
| 174 // thread. This reference MUST be released (on the originating thread, | |
| 175 // remember) _before_ calling DestroyHistoryService in TearDown(). See the | |
| 176 // giant comment in HistoryService::Cleanup explaining where the backend's | |
| 177 // dtor must be run. | |
| 178 void FlushHistoryBackend(Profile* profile) { | |
| 179 base::RunLoop run_loop; | |
| 180 HistoryServiceFactory::GetForProfile(profile, Profile::EXPLICIT_ACCESS) | |
| 181 ->FlushForTest(run_loop.QuitClosure()); | |
| 182 run_loop.Run(); | |
| 183 // Then make sure anything bounced back to the main thread has been handled. | |
| 184 base::RunLoop().RunUntilIdle(); | |
| 185 } | |
| 186 | |
| 187 // Runs the last download finder on all loaded profiles, returning the found | |
| 188 // download or an empty pointer if none was found. | |
| 189 scoped_ptr<safe_browsing::ClientIncidentReport_DownloadDetails> | |
| 190 RunLastDownloadFinder() { | |
| 191 base::RunLoop run_loop; | |
| 192 | |
| 193 scoped_ptr<safe_browsing::ClientIncidentReport_DownloadDetails> | |
| 194 last_download; | |
| 195 | |
| 196 scoped_ptr<safe_browsing::LastDownloadFinder> finder( | |
| 197 safe_browsing::LastDownloadFinder::Create( | |
| 198 base::Bind(&LastDownloadFinderTest::OnLastDownload, | |
| 199 base::Unretained(this), | |
| 200 &last_download, | |
| 201 run_loop.QuitClosure()))); | |
| 202 | |
| 203 if (finder) | |
| 204 run_loop.Run(); | |
| 205 | |
| 206 return last_download.Pass(); | |
| 207 } | |
| 208 | |
| 209 history::DownloadRow CreateTestDownloadRow() { | |
| 210 base::Time now(base::Time::Now()); | |
| 211 return history::DownloadRow( | |
| 212 base::FilePath(FILE_PATH_LITERAL("spam.exe")), | |
| 213 base::FilePath(FILE_PATH_LITERAL("spam.exe")), | |
| 214 std::vector<GURL>(1, GURL("http://www.google.com")), // url_chain | |
| 215 GURL(), // referrer | |
| 216 "application/octet-stream", // mime_type | |
| 217 "application/octet-stream", // original_mime_type | |
| 218 now - base::TimeDelta::FromMinutes(10), // start | |
| 219 now - base::TimeDelta::FromMinutes(9), // end | |
| 220 std::string(), // etag | |
| 221 std::string(), // last_modified | |
| 222 47LL, // received | |
| 223 47LL, // total | |
| 224 content::DownloadItem::COMPLETE, // download_state | |
| 225 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, // danger_type | |
| 226 content::DOWNLOAD_INTERRUPT_REASON_NONE, // interrupt_reason, | |
| 227 1, // id | |
| 228 false, // download_opened | |
| 229 std::string(), // ext_id | |
| 230 std::string()); // ext_name | |
| 231 } | |
| 232 | |
| 233 void ExpectNoDownloadFound(scoped_ptr< | |
| 234 safe_browsing::ClientIncidentReport_DownloadDetails> download) { | |
| 235 EXPECT_FALSE(download); | |
| 236 } | |
| 237 | |
| 238 void ExpectFoundTestDownload(scoped_ptr< | |
| 239 safe_browsing::ClientIncidentReport_DownloadDetails> download) { | |
| 240 ASSERT_TRUE(download); | |
| 241 } | |
| 242 | |
| 243 content::TestBrowserThreadBundle browser_thread_bundle_; | |
| 244 scoped_ptr<TestingProfileManager> profile_manager_; | |
| 245 | |
| 246 private: | |
| 247 // A HistoryService::DownloadCreateCallback that asserts that the download was | |
| 248 // created and runs |closure|. | |
| 249 void ContinueOnDownloadCreated(const base::Closure& closure, bool created) { | |
| 250 ASSERT_TRUE(created); | |
| 251 closure.Run(); | |
| 252 } | |
| 253 | |
| 254 // A HistoryService::DownloadCreateCallback that asserts that the download was | |
| 255 // created. | |
| 256 void OnDownloadCreated(bool created) { ASSERT_TRUE(created); } | |
| 257 | |
| 258 int profile_number_; | |
| 259 }; | |
| 260 | |
| 261 // Tests that nothing happens if there are no profiles at all. | |
| 262 TEST_F(LastDownloadFinderTest, NoProfiles) { | |
| 263 ExpectNoDownloadFound(RunLastDownloadFinder()); | |
| 264 } | |
| 265 | |
| 266 // Tests that nothing happens other than the callback being invoked if there are | |
| 267 // no profiles participating in safe browsing. | |
| 268 TEST_F(LastDownloadFinderTest, NoParticipatingProfiles) { | |
| 269 // Create a profile with a history service that is opted-out | |
| 270 TestingProfile* profile = CreateProfile(SAFE_BROWSING_OPT_OUT); | |
| 271 | |
| 272 // Add a download. | |
| 273 AddDownload(profile, CreateTestDownloadRow()); | |
| 274 | |
| 275 ExpectNoDownloadFound(RunLastDownloadFinder()); | |
| 276 } | |
| 277 | |
| 278 // Tests that a download is found from a single profile. | |
| 279 TEST_F(LastDownloadFinderTest, SimpleEndToEnd) { | |
| 280 // Create a profile with a history service that is opted-in. | |
| 281 TestingProfile* profile = CreateProfile(SAFE_BROWSING_OPT_IN); | |
| 282 | |
| 283 // Add a download. | |
| 284 AddDownload(profile, CreateTestDownloadRow()); | |
| 285 | |
| 286 ExpectFoundTestDownload(RunLastDownloadFinder()); | |
| 287 } | |
| 288 | |
| 289 // Tests that there is no crash if the finder is deleted before results arrive. | |
| 290 TEST_F(LastDownloadFinderTest, DeleteBeforeResults) { | |
| 291 // Create a profile with a history service that is opted-in. | |
| 292 TestingProfile* profile = CreateProfile(SAFE_BROWSING_OPT_IN); | |
| 293 | |
| 294 // Add a download. | |
| 295 AddDownload(profile, CreateTestDownloadRow()); | |
| 296 | |
| 297 // Start a finder and kill it before the search completes. | |
| 298 safe_browsing::LastDownloadFinder::Create( | |
| 299 base::Bind(&LastDownloadFinderTest::NeverCalled, base::Unretained(this))) | |
| 300 .reset(); | |
| 301 | |
| 302 // Flush tasks on the history backend thread. | |
| 303 FlushHistoryBackend(profile); | |
| 304 } | |
| 305 | |
| 306 // Tests that a download in profile added after the search is begun is found. | |
| 307 TEST_F(LastDownloadFinderTest, AddProfileAfterStarting) { | |
| 308 // Create a profile with a history service that is opted-in. | |
| 309 CreateProfile(SAFE_BROWSING_OPT_IN); | |
| 310 | |
| 311 scoped_ptr<safe_browsing::ClientIncidentReport_DownloadDetails> last_download; | |
| 312 base::RunLoop run_loop; | |
| 313 | |
| 314 // Post a task that will create a second profile once the main loop is run. | |
| 315 base::MessageLoop::current()->PostTask( | |
| 316 FROM_HERE, | |
| 317 base::Bind(&LastDownloadFinderTest::CreateProfileWithDownload, | |
| 318 base::Unretained(this))); | |
| 319 | |
| 320 // Create a finder that we expect will find a download in the second profile. | |
| 321 scoped_ptr<safe_browsing::LastDownloadFinder> finder( | |
| 322 safe_browsing::LastDownloadFinder::Create( | |
| 323 base::Bind(&LastDownloadFinderTest::OnLastDownload, | |
| 324 base::Unretained(this), | |
| 325 &last_download, | |
| 326 run_loop.QuitClosure()))); | |
| 327 | |
| 328 run_loop.Run(); | |
| 329 | |
| 330 ExpectFoundTestDownload(last_download.Pass()); | |
| 331 } | |
| OLD | NEW |