device_local_account_external_policy_loader_unittest.cc revision f2477e01787aa58f445919b809d89e252beef54f
1// Copyright 2013 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/chromeos/extensions/device_local_account_external_policy_loader.h" 6 7#include <string> 8 9#include "base/callback.h" 10#include "base/file_util.h" 11#include "base/files/scoped_temp_dir.h" 12#include "base/message_loop/message_loop.h" 13#include "base/message_loop/message_loop_proxy.h" 14#include "base/path_service.h" 15#include "base/run_loop.h" 16#include "base/strings/stringprintf.h" 17#include "base/values.h" 18#include "base/version.h" 19#include "chrome/browser/chrome_notification_types.h" 20#include "chrome/browser/extensions/external_provider_impl.h" 21#include "chrome/browser/extensions/updater/extension_downloader.h" 22#include "chrome/browser/policy/cloud/mock_cloud_policy_store.h" 23#include "chrome/common/chrome_paths.h" 24#include "chrome/common/extensions/extension_constants.h" 25#include "chrome/test/base/testing_browser_process.h" 26#include "components/policy/core/common/policy_map.h" 27#include "components/policy/core/common/policy_types.h" 28#include "content/public/browser/notification_service.h" 29#include "content/public/browser/notification_source.h" 30#include "content/public/browser/render_process_host.h" 31#include "content/public/test/test_browser_thread_bundle.h" 32#include "content/public/test/test_utils.h" 33#include "extensions/browser/external_provider_interface.h" 34#include "extensions/common/extension.h" 35#include "extensions/common/manifest.h" 36#include "net/url_request/test_url_fetcher_factory.h" 37#include "net/url_request/url_fetcher_delegate.h" 38#include "net/url_request/url_request_context_getter.h" 39#include "net/url_request/url_request_test_util.h" 40#include "policy/policy_constants.h" 41#include "testing/gmock/include/gmock/gmock.h" 42#include "testing/gtest/include/gtest/gtest.h" 43#include "url/gurl.h" 44 45using ::testing::InvokeWithoutArgs; 46using ::testing::Mock; 47using ::testing::_; 48 49namespace chromeos { 50 51namespace { 52 53const char kCacheDir[] = "cache"; 54const char kExtensionId[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf"; 55const char kExtensionUpdateManifest[] = 56 "extensions/good_v1_update_manifest.xml"; 57const char kExtensionCRXSourceDir[] = "extensions"; 58const char kExtensionCRXFile[] = "good.crx"; 59const char kExtensionCRXVersion[] = "1.0.0.0"; 60 61class MockExternalPolicyProviderVisitor 62 : public extensions::ExternalProviderInterface::VisitorInterface { 63 public: 64 MockExternalPolicyProviderVisitor(); 65 virtual ~MockExternalPolicyProviderVisitor(); 66 67 MOCK_METHOD6(OnExternalExtensionFileFound, 68 bool(const std::string&, 69 const base::Version*, 70 const base::FilePath&, 71 extensions::Manifest::Location, 72 int, 73 bool)); 74 MOCK_METHOD5(OnExternalExtensionUpdateUrlFound, 75 bool(const std::string&, 76 const GURL&, 77 extensions::Manifest::Location, 78 int, 79 bool)); 80 MOCK_METHOD1(OnExternalProviderReady, 81 void(const extensions::ExternalProviderInterface* provider)); 82 83 private: 84 DISALLOW_COPY_AND_ASSIGN(MockExternalPolicyProviderVisitor); 85}; 86 87MockExternalPolicyProviderVisitor::MockExternalPolicyProviderVisitor() { 88} 89 90MockExternalPolicyProviderVisitor::~MockExternalPolicyProviderVisitor() { 91} 92 93} // namespace 94 95class DeviceLocalAccountExternalPolicyLoaderTest : public testing::Test { 96 protected: 97 DeviceLocalAccountExternalPolicyLoaderTest(); 98 virtual ~DeviceLocalAccountExternalPolicyLoaderTest(); 99 100 virtual void SetUp() OVERRIDE; 101 virtual void TearDown() OVERRIDE; 102 103 void VerifyAndResetVisitorCallExpectations(); 104 void SetForceInstallListPolicy(); 105 106 content::TestBrowserThreadBundle thread_bundle_; 107 base::ScopedTempDir temp_dir_; 108 base::FilePath cache_dir_; 109 policy::MockCloudPolicyStore store_; 110 scoped_refptr<net::URLRequestContextGetter> request_context_getter_; 111 base::FilePath test_dir_; 112 113 scoped_refptr<DeviceLocalAccountExternalPolicyLoader> loader_; 114 MockExternalPolicyProviderVisitor visitor_; 115 scoped_ptr<extensions::ExternalProviderImpl> provider_; 116}; 117 118DeviceLocalAccountExternalPolicyLoaderTest:: 119 DeviceLocalAccountExternalPolicyLoaderTest() 120 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) { 121} 122 123DeviceLocalAccountExternalPolicyLoaderTest:: 124 ~DeviceLocalAccountExternalPolicyLoaderTest() { 125} 126 127void DeviceLocalAccountExternalPolicyLoaderTest::SetUp() { 128 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 129 cache_dir_ = temp_dir_.path().Append(kCacheDir); 130 ASSERT_TRUE(file_util::CreateDirectoryAndGetError(cache_dir_, NULL)); 131 request_context_getter_ = 132 new net::TestURLRequestContextGetter(base::MessageLoopProxy::current()); 133 TestingBrowserProcess::GetGlobal()->SetSystemRequestContext( 134 request_context_getter_.get()); 135 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir_)); 136 137 loader_ = new DeviceLocalAccountExternalPolicyLoader(&store_, cache_dir_); 138 provider_.reset(new extensions::ExternalProviderImpl( 139 &visitor_, 140 loader_, 141 NULL, 142 extensions::Manifest::EXTERNAL_POLICY, 143 extensions::Manifest::EXTERNAL_POLICY_DOWNLOAD, 144 extensions::Extension::NO_FLAGS)); 145 146 content::RenderProcessHost::SetRunRendererInProcess(true); 147 148 VerifyAndResetVisitorCallExpectations(); 149} 150 151void DeviceLocalAccountExternalPolicyLoaderTest::TearDown() { 152 content::RenderProcessHost::SetRunRendererInProcess(false); 153 TestingBrowserProcess::GetGlobal()->SetSystemRequestContext(NULL); 154} 155 156void DeviceLocalAccountExternalPolicyLoaderTest:: 157 VerifyAndResetVisitorCallExpectations() { 158 Mock::VerifyAndClearExpectations(&visitor_); 159 EXPECT_CALL(visitor_, OnExternalExtensionFileFound(_, _, _, _, _, _)) 160 .Times(0); 161 EXPECT_CALL(visitor_, OnExternalExtensionUpdateUrlFound(_, _, _, _, _)) 162 .Times(0); 163 EXPECT_CALL(visitor_, OnExternalProviderReady(_)) 164 .Times(0); 165} 166 167void DeviceLocalAccountExternalPolicyLoaderTest::SetForceInstallListPolicy() { 168 scoped_ptr<base::ListValue> forcelist(new base::ListValue); 169 forcelist->AppendString("invalid"); 170 forcelist->AppendString(base::StringPrintf( 171 "%s;%s", 172 kExtensionId, 173 extension_urls::GetWebstoreUpdateUrl().spec().c_str())); 174 store_.policy_map_.Set(policy::key::kExtensionInstallForcelist, 175 policy::POLICY_LEVEL_MANDATORY, 176 policy::POLICY_SCOPE_USER, 177 forcelist.release(), 178 NULL); 179 store_.NotifyStoreLoaded(); 180} 181 182// Verifies that when the cache is not explicitly started, the loader does not 183// serve any extensions, even if the force-install list policy is set or a load 184// is manually requested. 185TEST_F(DeviceLocalAccountExternalPolicyLoaderTest, CacheNotStarted) { 186 // Set the force-install list policy. 187 SetForceInstallListPolicy(); 188 189 // Manually request a load. 190 loader_->StartLoading(); 191 192 EXPECT_FALSE(loader_->IsCacheRunning()); 193 EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting()); 194} 195 196// Verifies that the cache can be started and stopped correctly. 197TEST_F(DeviceLocalAccountExternalPolicyLoaderTest, ForceInstallListEmpty) { 198 // Set an empty force-install list policy. 199 store_.NotifyStoreLoaded(); 200 201 // Start the cache. Verify that the loader announces an empty extension list. 202 EXPECT_CALL(visitor_, OnExternalProviderReady(provider_.get())) 203 .Times(1); 204 loader_->StartCache(base::MessageLoopProxy::current()); 205 VerifyAndResetVisitorCallExpectations(); 206 207 // Stop the cache. Verify that the loader announces an empty extension list. 208 EXPECT_CALL(visitor_, OnExternalProviderReady(provider_.get())) 209 .Times(1); 210 base::RunLoop run_loop; 211 loader_->StopCache(run_loop.QuitClosure()); 212 VerifyAndResetVisitorCallExpectations(); 213 214 // Spin the loop until the cache shutdown callback is invoked. Verify that at 215 // that point, no further file I/O tasks are pending. 216 run_loop.Run(); 217 EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting()); 218} 219 220// Verifies that when a force-install list policy referencing an extension is 221// set and the cache is started, the loader downloads, caches and serves the 222// extension. 223TEST_F(DeviceLocalAccountExternalPolicyLoaderTest, ForceInstallListSet) { 224 // Set a force-install list policy that contains an invalid entry (which 225 // should be ignored) and a valid reference to an extension. 226 SetForceInstallListPolicy(); 227 228 // Start the cache. 229 loader_->StartCache(base::MessageLoopProxy::current()); 230 231 // Spin the loop, allowing the loader to process the force-install list. 232 // Verify that the loader announces an empty extension list. 233 net::TestURLFetcherFactory factory; 234 EXPECT_CALL(visitor_, OnExternalProviderReady(provider_.get())) 235 .Times(1); 236 base::MessageLoop::current()->RunUntilIdle(); 237 238 // Verify that a downloader has started and is attempting to download an 239 // update manifest. 240 net::TestURLFetcher* fetcher = factory.GetFetcherByID( 241 extensions::ExtensionDownloader::kManifestFetcherId); 242 ASSERT_TRUE(fetcher); 243 ASSERT_TRUE(fetcher->delegate()); 244 245 // Return a manifest to the downloader. 246 std::string manifest; 247 EXPECT_TRUE(base::ReadFileToString(test_dir_.Append(kExtensionUpdateManifest), 248 &manifest)); 249 fetcher->set_response_code(200); 250 fetcher->SetResponseString(manifest); 251 fetcher->delegate()->OnURLFetchComplete(fetcher); 252 253 // Wait for the manifest to be parsed. 254 content::WindowedNotificationObserver( 255 chrome::NOTIFICATION_EXTENSION_UPDATE_FOUND, 256 content::NotificationService::AllSources()).Wait(); 257 258 // Verify that the downloader is attempting to download a CRX file. 259 fetcher = factory.GetFetcherByID( 260 extensions::ExtensionDownloader::kExtensionFetcherId); 261 ASSERT_TRUE(fetcher); 262 ASSERT_TRUE(fetcher->delegate()); 263 264 // Create a temporary CRX file and return its path to the downloader. 265 EXPECT_TRUE(base::CopyFile( 266 test_dir_.Append(kExtensionCRXSourceDir).Append(kExtensionCRXFile), 267 temp_dir_.path().Append(kExtensionCRXFile))); 268 fetcher->set_response_code(200); 269 fetcher->SetResponseFilePath(temp_dir_.path().Append(kExtensionCRXFile)); 270 fetcher->delegate()->OnURLFetchComplete(fetcher); 271 272 // Spin the loop. Verify that the loader announces the presence of a new CRX 273 // file, served from the cache directory. 274 const base::FilePath cached_crx_path = cache_dir_.Append(base::StringPrintf( 275 "%s-%s.crx", kExtensionId, kExtensionCRXVersion)); 276 base::RunLoop cache_run_loop; 277 EXPECT_CALL(visitor_, OnExternalExtensionFileFound( 278 kExtensionId, 279 _, 280 cached_crx_path, 281 extensions::Manifest::EXTERNAL_POLICY, 282 _, 283 _)); 284 EXPECT_CALL(visitor_, OnExternalProviderReady(provider_.get())) 285 .Times(1) 286 .WillOnce(InvokeWithoutArgs(&cache_run_loop, &base::RunLoop::Quit)); 287 cache_run_loop.Run(); 288 VerifyAndResetVisitorCallExpectations(); 289 290 // Verify that the CRX file actually exists in the cache directory and its 291 // contents matches the file returned to the downloader. 292 EXPECT_TRUE(base::ContentsEqual( 293 test_dir_.Append(kExtensionCRXSourceDir).Append(kExtensionCRXFile), 294 cached_crx_path)); 295 296 // Stop the cache. Verify that the loader announces an empty extension list. 297 EXPECT_CALL(visitor_, OnExternalProviderReady(provider_.get())) 298 .Times(1); 299 base::RunLoop shutdown_run_loop; 300 loader_->StopCache(shutdown_run_loop.QuitClosure()); 301 VerifyAndResetVisitorCallExpectations(); 302 303 // Spin the loop until the cache shutdown callback is invoked. Verify that at 304 // that point, no further file I/O tasks are pending. 305 shutdown_run_loop.Run(); 306 EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting()); 307} 308 309} // namespace chromeos 310