Chromium Code Reviews| Index: chrome/browser/policy/enterprise_metrics_unittest.cc |
| diff --git a/chrome/browser/policy/enterprise_metrics_unittest.cc b/chrome/browser/policy/enterprise_metrics_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..9c148ee1d0463be5aa661877596dbc2e3455a9be |
| --- /dev/null |
| +++ b/chrome/browser/policy/enterprise_metrics_unittest.cc |
| @@ -0,0 +1,835 @@ |
| +// Copyright (c) 2011 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. |
| + |
| +// These tests run in a child process because they depend on the static |
| +// initialization of the UMA counters. Those depend on a singleton instance of |
| +// base::StatisticsRecorder, which isn't available for unit_tests. Creating |
| +// one just for a couple of tests could lead to problems with other tests that |
| +// also depend on the base::StatisticsRecorder; basically, each statically |
| +// initialized UMA counter will belong to the StatisticsRecorder that exists |
| +// on the first execution of the function that contains the counter. Since we |
| +// can't make sure we are the first invokers of that function, we spawn a |
| +// child process instead that will create the StatisticsRecorder on its entry |
| +// function. |
|
gfeher
2011/07/15 12:21:34
I am going to contradict one of my comments in our
Joao da Silva
2011/07/18 08:45:10
As discussed offline, the out-of-process tests wer
|
| + |
| +#include <vector> |
| + |
| +#include "base/file_util.h" |
| +#include "base/message_loop.h" |
| +#include "base/metrics/histogram.h" |
| +#include "base/scoped_temp_dir.h" |
| +#include "base/test/multiprocess_test.h" |
| +#include "base/time.h" |
| +#include "chrome/browser/policy/cloud_policy_controller.h" |
| +#include "chrome/browser/policy/cloud_policy_data_store.h" |
| +#include "chrome/browser/policy/device_management_backend.h" |
| +#include "chrome/browser/policy/device_management_backend_mock.h" |
| +#include "chrome/browser/policy/device_management_service.h" |
| +#include "chrome/browser/policy/device_token_fetcher.h" |
| +#include "chrome/browser/policy/enterprise_metrics.h" |
| +#include "chrome/browser/policy/policy_notifier.h" |
| +#include "chrome/browser/policy/proto/device_management_backend.pb.h" |
| +#include "chrome/browser/policy/proto/device_management_local.pb.h" |
| +#include "chrome/browser/policy/user_policy_cache.h" |
| +#include "chrome/browser/policy/user_policy_disk_cache.h" |
| +#include "chrome/browser/policy/user_policy_token_cache.h" |
| +#include "content/browser/browser_thread.h" |
| +#include "net/url_request/url_request_status.h" |
| +#include "testing/gmock/include/gmock/gmock.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| +#include "testing/multiprocess_func_list.h" |
| + |
| +#if defined(OS_CHROMEOS) |
| +#include "chrome/browser/chromeos/cros/mock_cryptohome_library.h" |
| +#include "chrome/browser/chromeos/login/signed_settings.h" |
| +#include "chrome/browser/chromeos/login/signed_settings_helper.h" |
| +#include "chrome/browser/policy/device_policy_cache.h" |
| +#include "chrome/browser/policy/enterprise_install_attributes.h" |
| +#endif |
| + |
| +namespace policy { |
| + |
| +namespace em = enterprise_management; |
| + |
| +class EnterpriseMetricsTest : public base::MultiProcessTest { |
| + protected: |
| + EnterpriseMetricsTest() {} |
| + |
| + void TestSubProcess(const std::string& child_name); |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(EnterpriseMetricsTest); |
| +}; |
| + |
| +void EnterpriseMetricsTest::TestSubProcess(const std::string& child_name) { |
| + base::ProcessHandle handle = SpawnChild(child_name, false); |
| + ASSERT_TRUE(handle); |
| + int exit_code = 0; |
| + EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code)); |
| + EXPECT_EQ(exit_code, 0); |
| +} |
| + |
| +TEST_F(EnterpriseMetricsTest, TokenFetch) { |
| + TestSubProcess("enterprise_metrics_token_fetch"); |
| +} |
| + |
| +TEST_F(EnterpriseMetricsTest, TokenStorage) { |
| + TestSubProcess("enterprise_metrics_token_storage"); |
| +} |
| + |
| +TEST_F(EnterpriseMetricsTest, PolicyFetch) { |
| + TestSubProcess("enterprise_metrics_policy_fetch"); |
| +} |
| + |
| +TEST_F(EnterpriseMetricsTest, UserPolicyStorage) { |
| + TestSubProcess("enterprise_metrics_user_policy_storage"); |
| +} |
| + |
| +#if defined(OS_CHROMEOS) |
| + |
| +TEST_F(EnterpriseMetricsTest, DevicePolicyStorage) { |
| + TestSubProcess("enterprise_metrics_device_policy_storage"); |
| +} |
| + |
| +#endif |
| + |
| +// Tests in child processes have to return a non-zero value to signal that they |
| +// failed. These macros are used to return the appropriate value. |
| + |
| +// MULTIPROCESS_TEST_MAIN defines a function that returns an int, while |
| +// ASSERT_* macros return void, so they can't be used. Use this macro after |
| +// an EXPECT_* call that can't fail instead. |
| +#define RETURN_IF_FAILED() \ |
| + do { \ |
| + if (testing::Test::HasFailure()) \ |
| + return 1; \ |
| + } while (0) |
| + |
| +#define RETURN_CHECK_FAILED() \ |
| + return testing::Test::HasFailure() ? 1 : 0 |
| + |
| +namespace { |
| + |
| +using testing::_; |
| +using testing::AnyNumber; |
| +using testing::DoAll; |
| +using testing::Return; |
| +using testing::SetArgumentPointee; |
| + |
| +class MockDeviceManagementService : public DeviceManagementService { |
|
gfeher
2011/07/15 12:21:34
Have you considered reusing the existing MockDevic
Joao da Silva
2011/07/18 08:45:10
They are indeed different, wdyt of the merged vers
|
| + public: |
| + MockDeviceManagementService() |
| + : DeviceManagementService(""), |
| + response_code_(-1) { |
| + } |
| + |
| + virtual void StartJob(DeviceManagementJob* job) OVERRIDE { |
| + job->HandleResponse(status_, response_code_, cookies_, data_); |
| + } |
| + |
| + void set_url_request_status(const net::URLRequestStatus& status) { |
| + status_ = status; |
| + } |
| + |
| + void set_response_code(int response_code) { |
| + response_code_ = response_code; |
| + } |
| + |
| + void set_cookies(const net::ResponseCookies& cookies) { |
| + cookies_ = cookies; |
| + } |
| + |
| + void set_data(const std::string& data) { |
| + data_ = data; |
| + } |
| + |
| + private: |
| + DeviceManagementJob* job_; |
| + net::URLRequestStatus status_; |
| + int response_code_; |
| + net::ResponseCookies cookies_; |
| + std::string data_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(MockDeviceManagementService); |
| +}; |
| + |
| +class MockTokenAvailableObserver |
| + : public policy::CloudPolicyDataStore::Observer { |
| + public: |
| + MockTokenAvailableObserver() {} |
| + virtual ~MockTokenAvailableObserver() {} |
| + |
| + MOCK_METHOD0(OnDeviceTokenChanged, void()); |
| + MOCK_METHOD0(OnCredentialsChanged, void()); |
| + MOCK_METHOD0(OnDataStoreGoingAway, void()); |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(MockTokenAvailableObserver); |
| +}; |
| + |
| +#if defined(OS_CHROMEOS) |
| + |
| +class MockSignedSettingsHelper : public chromeos::SignedSettingsHelper { |
| + public: |
| + MockSignedSettingsHelper() {} |
| + virtual ~MockSignedSettingsHelper() {} |
| + |
| + MOCK_METHOD2(StartCheckWhitelistOp, |
| + void(const std::string& email, Callback*)); |
| + MOCK_METHOD3(StartWhitelistOp, |
| + void(const std::string&, bool, Callback*)); |
| + MOCK_METHOD3(StartStorePropertyOp, |
| + void(const std::string&, const std::string&, Callback*)); |
| + MOCK_METHOD2(StartRetrieveProperty, |
| + void(const std::string&, Callback*)); |
| + MOCK_METHOD2(StartStorePolicyOp, |
| + void(const em::PolicyFetchResponse&, Callback*)); |
| + MOCK_METHOD1(StartRetrievePolicyOp, void(Callback* callback)); |
| + MOCK_METHOD1(CancelCallback, void(Callback*)); |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(MockSignedSettingsHelper); |
| +}; |
| + |
| +ACTION_P(MockSignedSettingsHelperStorePolicy, status_code) { |
| + arg1->OnStorePolicyCompleted(status_code); |
| +} |
| + |
| +class TestInstallAttributes { |
| + public: |
| + explicit TestInstallAttributes(const std::string& user) |
| + : user_(user), |
| + owned_("true"), |
| + install_attributes_(&mock_cryptohome_library_) { |
| + EXPECT_CALL(mock_cryptohome_library_, InstallAttributesIsReady()) |
| + .WillOnce(Return(true)); |
| + EXPECT_CALL(mock_cryptohome_library_, InstallAttributesIsInvalid()) |
| + .WillOnce(Return(false)); |
| + EXPECT_CALL(mock_cryptohome_library_, InstallAttributesIsFirstInstall()) |
| + .WillOnce(Return(false)); |
| + EXPECT_CALL(mock_cryptohome_library_, |
| + InstallAttributesGet("enterprise.owned", _)) |
| + .WillOnce(DoAll(SetArgumentPointee<1>(owned_), |
| + Return(true))); |
| + EXPECT_CALL(mock_cryptohome_library_, |
| + InstallAttributesGet("enterprise.user", _)) |
| + .WillOnce(DoAll(SetArgumentPointee<1>(user_), |
| + Return(true))); |
| + } |
| + |
| + EnterpriseInstallAttributes* install_attributes() { |
| + return &install_attributes_; |
| + } |
| + |
| + private: |
| + std::string user_; |
| + std::string owned_; |
| + chromeos::MockCryptohomeLibrary mock_cryptohome_library_; |
| + EnterpriseInstallAttributes install_attributes_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(TestInstallAttributes); |
| +}; |
| + |
| +#endif |
| + |
| +// A helper class for out-of-process tests. |
| +class MetricsTest { |
|
gfeher
2011/07/15 12:21:34
Maybe call it MetricsTestHelper?
Joao da Silva
2011/07/18 08:45:10
Obsolete.
|
| + public: |
| + explicit MetricsTest(const std::string& metric_name) |
| + : ui_thread_(BrowserThread::UI, &loop_), |
| + file_thread_(BrowserThread::FILE, &loop_), |
| + metric_name_(metric_name) { |
| + EXPECT_TRUE(temp_user_data_dir_.CreateUniqueTempDir()); |
| + |
| + if (metric_name_ == kMetricToken) { |
| + samples_.resize(kMetricTokenSize, 0); |
| + } else if (metric_name_ == kMetricPolicy) { |
| + samples_.resize(kMetricPolicySize, 0); |
| + } else { |
| + NOTREACHED(); |
| + } |
| + } |
| + |
| + const FilePath& temp_dir() { |
| + return temp_user_data_dir_.path(); |
| + } |
| + |
| + void RunAllPending() { |
| + loop_.RunAllPending(); |
| + } |
| + |
| + void Done() { |
| + RunAllPending(); |
| + CheckSamples("Done"); |
| + } |
| + |
| + void ExpectSample(int sample) { |
| + ASSERT_GE(sample, 0); |
| + ASSERT_LT(sample, (int) samples_.size()); |
| + samples_[sample]++; |
| + } |
| + |
| + void CheckSamples(const std::string& test_case) { |
| + bool expects_samples = false; |
| + for (size_t i = 0; i < samples_.size(); ++i) { |
| + if (samples_[i] > 0) { |
| + expects_samples = true; |
| + break; |
| + } |
| + } |
| + |
| + // The histogram won't be available until the first sample is measured. |
| + base::Histogram* histogram = NULL; |
| + if (!expects_samples) { |
| + EXPECT_FALSE(base::StatisticsRecorder::FindHistogram(metric_name_, |
| + &histogram)); |
| + return; |
| + } |
| + |
| + EXPECT_TRUE(base::StatisticsRecorder::FindHistogram(metric_name_, |
| + &histogram)); |
| + ASSERT_TRUE(histogram != NULL); |
| + |
| + base::Histogram::SampleSet samples; |
| + histogram->SnapshotSample(&samples); |
| + |
| + size_t sum = 0; |
| + for (size_t i = 0; i < samples_.size(); ++i) { |
| + EXPECT_EQ(samples_[i], samples.counts(i)) |
| + << "Mismatch for " << test_case << ", i is " << i; |
| + sum += samples_[i]; |
| + } |
| + EXPECT_EQ(sum, (size_t) samples.TotalCount()); |
| + } |
| + |
| + private: |
| + base::StatisticsRecorder statistics_recorder_; |
| + MessageLoop loop_; |
| + ScopedTempDir temp_user_data_dir_; |
| + BrowserThread ui_thread_; |
| + BrowserThread file_thread_; |
| + std::string metric_name_; |
| + std::vector<int> samples_; |
|
gfeher
2011/07/15 12:21:34
Call this expected_samples_?
Joao da Silva
2011/07/18 08:45:10
Done.
|
| + |
| + DISALLOW_COPY_AND_ASSIGN(MetricsTest); |
| +}; |
| + |
| +} // namespace |
| + |
| +MULTIPROCESS_TEST_MAIN(enterprise_metrics_token_fetch) { |
| + MetricsTest test(kMetricToken); |
| + RETURN_IF_FAILED(); |
| + |
| + MockDeviceManagementService service; |
| + service.ScheduleInitialization(0); |
| + test.RunAllPending(); |
| + scoped_ptr<DeviceManagementBackend> backend(service.CreateBackend()); |
| + |
| + em::DeviceRegisterRequest request; |
| + DeviceRegisterResponseDelegateMock delegate; |
| + EXPECT_CALL(delegate, OnError(_)).Times(AnyNumber()); |
| + EXPECT_CALL(delegate, HandleRegisterResponse(_)).Times(AnyNumber()); |
| + net::URLRequestStatus status; |
| + |
| + // Test failed requests. |
| + status.set_status(net::URLRequestStatus::FAILED); |
| + service.set_url_request_status(status); |
| + test.ExpectSample(kMetricTokenFetchRequested); |
| + test.ExpectSample(kMetricTokenFetchRequestFailed); |
| + backend->ProcessRegisterRequest("token", "testid", request, &delegate); |
| + test.CheckSamples("FailedRequest"); |
| + |
| + // Test invalid data. |
| + std::string data("\xff"); |
| + status.set_status(net::URLRequestStatus::SUCCESS); |
| + service.set_url_request_status(status); |
| + service.set_response_code(200); |
| + service.set_data(data); |
| + test.ExpectSample(kMetricTokenFetchRequested); |
| + test.ExpectSample(kMetricTokenFetchBadResponse); |
| + backend->ProcessRegisterRequest("token", "testid", request, &delegate); |
| + test.CheckSamples("BadData"); |
| + |
| + // Test various error cases. |
| + struct { |
| + const char* test_case; |
| + int error_code; |
| + MetricToken sample; |
| + } cases[] = { |
| + { "400", 400, kMetricTokenFetchRequestFailed }, |
| + { "401", 401, kMetricTokenFetchServerFailed }, |
| + { "403", 403, kMetricTokenFetchManagementNotSupported }, |
| + { "404", 404, kMetricTokenFetchServerFailed }, |
| + { "410", 410, kMetricTokenFetchDeviceNotFound }, |
| + { "412", 412, kMetricTokenFetchServerFailed }, |
| + { "500", 500, kMetricTokenFetchServerFailed }, |
| + { "503", 503, kMetricTokenFetchServerFailed }, |
| + { "902", 902, kMetricTokenFetchServerFailed }, |
| + { "491", 491, kMetricTokenFetchServerFailed }, |
| + { "901", 901, kMetricTokenFetchDeviceNotFound }, |
| + }; |
| + |
| + service.set_data(std::string()); |
| + |
| + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { |
| + service.set_response_code(cases[i].error_code); |
| + test.ExpectSample(kMetricTokenFetchRequested); |
| + test.ExpectSample(cases[i].sample); |
| + backend->ProcessRegisterRequest("token", "testid", request, &delegate); |
| + test.CheckSamples(cases[i].test_case); |
| + } |
| + |
| + // Test successful token retrieval. |
| + service.set_response_code(200); |
| + test.ExpectSample(kMetricTokenFetchRequested); |
| + test.ExpectSample(kMetricTokenFetchResponseReceived); |
| + backend->ProcessRegisterRequest("token", "testid", request, &delegate); |
| + test.CheckSamples("ResponseReceived"); |
| + |
| + // Test token fetcher. |
| + UserPolicyCache cache(test.temp_dir().AppendASCII("FetchTokenTest")); |
| + scoped_ptr<CloudPolicyDataStore> data_store; |
| + data_store.reset(CloudPolicyDataStore::CreateForUserPolicies()); |
| + data_store->SetupForTesting("", "fake_device_id", "fake_user_name", |
| + "fake_auth_token", true); |
| + PolicyNotifier notifier; |
| + DeviceTokenFetcher fetcher(&service, &cache, data_store.get(), ¬ifier); |
| + |
| + MockTokenAvailableObserver observer; |
| + data_store->AddObserver(&observer); |
| + EXPECT_CALL(observer, OnDeviceTokenChanged()).Times(1); |
| + |
| + em::DeviceManagementResponse response; |
| + response.mutable_register_response()->set_device_management_token("token"); |
| + response.SerializeToString(&data); |
| + service.set_data(data); |
| + |
| + fetcher.FetchToken(); |
| + |
| + test.ExpectSample(kMetricTokenFetchRequested); |
| + test.ExpectSample(kMetricTokenFetchResponseReceived); |
| + test.ExpectSample(kMetricTokenFetchOK); |
| + test.CheckSamples("FetchOK"); |
| + |
| + // Cleanup. |
| + data_store->RemoveObserver(&observer); |
| + |
| + test.Done(); |
| + RETURN_CHECK_FAILED(); |
| +} |
| + |
| +MULTIPROCESS_TEST_MAIN(enterprise_metrics_token_storage) { |
| + MetricsTest test(kMetricToken); |
| + RETURN_IF_FAILED(); |
| + |
| + FilePath path = test.temp_dir().AppendASCII("StoreTokenTest"); |
| + |
| + scoped_ptr<CloudPolicyDataStore> data_store; |
| + data_store.reset(CloudPolicyDataStore::CreateForUserPolicies()); |
| + data_store->SetupForTesting("", "fake_device_id", "fake_user_name", |
| + "fake_auth_token", false); |
| + UserPolicyTokenCache cache(data_store.get(), path); |
| + |
| + // Try loading a non-existing file first. |
| + cache.Load(); |
| + test.RunAllPending(); |
| + // No samples expected. |
| + test.CheckSamples("LoadEmpty"); |
| + |
| + // Try loading an invalid file. |
| + std::string data("\xff"); |
| + int result = file_util::WriteFile(path, data.c_str(), data.size()); |
| + EXPECT_EQ((int) data.size(), result); |
| + RETURN_IF_FAILED(); |
| + |
| + // Make the data store expect a load from cache again. |
| + data_store->SetupForTesting("", "fake_device_id", "fake_user_name", |
| + "fake_auth_token", false); |
| + cache.Load(); |
| + test.RunAllPending(); |
| + test.ExpectSample(kMetricTokenLoadFailed); |
| + test.CheckSamples("LoadFailed"); |
| + |
| + // Test storing a valid cache. |
| + data_store->SetupForTesting("token", "fake_device_id", "fake_user_name", |
| + "fake_auth_token", false); |
| + cache.OnDeviceTokenChanged(); |
| + test.RunAllPending(); |
| + test.ExpectSample(kMetricTokenStoreSucceeded); |
| + test.CheckSamples("StoreSucceeded"); |
| + |
| + // Test loading a valid cache. |
| + // Make the data store expect a load from cache again. |
| + data_store->SetupForTesting("", "fake_device_id", "fake_user_name", |
| + "fake_auth_token", false); |
| + cache.Load(); |
| + test.RunAllPending(); |
| + test.ExpectSample(kMetricTokenLoadSucceeded); |
| + test.CheckSamples("LoadSucceeded"); |
| + |
| + test.Done(); |
| + RETURN_CHECK_FAILED(); |
| +} |
| + |
| +MULTIPROCESS_TEST_MAIN(enterprise_metrics_policy_fetch) { |
| + MetricsTest test(kMetricPolicy); |
| + RETURN_IF_FAILED(); |
| + |
| + MockDeviceManagementService service; |
| + service.ScheduleInitialization(0); |
| + test.RunAllPending(); |
| + scoped_ptr<DeviceManagementBackend> backend(service.CreateBackend()); |
| + |
| + em::DevicePolicyRequest request; |
| + DevicePolicyResponseDelegateMock delegate; |
| + EXPECT_CALL(delegate, OnError(_)).Times(AnyNumber()); |
| + EXPECT_CALL(delegate, HandlePolicyResponse(_)).Times(AnyNumber()); |
| + net::URLRequestStatus status; |
| + |
| + // Test failed requests. |
| + status.set_status(net::URLRequestStatus::FAILED); |
| + service.set_url_request_status(status); |
| + test.ExpectSample(kMetricPolicyFetchRequested); |
| + test.ExpectSample(kMetricPolicyFetchRequestFailed); |
| + backend->ProcessPolicyRequest("token", "testid", request, &delegate); |
| + test.CheckSamples("FailedRequest"); |
| + |
| + // Test invalid data. |
| + std::string data("\xff"); |
| + status.set_status(net::URLRequestStatus::SUCCESS); |
| + service.set_url_request_status(status); |
| + service.set_response_code(200); |
| + service.set_data(data); |
| + test.ExpectSample(kMetricPolicyFetchRequested); |
| + test.ExpectSample(kMetricPolicyFetchBadResponse); |
| + backend->ProcessPolicyRequest("token", "testid", request, &delegate); |
| + test.CheckSamples("BadData"); |
| + |
| + // Test various error cases. |
| + struct { |
| + const char* test_case; |
| + int error_code; |
| + MetricPolicy sample; |
| + } cases[] = { |
| + { "400", 400, kMetricPolicyFetchRequestFailed }, |
| + { "401", 401, kMetricPolicyFetchInvalidToken }, |
| + { "403", 403, kMetricPolicyFetchServerFailed }, |
| + { "404", 404, kMetricPolicyFetchServerFailed }, |
| + { "410", 410, kMetricPolicyFetchServerFailed }, |
| + { "412", 412, kMetricPolicyFetchServerFailed }, |
| + { "500", 500, kMetricPolicyFetchServerFailed }, |
| + { "503", 503, kMetricPolicyFetchServerFailed }, |
| + { "902", 902, kMetricPolicyFetchNotFound }, |
| + { "491", 491, kMetricPolicyFetchServerFailed }, |
| + { "901", 901, kMetricPolicyFetchServerFailed }, |
| + }; |
| + |
| + service.set_data(std::string()); |
| + |
| + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { |
| + service.set_response_code(cases[i].error_code); |
| + test.ExpectSample(kMetricPolicyFetchRequested); |
| + test.ExpectSample(cases[i].sample); |
| + backend->ProcessPolicyRequest("token", "testid", request, &delegate); |
| + test.CheckSamples(cases[i].test_case); |
| + } |
| + |
| + // Test successful policy retrieval. |
| + service.set_response_code(200); |
| + test.ExpectSample(kMetricPolicyFetchRequested); |
| + test.ExpectSample(kMetricPolicyFetchResponseReceived); |
| + backend->ProcessPolicyRequest("token", "testid", request, &delegate); |
| + test.CheckSamples("ResponseReceived"); |
| + |
| + // Test fetching an invalid policy. |
| + UserPolicyCache cache(test.temp_dir().AppendASCII("UserPolicyCacheTest")); |
| + // This is to bypass the private method override in UserPolicyCache: |
| + UserPolicyDiskCache::Delegate* cache_as_delegate = |
| + implicit_cast<UserPolicyDiskCache::Delegate*>(&cache); |
| + |
| + em::CachedCloudPolicyResponse response; |
| + response.mutable_cloud_policy()->set_policy_data(data); |
| + cache_as_delegate->OnDiskCacheLoaded(response); |
| + test.ExpectSample(kMetricPolicyFetchInvalidPolicy); |
| + test.CheckSamples("InvalidPolicy"); |
| + |
| + // Test timestamp in future. |
| + em::PolicyData policy_data; |
| + base::TimeDelta timestamp = |
| + (base::Time::NowFromSystemTime() + base::TimeDelta::FromDays(1000)) - |
| + base::Time::UnixEpoch(); |
| + policy_data.set_timestamp(timestamp.InMilliseconds()); |
| + policy_data.SerializeToString(&data); |
| + response.mutable_cloud_policy()->set_policy_data(data); |
| + cache_as_delegate->OnDiskCacheLoaded(response); |
| + test.ExpectSample(kMetricPolicyFetchTimestampInFuture); |
| + test.CheckSamples("TimestampInFuture"); |
| + |
| + // Test policy not modified. |
| + policy_data.set_timestamp(0); |
| + policy_data.SerializeToString(&data); |
| + response.mutable_cloud_policy()->set_policy_data(data); |
| + cache_as_delegate->OnDiskCacheLoaded(response); |
| + test.ExpectSample(kMetricPolicyFetchNotModified); |
| + test.CheckSamples("NotModified"); |
| + |
| + // Test fetch OK. |
| + cache.SetPolicy(response.cloud_policy()); |
| + test.ExpectSample(kMetricPolicyFetchOK); |
| + test.ExpectSample(kMetricPolicyFetchNotModified); |
| + test.CheckSamples("FetchOK"); |
| + // This also triggers a store. Update the expected samples. |
| + test.RunAllPending(); |
| + test.ExpectSample(kMetricPolicyStoreSucceeded); |
| + test.CheckSamples("FetchOKAndStore"); |
| + |
| + // Test bad responses. |
| + PolicyNotifier notifier; |
| + scoped_ptr<CloudPolicyDataStore> data_store; |
| + data_store.reset(CloudPolicyDataStore::CreateForUserPolicies()); |
| + data_store->SetupForTesting("", "fake_device_id", "fake_user_name", |
| + "fake_auth_token", true); |
| + CloudPolicyController controller(NULL, &cache, NULL, data_store.get(), |
| + ¬ifier); |
| + em::DevicePolicyResponse device_policy_response; |
| + controller.HandlePolicyResponse(device_policy_response); |
| + test.ExpectSample(kMetricPolicyFetchBadResponse); |
| + test.CheckSamples("BadResponse"); |
| + |
| + // More bad responses. |
| + em::PolicyFetchResponse* policy_fetch_response = |
| + device_policy_response.add_response(); |
| + policy_fetch_response->set_error_code( |
| + DeviceManagementBackend::kErrorServicePolicyNotFound); |
| + controller.HandlePolicyResponse(device_policy_response); |
| + test.ExpectSample(kMetricPolicyFetchBadResponse); |
| + test.CheckSamples("BadResponse2"); |
| + |
| + test.Done(); |
| + RETURN_CHECK_FAILED(); |
| +} |
| + |
| +MULTIPROCESS_TEST_MAIN(enterprise_metrics_user_policy_storage) { |
| + MetricsTest test(kMetricPolicy); |
| + RETURN_IF_FAILED(); |
| + |
| + FilePath path = test.temp_dir().AppendASCII("UserPolicyDiskCacheTest"); |
| + |
| + scoped_refptr<UserPolicyDiskCache> cache( |
| + new UserPolicyDiskCache(base::WeakPtr<UserPolicyDiskCache::Delegate>(), |
| + path)); |
| + |
| + // Load empty cache. |
| + cache->Load(); |
| + test.RunAllPending(); |
| + // No samples expected. |
| + test.CheckSamples("NoCache"); |
| + |
| + // Load an invalid cache. |
| + std::string data("\xff"); |
| + int result = file_util::WriteFile(path, data.c_str(), data.size()); |
| + EXPECT_EQ((int) data.size(), result); |
| + RETURN_IF_FAILED(); |
| + |
| + cache->Load(); |
| + test.RunAllPending(); |
| + test.ExpectSample(kMetricPolicyLoadFailed); |
| + test.CheckSamples("InvalidCache"); |
| + |
| + // Store a cache. |
| + em::CachedCloudPolicyResponse response; |
| + cache->Store(response); |
| + test.RunAllPending(); |
| + test.ExpectSample(kMetricPolicyStoreSucceeded); |
| + test.CheckSamples("StoreCache"); |
| + |
| + // Load a good cache. |
| + cache->Load(); |
| + test.RunAllPending(); |
| + test.ExpectSample(kMetricPolicyLoadSucceeded); |
| + test.CheckSamples("LoadCache"); |
| + |
| + test.Done(); |
| + RETURN_CHECK_FAILED(); |
| +} |
| + |
| +#if defined(OS_CHROMEOS) |
| + |
| +MULTIPROCESS_TEST_MAIN(enterprise_metrics_device_policy_storage) { |
| + MetricsTest test(kMetricPolicy); |
| + RETURN_IF_FAILED(); |
| + |
| + scoped_ptr<CloudPolicyDataStore> data_store; |
| + data_store.reset(CloudPolicyDataStore::CreateForUserPolicies()); |
| + // The DevicePolicyCache is reset to a new object to have |
| + // |starting_up_| set to true again, and test the loading path. |
| + scoped_ptr<DevicePolicyCache> device_policy_cache; |
| + em::PolicyFetchResponse response; |
| + |
| + // Test non-existing policy. |
| + device_policy_cache.reset(new DevicePolicyCache(data_store.get(), NULL)); |
| + data_store->SetupForTesting("", "id", "user", "token", false); |
| + device_policy_cache->OnRetrievePolicyCompleted( |
| + chromeos::SignedSettings::NOT_FOUND, response); |
| + // No samples expected. |
| + test.CheckSamples("NoPolicy"); |
| + |
| + // Test bad policy data. |
| + response.set_policy_data(std::string("\xff")); |
| + device_policy_cache.reset(new DevicePolicyCache(data_store.get(), NULL)); |
| + data_store->SetupForTesting("", "id", "user", "token", false); |
| + device_policy_cache->OnRetrievePolicyCompleted( |
| + chromeos::SignedSettings::SUCCESS, response); |
| + test.ExpectSample(kMetricPolicyLoadFailed); |
| + test.CheckSamples("BadPolicyData"); |
| + |
| + // Test more bad policy data. |
| + em::PolicyData policy_data; |
| + policy_data.set_request_token("token"); |
| + std::string policy_data_string; |
| + policy_data.SerializeToString(&policy_data_string); |
| + response.set_policy_data(policy_data_string); |
| + device_policy_cache.reset(new DevicePolicyCache(data_store.get(), NULL)); |
| + data_store->SetupForTesting("", "id", "user", "token", false); |
| + device_policy_cache->OnRetrievePolicyCompleted( |
| + chromeos::SignedSettings::SUCCESS, response); |
| + test.ExpectSample(kMetricPolicyLoadFailed); |
| + test.CheckSamples("BadPolicyData2"); |
| + |
| + // Test good policy data. |
| + policy_data.set_username("user"); |
| + policy_data.set_device_id("device_id"); |
| + policy_data.SerializeToString(&policy_data_string); |
| + response.set_policy_data(policy_data_string); |
| + device_policy_cache.reset(new DevicePolicyCache(data_store.get(), NULL)); |
| + data_store->SetupForTesting("", "id", "user", "token", false); |
| + device_policy_cache->OnRetrievePolicyCompleted( |
| + chromeos::SignedSettings::SUCCESS, response); |
| + test.ExpectSample(kMetricPolicyLoadSucceeded); |
| + // There is no policy data though. |
| + test.ExpectSample(kMetricPolicyFetchNotModified); |
| + test.CheckSamples("LoadSucceeded"); |
| + |
| + // Test storing the device policy. |
| + struct { |
| + const char* case_name; |
| + chromeos::SignedSettings::ReturnCode return_code; |
| + int expected_retrieve; |
| + int expected_sample; |
| + int expected_sample2; |
| + } cases[] = { |
| + { "StoreSuceeded", chromeos::SignedSettings::SUCCESS, 1, |
| + kMetricPolicyStoreSucceeded, -1 }, |
| + { "StoreBadSignature", chromeos::SignedSettings::BAD_SIGNATURE, 0, |
| + kMetricPolicyStoreFailed, kMetricPolicyFetchBadSignature }, |
| + { "StoreOtherFailed", chromeos::SignedSettings::OPERATION_FAILED, 0, |
| + kMetricPolicyStoreFailed, kMetricPolicyFetchOtherFailed }, |
| + }; |
| + |
| + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { |
| + TestInstallAttributes install_attributes("user"); |
| + MockSignedSettingsHelper mock_signed_settings_helper; |
| + |
| + device_policy_cache.reset( |
| + new DevicePolicyCache(data_store.get(), |
| + install_attributes.install_attributes(), &mock_signed_settings_helper)); |
| + |
| + EXPECT_CALL(mock_signed_settings_helper, StartStorePolicyOp(_, _)).WillOnce( |
| + MockSignedSettingsHelperStorePolicy(cases[i].return_code)); |
| + EXPECT_CALL(mock_signed_settings_helper, CancelCallback(_)).Times(2); |
| + EXPECT_CALL(mock_signed_settings_helper, |
| + StartRetrievePolicyOp(_)).Times(cases[i].expected_retrieve); |
| + |
| + // Make the cache have |starting_up_| set to false. |
| + data_store->SetupForTesting("", "id", "user", "token", false); |
| + device_policy_cache->OnRetrievePolicyCompleted( |
| + chromeos::SignedSettings::NOT_FOUND, response); |
| + // Now trigger the store. |
| + device_policy_cache->SetPolicy(response); |
| + test.ExpectSample(cases[i].expected_sample); |
| + if (cases[i].expected_sample2 >= 0) |
| + test.ExpectSample(cases[i].expected_sample2); |
| + test.CheckSamples(cases[i].case_name); |
| + |
| + // Cleanup while the MockSignedSettingsHelper is alive. |
| + device_policy_cache.reset(); |
| + } |
| + |
| + // Test setting policy on non-enterprise device. |
| + { |
| + EnterpriseInstallAttributes install_attributes(NULL); |
| + device_policy_cache.reset(new DevicePolicyCache(data_store.get(), |
| + &install_attributes)); |
| + // Make the cache have |starting_up_| set to false. |
| + data_store->SetupForTesting("", "id", "user", "token", false); |
| + device_policy_cache->OnRetrievePolicyCompleted( |
| + chromeos::SignedSettings::NOT_FOUND, response); |
| + // Now trigger the error. |
| + device_policy_cache->SetPolicy(response); |
| + test.ExpectSample(kMetricPolicyFetchNonEnterpriseDevice); |
| + test.CheckSamples("NonEnterprise"); |
| + } |
| + |
| + // Test user-mismatch between device and policy. |
| + { |
| + TestInstallAttributes install_attributes("bogus"); |
| + device_policy_cache.reset(new DevicePolicyCache(data_store.get(), |
| + install_attributes.install_attributes())); |
| + // Make the cache have |starting_up_| set to false. |
| + data_store->SetupForTesting("", "id", "user", "token", false); |
| + device_policy_cache->OnRetrievePolicyCompleted( |
| + chromeos::SignedSettings::NOT_FOUND, response); |
| + // Now trigger the store. |
| + device_policy_cache->SetPolicy(response); |
| + test.ExpectSample(kMetricPolicyFetchUserMismatch); |
| + test.CheckSamples("UserMismatch"); |
| + } |
| + |
| + // Test bad signature. |
| + device_policy_cache.reset(new DevicePolicyCache(data_store.get(), NULL)); |
| + // Make the cache have |starting_up_| set to false. |
| + data_store->SetupForTesting("", "id", "user", "token", false); |
| + device_policy_cache->OnRetrievePolicyCompleted( |
| + chromeos::SignedSettings::NOT_FOUND, response); |
| + // Now trigger the store. |
| + device_policy_cache->OnRetrievePolicyCompleted( |
| + chromeos::SignedSettings::BAD_SIGNATURE, response); |
| + test.ExpectSample(kMetricPolicyFetchBadSignature); |
| + test.CheckSamples("BadSignature"); |
| + |
| + // Test other failures. |
| + device_policy_cache.reset(new DevicePolicyCache(data_store.get(), NULL)); |
| + // Make the cache have |starting_up_| set to false. |
| + data_store->SetupForTesting("", "id", "user", "token", false); |
| + device_policy_cache->OnRetrievePolicyCompleted( |
| + chromeos::SignedSettings::NOT_FOUND, response); |
| + // Now trigger the store. |
| + device_policy_cache->OnRetrievePolicyCompleted( |
| + chromeos::SignedSettings::OPERATION_FAILED, response); |
| + test.ExpectSample(kMetricPolicyFetchOtherFailed); |
| + test.CheckSamples("BadSignature"); |
| + |
| + // Test fetching invalid policy. |
| + { |
| + TestInstallAttributes install_attributes("user"); |
| + device_policy_cache.reset(new DevicePolicyCache(data_store.get(), |
| + install_attributes.install_attributes())); |
| + // Make the cache have |starting_up_| set to false. |
| + data_store->SetupForTesting("", "id", "user", "token", false); |
| + device_policy_cache->OnRetrievePolicyCompleted( |
| + chromeos::SignedSettings::NOT_FOUND, response); |
| + // Now trigger the store. |
| + response.set_policy_data(std::string("\xff")); |
| + device_policy_cache->SetPolicy(response); |
| + test.ExpectSample(kMetricPolicyFetchInvalidPolicy); |
| + test.CheckSamples("UserMismatch"); |
| + } |
| + |
| + test.Done(); |
| + RETURN_CHECK_FAILED(); |
| +} |
| + |
| +#endif |
| + |
| +} // namespace policy |