Chromium Code Reviews| Index: chrome/browser/chromeos/extensions/device_local_account_external_policy_loader_unittest.cc |
| diff --git a/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader_unittest.cc b/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..26c8cb37f169d2e2c678f5dee8e6d7b62bf0020d |
| --- /dev/null |
| +++ b/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader_unittest.cc |
| @@ -0,0 +1,309 @@ |
| +// Copyright 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h" |
| + |
| +#include <string> |
| + |
| +#include "base/callback.h" |
| +#include "base/file_util.h" |
| +#include "base/files/scoped_temp_dir.h" |
| +#include "base/message_loop/message_loop.h" |
| +#include "base/message_loop/message_loop_proxy.h" |
| +#include "base/path_service.h" |
| +#include "base/run_loop.h" |
| +#include "base/strings/stringprintf.h" |
| +#include "base/values.h" |
| +#include "base/version.h" |
| +#include "chrome/browser/chrome_notification_types.h" |
| +#include "chrome/browser/extensions/external_provider_impl.h" |
| +#include "chrome/browser/extensions/external_provider_interface.h" |
| +#include "chrome/browser/extensions/updater/extension_downloader.h" |
| +#include "chrome/browser/policy/cloud/mock_cloud_policy_store.h" |
| +#include "chrome/browser/policy/policy_map.h" |
| +#include "chrome/browser/policy/policy_types.h" |
| +#include "chrome/common/chrome_paths.h" |
| +#include "chrome/common/extensions/extension.h" |
| +#include "chrome/common/extensions/extension_constants.h" |
| +#include "chrome/test/base/testing_browser_process.h" |
| +#include "content/public/browser/notification_service.h" |
| +#include "content/public/browser/notification_source.h" |
| +#include "content/public/browser/render_process_host.h" |
| +#include "content/public/test/test_browser_thread_bundle.h" |
| +#include "content/public/test/test_utils.h" |
| +#include "extensions/common/manifest.h" |
| +#include "net/url_request/test_url_fetcher_factory.h" |
| +#include "net/url_request/url_fetcher_delegate.h" |
| +#include "net/url_request/url_request_context_getter.h" |
| +#include "net/url_request/url_request_test_util.h" |
| +#include "policy/policy_constants.h" |
| +#include "testing/gmock/include/gmock/gmock.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| +#include "url/gurl.h" |
| + |
| +using ::testing::InvokeWithoutArgs; |
| +using ::testing::Mock; |
| +using ::testing::_; |
| + |
| +namespace chromeos { |
| + |
| +namespace { |
| + |
| +const char kCacheDir[] = "cache"; |
| +const char kExtensionId[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf"; |
| +const char kExtensionUpdateManifest[] = |
| + "extensions/good_v1_update_manifest.xml"; |
| +const char kExtensionCRXSourceDir[] = "extensions"; |
| +const char kExtensionCRXFile[] = "good.crx"; |
| +const char kExtensionCRXVersion[] = "1.0.0.0"; |
| + |
| +class MockExternalPolicyProviderVisitor |
| + : public extensions::ExternalProviderInterface::VisitorInterface { |
| + public: |
| + MockExternalPolicyProviderVisitor(); |
| + virtual ~MockExternalPolicyProviderVisitor(); |
| + |
| + MOCK_METHOD6(OnExternalExtensionFileFound, |
| + bool(const std::string&, |
| + const base::Version*, |
| + const base::FilePath&, |
| + extensions::Manifest::Location, |
| + int, |
| + bool)); |
| + MOCK_METHOD5(OnExternalExtensionUpdateUrlFound, |
| + bool(const std::string&, |
| + const GURL&, |
| + extensions::Manifest::Location, |
| + int, |
| + bool)); |
| + MOCK_METHOD1(OnExternalProviderReady, |
| + void(const extensions::ExternalProviderInterface* provider)); |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(MockExternalPolicyProviderVisitor); |
| +}; |
| + |
| +MockExternalPolicyProviderVisitor::MockExternalPolicyProviderVisitor() { |
| +} |
| + |
| +MockExternalPolicyProviderVisitor::~MockExternalPolicyProviderVisitor() { |
| +} |
| + |
| +} // namespace |
| + |
| +class DeviceLocalAccountExternalPolicyLoaderTest : public testing::Test { |
| + protected: |
| + DeviceLocalAccountExternalPolicyLoaderTest(); |
| + virtual ~DeviceLocalAccountExternalPolicyLoaderTest(); |
| + |
| + virtual void SetUp() OVERRIDE; |
| + virtual void TearDown() OVERRIDE; |
| + |
| + void VerifyAndResetVisitorCallExpectations(); |
| + void SetForceInstallListPolicy(); |
| + |
| + content::TestBrowserThreadBundle thread_bundle_; |
|
Joao da Silva
2013/10/17 14:57:54
This probably won't be necessary if you just have
bartfab (slow)
2013/10/18 12:58:39
DeviceLocalAccountExternalPolicyLoader inherits fr
|
| + base::ScopedTempDir temp_dir_; |
| + base::FilePath cache_dir_; |
|
Joao da Silva
2013/10/17 14:57:54
#include
bartfab (slow)
2013/10/18 12:58:39
Already included by device_local_account_external_
|
| + policy::MockCloudPolicyStore store_; |
| + scoped_refptr<net::URLRequestContextGetter> request_context_getter_; |
| + base::FilePath test_dir_; |
| + |
| + scoped_refptr<DeviceLocalAccountExternalPolicyLoader> loader_; |
| + MockExternalPolicyProviderVisitor visitor_; |
| + scoped_ptr<extensions::ExternalProviderImpl> provider_; |
| +}; |
| + |
| +DeviceLocalAccountExternalPolicyLoaderTest:: |
| + DeviceLocalAccountExternalPolicyLoaderTest() |
| + : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) { |
| + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| + cache_dir_ = temp_dir_.path().Append(kCacheDir); |
| + ASSERT_TRUE(file_util::CreateDirectoryAndGetError(cache_dir_, NULL)); |
| +} |
| + |
| +DeviceLocalAccountExternalPolicyLoaderTest:: |
| + ~DeviceLocalAccountExternalPolicyLoaderTest() { |
| +} |
| + |
| +void DeviceLocalAccountExternalPolicyLoaderTest::SetUp() { |
| + request_context_getter_ = |
| + new net::TestURLRequestContextGetter(base::MessageLoopProxy::current()); |
| + TestingBrowserProcess::GetGlobal()->SetSystemRequestContext( |
| + request_context_getter_.get()); |
| + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir_)); |
| + |
| + loader_ = new DeviceLocalAccountExternalPolicyLoader(&store_, cache_dir_); |
| + provider_.reset(new extensions::ExternalProviderImpl( |
| + &visitor_, |
| + loader_, |
| + NULL, |
| + extensions::Manifest::EXTERNAL_POLICY, |
| + extensions::Manifest::EXTERNAL_POLICY_DOWNLOAD, |
| + extensions::Extension::NO_FLAGS)); |
| + |
| + content::RenderProcessHost::SetRunRendererInProcess(true); |
|
Joao da Silva
2013/10/17 14:57:54
Why?
Joao da Silva
2013/10/17 14:57:54
Why?
bartfab (slow)
2013/10/18 12:58:39
Without this, the extension system would try to un
|
| + |
| + VerifyAndResetVisitorCallExpectations(); |
| +} |
| + |
| +void DeviceLocalAccountExternalPolicyLoaderTest::TearDown() { |
| + content::RenderProcessHost::SetRunRendererInProcess(false); |
| + TestingBrowserProcess::GetGlobal()->SetSystemRequestContext(NULL); |
| +} |
| + |
| +void DeviceLocalAccountExternalPolicyLoaderTest:: |
| + VerifyAndResetVisitorCallExpectations() { |
| + Mock::VerifyAndClearExpectations(&visitor_); |
| + EXPECT_CALL(visitor_, OnExternalExtensionFileFound(_, _, _, _, _, _)) |
| + .Times(0); |
| + EXPECT_CALL(visitor_, OnExternalExtensionUpdateUrlFound(_, _, _, _, _)) |
| + .Times(0); |
| + EXPECT_CALL(visitor_, OnExternalProviderReady(_)) |
| + .Times(0); |
| +} |
| + |
| +void DeviceLocalAccountExternalPolicyLoaderTest::SetForceInstallListPolicy() { |
| + scoped_ptr<base::ListValue> forcelist(new base::ListValue); |
| + forcelist->AppendString("invalid"); |
| + forcelist->AppendString(base::StringPrintf( |
| + "%s;%s", |
| + kExtensionId, |
| + extension_urls::GetWebstoreUpdateUrl().spec().c_str())); |
| + store_.policy_map_.Set(policy::key::kExtensionInstallForcelist, |
| + policy::POLICY_LEVEL_MANDATORY, |
| + policy::POLICY_SCOPE_USER, |
| + forcelist.release(), |
| + NULL); |
| + store_.NotifyStoreLoaded(); |
| +} |
| + |
| +// Verifies that when the cache is not explicitly started, the loader does not |
| +// serve any extensions, even if the force-install list policy is set or a load |
| +// is manually requested. |
| +TEST_F(DeviceLocalAccountExternalPolicyLoaderTest, CacheNotStarted) { |
| + // Set the force-install list policy. |
| + SetForceInstallListPolicy(); |
| + |
| + // Manually request a load. |
| + loader_->StartLoading(); |
| + |
| + EXPECT_FALSE(loader_->IsCacheRunning()); |
| + EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting()); |
| +} |
| + |
| +// Verifies that the cache can be started and stopped correctly. |
| +TEST_F(DeviceLocalAccountExternalPolicyLoaderTest, ForceInstallListEmpty) { |
| + // Set an empty force-install list policy. |
| + store_.NotifyStoreLoaded(); |
| + |
| + // Start the cache. Verify that the loader announces an empty extension list. |
| + EXPECT_CALL(visitor_, OnExternalProviderReady(provider_.get())) |
| + .Times(1); |
| + loader_->StartCache(base::MessageLoopProxy::current()); |
| + VerifyAndResetVisitorCallExpectations(); |
| + |
| + // Stop the cache. Verify that the loader announces an empty extension list. |
| + EXPECT_CALL(visitor_, OnExternalProviderReady(provider_.get())) |
| + .Times(1); |
| + base::RunLoop run_loop; |
| + loader_->StopCache(run_loop.QuitClosure()); |
| + VerifyAndResetVisitorCallExpectations(); |
| + |
| + // Spin the loop until the cache shutdown callback is invoked. Verify that at |
| + // that point, no further file I/O tasks are pending. |
| + run_loop.Run(); |
| + EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting()); |
| +} |
| + |
| +// Verifies that when a force-install list policy referencing an extension is |
| +// set and the cache is started, the loader downloads, caches and serves the |
| +// extension. |
| +TEST_F(DeviceLocalAccountExternalPolicyLoaderTest, ForceInstallListSet) { |
| + // Set a force-install list policy that contains an invalid entry (which |
| + // should be ignored) and a valid reference to an extension. |
| + SetForceInstallListPolicy(); |
| + |
| + // Start the cache. |
| + loader_->StartCache(base::MessageLoopProxy::current()); |
| + |
| + // Spin the loop, allowing the loader to process the force-install list. |
| + // Verify that the loader announces an empty extension list. |
| + net::TestURLFetcherFactory factory; |
| + EXPECT_CALL(visitor_, OnExternalProviderReady(provider_.get())) |
| + .Times(1); |
| + base::MessageLoop::current()->RunUntilIdle(); |
| + |
| + // Verify that a downloader has started and is attempting to download an |
| + // update manifest. |
| + net::TestURLFetcher* fetcher = factory.GetFetcherByID( |
| + extensions::ExtensionDownloader::kManifestFetcherId); |
| + ASSERT_TRUE(fetcher); |
| + ASSERT_TRUE(fetcher->delegate()); |
| + |
| + // Return a manifest to the downloader. |
| + std::string manifest; |
| + EXPECT_TRUE(base::ReadFileToString(test_dir_.Append(kExtensionUpdateManifest), |
| + &manifest)); |
| + fetcher->set_response_code(200); |
| + fetcher->SetResponseString(manifest); |
| + fetcher->delegate()->OnURLFetchComplete(fetcher); |
| + |
| + // Wait for the manifest to be parsed. |
| + content::WindowedNotificationObserver( |
| + chrome::NOTIFICATION_EXTENSION_UPDATE_FOUND, |
| + content::NotificationService::AllSources()).Wait(); |
| + |
| + // Verify that the downloader is attempting to download a CRX file. |
| + fetcher = factory.GetFetcherByID( |
| + extensions::ExtensionDownloader::kExtensionFetcherId); |
| + ASSERT_TRUE(fetcher); |
| + ASSERT_TRUE(fetcher->delegate()); |
| + |
| + // Create a temporary CRX file and return its path to the downloader. |
| + EXPECT_TRUE(base::CopyFile( |
| + test_dir_.Append(kExtensionCRXSourceDir).Append(kExtensionCRXFile), |
| + temp_dir_.path().Append(kExtensionCRXFile))); |
| + fetcher->set_response_code(200); |
| + fetcher->SetResponseFilePath(temp_dir_.path().Append(kExtensionCRXFile)); |
| + fetcher->delegate()->OnURLFetchComplete(fetcher); |
| + |
| + // Spin the loop. Verify that the loader announces the presence of a new CRX |
| + // file, served from the cache directory. |
| + const base::FilePath cached_crx_path = cache_dir_.Append(base::StringPrintf( |
| + "%s-%s.crx", kExtensionId, kExtensionCRXVersion)); |
| + base::RunLoop cache_run_loop; |
| + EXPECT_CALL(visitor_, OnExternalExtensionFileFound( |
| + kExtensionId, |
| + _, |
| + cached_crx_path, |
| + extensions::Manifest::EXTERNAL_POLICY, |
| + _, |
| + _)); |
| + EXPECT_CALL(visitor_, OnExternalProviderReady(provider_.get())) |
| + .Times(1) |
| + .WillOnce(InvokeWithoutArgs(&cache_run_loop, &base::RunLoop::Quit)); |
| + cache_run_loop.Run(); |
| + VerifyAndResetVisitorCallExpectations(); |
| + |
| + // Verify that the CRX file actually exists in the cache directory and its |
| + // contents matches the file returned to the downloader. |
| + EXPECT_TRUE(base::ContentsEqual( |
| + test_dir_.Append(kExtensionCRXSourceDir).Append(kExtensionCRXFile), |
| + cached_crx_path)); |
| + |
| + // Stop the cache. Verify that the loader announces an empty extension list. |
| + EXPECT_CALL(visitor_, OnExternalProviderReady(provider_.get())) |
| + .Times(1); |
| + base::RunLoop shutdown_run_loop; |
| + loader_->StopCache(shutdown_run_loop.QuitClosure()); |
| + VerifyAndResetVisitorCallExpectations(); |
| + |
| + // Spin the loop until the cache shutdown callback is invoked. Verify that at |
| + // that point, no further file I/O tasks are pending. |
| + shutdown_run_loop.Run(); |
| + EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting()); |
| +} |
|
Joao da Silva
2013/10/17 14:57:54
nice test
|
| + |
| +} // namespace chromeos |