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 "base/basictypes.h" 6 #include "base/compiler_specific.h" 7 #include "base/file_util.h" 8 #include "base/memory/ref_counted.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "base/path_service.h" 11 #include "base/run_loop.h" 12 #include "base/version.h" 13 #include "chrome/browser/component_updater/crx_update_item.h" 14 #include "chrome/browser/component_updater/test/component_updater_service_unittest.h" 15 #include "chrome/browser/component_updater/test/url_request_post_interceptor.h" 16 #include "chrome/browser/component_updater/update_checker.h" 17 #include "chrome/common/chrome_paths.h" 18 #include "content/public/browser/browser_thread.h" 19 #include "content/public/test/test_browser_thread_bundle.h" 20 #include "net/url_request/url_fetcher.h" 21 #include "net/url_request/url_request_test_util.h" 22 #include "testing/gtest/include/gtest/gtest.h" 23 24 using content::BrowserThread; 25 26 namespace component_updater { 27 28 namespace { 29 30 base::FilePath test_file(const char* file) { 31 base::FilePath path; 32 PathService::Get(chrome::DIR_TEST_DATA, &path); 33 return path.AppendASCII("components").AppendASCII(file); 34 } 35 36 } // namespace 37 38 class UpdateCheckerTest : public testing::Test { 39 public: 40 UpdateCheckerTest(); 41 virtual ~UpdateCheckerTest(); 42 43 // Overrides from testing::Test. 44 virtual void SetUp() OVERRIDE; 45 virtual void TearDown() OVERRIDE; 46 47 void UpdateCheckComplete(int error, 48 const std::string& error_message, 49 const UpdateResponse::Results& results); 50 51 net::URLRequestContextGetter* context() { return context_.get(); } 52 53 protected: 54 void Quit(); 55 void RunThreads(); 56 void RunThreadsUntilIdle(); 57 58 CrxUpdateItem BuildCrxUpdateItem(); 59 60 scoped_ptr<UpdateChecker> update_checker_; 61 62 scoped_ptr<InterceptorFactory> interceptor_factory_; 63 URLRequestPostInterceptor* post_interceptor_; // Owned by the factory. 64 65 int error_; 66 std::string error_message_; 67 UpdateResponse::Results results_; 68 69 private: 70 scoped_refptr<net::TestURLRequestContextGetter> context_; 71 content::TestBrowserThreadBundle thread_bundle_; 72 base::FilePath test_data_dir_; 73 base::Closure quit_closure_; 74 75 DISALLOW_COPY_AND_ASSIGN(UpdateCheckerTest); 76 }; 77 78 UpdateCheckerTest::UpdateCheckerTest() 79 : error_(0), 80 context_(new net::TestURLRequestContextGetter( 81 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO))), 82 thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) { 83 // The test directory is chrome/test/data/components. 84 PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_); 85 test_data_dir_ = test_data_dir_.AppendASCII("components"); 86 87 net::URLFetcher::SetEnableInterceptionForTests(true); 88 } 89 90 UpdateCheckerTest::~UpdateCheckerTest() { 91 net::URLFetcher::SetEnableInterceptionForTests(false); 92 context_ = NULL; 93 } 94 95 void UpdateCheckerTest::SetUp() { 96 interceptor_factory_.reset(new InterceptorFactory); 97 post_interceptor_ = interceptor_factory_->CreateInterceptor(); 98 EXPECT_TRUE(post_interceptor_); 99 100 update_checker_.reset(); 101 102 error_ = 0; 103 error_message_.clear(); 104 results_ = UpdateResponse::Results(); 105 } 106 107 void UpdateCheckerTest::TearDown() { 108 update_checker_.reset(); 109 110 post_interceptor_ = NULL; 111 interceptor_factory_.reset(); 112 } 113 114 void UpdateCheckerTest::RunThreads() { 115 base::RunLoop runloop; 116 quit_closure_ = runloop.QuitClosure(); 117 runloop.Run(); 118 119 // Since some tests need to drain currently enqueued tasks such as network 120 // intercepts on the IO thread, run the threads until they are 121 // idle. The component updater service won't loop again until the loop count 122 // is set and the service is started. 123 RunThreadsUntilIdle(); 124 } 125 126 void UpdateCheckerTest::RunThreadsUntilIdle() { 127 base::RunLoop().RunUntilIdle(); 128 } 129 130 void UpdateCheckerTest::Quit() { 131 if (!quit_closure_.is_null()) 132 quit_closure_.Run(); 133 } 134 135 void UpdateCheckerTest::UpdateCheckComplete( 136 int error, 137 const std::string& error_message, 138 const UpdateResponse::Results& results) { 139 error_ = error; 140 error_message_ = error_message; 141 results_ = results; 142 Quit(); 143 } 144 145 CrxUpdateItem UpdateCheckerTest::BuildCrxUpdateItem() { 146 CrxComponent crx_component; 147 crx_component.name = "test_jebg"; 148 crx_component.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash)); 149 crx_component.installer = NULL; 150 crx_component.version = base::Version("0.9"); 151 crx_component.fingerprint = "fp1"; 152 153 CrxUpdateItem crx_update_item; 154 crx_update_item.status = CrxUpdateItem::kNew; 155 crx_update_item.id = "jebgalgnebhfojomionfpkfelancnnkf"; 156 crx_update_item.component = crx_component; 157 158 return crx_update_item; 159 } 160 161 TEST_F(UpdateCheckerTest, UpdateCheckSuccess) { 162 EXPECT_TRUE(post_interceptor_->ExpectRequest( 163 new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml"))); 164 165 update_checker_ = 166 UpdateChecker::Create(GURL("https://localhost2/update2"), 167 context(), 168 base::Bind(&UpdateCheckerTest::UpdateCheckComplete, 169 base::Unretained(this))).Pass(); 170 171 CrxUpdateItem item(BuildCrxUpdateItem()); 172 std::vector<CrxUpdateItem*> items_to_check; 173 items_to_check.push_back(&item); 174 175 update_checker_->CheckForUpdates(items_to_check, "extra=\"params\""); 176 177 RunThreads(); 178 179 EXPECT_EQ(1, post_interceptor_->GetHitCount()) 180 << post_interceptor_->GetRequestsAsString(); 181 EXPECT_EQ(1, post_interceptor_->GetCount()) 182 << post_interceptor_->GetRequestsAsString(); 183 184 // Sanity check the request. 185 EXPECT_NE( 186 string::npos, 187 post_interceptor_->GetRequests()[0].find( 188 "request protocol=\"3.0\" extra=\"params\"")); 189 EXPECT_NE( 190 string::npos, 191 post_interceptor_->GetRequests()[0].find( 192 "app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" version=\"0.9\">" 193 "<updatecheck /><packages><package fp=\"fp1\"/></packages></app>")); 194 195 EXPECT_NE(string::npos, 196 post_interceptor_->GetRequests()[0].find("<hw physmemory=")); 197 198 // Sanity check the arguments of the callback after parsing. 199 EXPECT_EQ(0, error_); 200 EXPECT_TRUE(error_message_.empty()); 201 EXPECT_EQ(1ul, results_.list.size()); 202 EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", 203 results_.list[0].extension_id.c_str()); 204 EXPECT_STREQ("1.0", results_.list[0].manifest.version.c_str()); 205 } 206 207 TEST_F(UpdateCheckerTest, UpdateNetworkError) { 208 // Setting this expectation simulates a network error since the 209 // file is not found. Since setting the expectation fails, this function 210 // owns |request_matcher|. 211 scoped_ptr<PartialMatch> request_matcher(new PartialMatch("updatecheck")); 212 EXPECT_FALSE(post_interceptor_->ExpectRequest(request_matcher.get(), 213 test_file("no such file"))); 214 215 update_checker_ = 216 UpdateChecker::Create(GURL("https://localhost2/update2"), 217 context(), 218 base::Bind(&UpdateCheckerTest::UpdateCheckComplete, 219 base::Unretained(this))).Pass(); 220 221 CrxUpdateItem item(BuildCrxUpdateItem()); 222 std::vector<CrxUpdateItem*> items_to_check; 223 items_to_check.push_back(&item); 224 225 update_checker_->CheckForUpdates(items_to_check, ""); 226 227 RunThreads(); 228 229 EXPECT_EQ(0, post_interceptor_->GetHitCount()) 230 << post_interceptor_->GetRequestsAsString(); 231 EXPECT_EQ(1, post_interceptor_->GetCount()) 232 << post_interceptor_->GetRequestsAsString(); 233 234 EXPECT_NE(0, error_); 235 EXPECT_STREQ("network error", error_message_.c_str()); 236 EXPECT_EQ(0ul, results_.list.size()); 237 } 238 239 } // namespace component_updater 240