blob: e71691452b69085ee3075b98cb864457edec19cb [file] [log] [blame]
// Copyright (c) 2015 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 "base/prefs/testing_pref_service.h"
#include "base/test/test_simple_task_runner.h"
#include "base/time/time.h"
#include "chrome/browser/chromeos/policy/device_local_account.h"
#include "chrome/browser/chromeos/policy/device_status_collector.h"
#include "chrome/browser/chromeos/policy/status_uploader.h"
#include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h"
#include "chromeos/settings/cros_settings_names.h"
#include "components/policy/core/common/cloud/cloud_policy_client.h"
#include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
#include "components/policy/core/common/cloud/mock_device_management_service.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_utils.h"
#include "net/url_request/url_request_context_getter.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/user_activity/user_activity_detector.h"
#include "ui/events/platform/platform_event_source.h"
#include "ui/events/platform/platform_event_types.h"
#if defined(USE_X11)
#include "ui/events/devices/x11/device_data_manager_x11.h"
#include "ui/events/devices/x11/touch_factory_x11.h"
#include "ui/events/test/events_test_utils_x11.h"
#endif
#if defined(USE_OZONE)
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#endif
using ::testing::_;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::WithArgs;
namespace em = enterprise_management;
namespace {
class MockDeviceStatusCollector : public policy::DeviceStatusCollector {
public:
explicit MockDeviceStatusCollector(PrefService* local_state)
: DeviceStatusCollector(
local_state,
nullptr,
policy::DeviceStatusCollector::LocationUpdateRequester(),
policy::DeviceStatusCollector::VolumeInfoFetcher(),
policy::DeviceStatusCollector::CPUStatisticsFetcher(),
policy::DeviceStatusCollector::CPUTempFetcher()) {}
MOCK_METHOD1(GetDeviceStatus, bool(em::DeviceStatusReportRequest*));
MOCK_METHOD1(GetDeviceSessionStatus, bool(em::SessionStatusReportRequest*));
// Explicit mock implementation declared here, since gmock::Invoke can't
// handle returning non-moveable types like scoped_ptr.
scoped_ptr<policy::DeviceLocalAccount> GetAutoLaunchedKioskSessionInfo()
override {
return make_scoped_ptr(new policy::DeviceLocalAccount(
policy::DeviceLocalAccount::TYPE_KIOSK_APP, "account_id", "app_id",
"update_url"));
}
};
} // namespace
namespace policy {
class StatusUploaderTest : public testing::Test {
public:
StatusUploaderTest() : task_runner_(new base::TestSimpleTaskRunner()) {
DeviceStatusCollector::RegisterPrefs(prefs_.registry());
}
void SetUp() override {
#if defined(USE_X11)
ui::DeviceDataManagerX11::CreateInstance();
#endif
client_.SetDMToken("dm_token");
collector_.reset(new MockDeviceStatusCollector(&prefs_));
settings_helper_.ReplaceProvider(chromeos::kReportUploadFrequency);
}
void TearDown() override {
content::RunAllBlockingPoolTasksUntilIdle();
}
// Given a pending task to upload status, mocks out a server response.
void RunPendingUploadTaskAndCheckNext(const StatusUploader& uploader,
base::TimeDelta expected_delay) {
EXPECT_FALSE(task_runner_->GetPendingTasks().empty());
CloudPolicyClient::StatusCallback callback;
EXPECT_CALL(client_, UploadDeviceStatus(_, _, _))
.WillOnce(SaveArg<2>(&callback));
task_runner_->RunPendingTasks();
testing::Mock::VerifyAndClearExpectations(&device_management_service_);
// Make sure no status upload is queued up yet (since an upload is in
// progress).
EXPECT_TRUE(task_runner_->GetPendingTasks().empty());
// Now invoke the response.
callback.Run(true);
// Now that the previous request was satisfied, a task to do the next
// upload should be queued.
EXPECT_EQ(1U, task_runner_->GetPendingTasks().size());
CheckPendingTaskDelay(uploader, expected_delay);
}
void CheckPendingTaskDelay(const StatusUploader& uploader,
base::TimeDelta expected_delay) {
// The next task should be scheduled sometime between |last_upload| +
// |expected_delay| and |now| + |expected_delay|.
base::Time now = base::Time::NowFromSystemTime();
base::Time next_task = now + task_runner_->NextPendingTaskDelay();
EXPECT_LE(next_task, now + expected_delay);
EXPECT_GE(next_task, uploader.last_upload() + expected_delay);
}
content::TestBrowserThreadBundle thread_bundle_;
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
chromeos::ScopedCrosSettingsTestHelper settings_helper_;
scoped_ptr<MockDeviceStatusCollector> collector_;
ui::UserActivityDetector detector_;
MockCloudPolicyClient client_;
MockDeviceManagementService device_management_service_;
TestingPrefServiceSimple prefs_;
};
TEST_F(StatusUploaderTest, BasicTest) {
EXPECT_TRUE(task_runner_->GetPendingTasks().empty());
StatusUploader uploader(&client_, collector_.Pass(), task_runner_);
EXPECT_EQ(1U, task_runner_->GetPendingTasks().size());
// On startup, first update should happen immediately.
EXPECT_EQ(base::TimeDelta(), task_runner_->NextPendingTaskDelay());
}
TEST_F(StatusUploaderTest, DifferentFrequencyAtStart) {
// Keep a pointer to the mock collector because collector_ gets cleared
// when it is passed to the StatusUploader constructor below.
MockDeviceStatusCollector* const mock_collector = collector_.get();
const int new_delay = StatusUploader::kDefaultUploadDelayMs * 2;
settings_helper_.SetInteger(chromeos::kReportUploadFrequency, new_delay);
const base::TimeDelta expected_delay = base::TimeDelta::FromMilliseconds(
new_delay);
EXPECT_TRUE(task_runner_->GetPendingTasks().empty());
StatusUploader uploader(&client_, collector_.Pass(), task_runner_);
ASSERT_EQ(1U, task_runner_->GetPendingTasks().size());
// On startup, first update should happen immediately.
EXPECT_EQ(base::TimeDelta(), task_runner_->NextPendingTaskDelay());
EXPECT_CALL(*mock_collector, GetDeviceStatus(_)).WillRepeatedly(Return(true));
EXPECT_CALL(*mock_collector, GetDeviceSessionStatus(_)).WillRepeatedly(
Return(true));
// Second update should use the delay specified in settings.
RunPendingUploadTaskAndCheckNext(uploader, expected_delay);
}
TEST_F(StatusUploaderTest, ResetTimerAfterStatusCollection) {
// Keep a pointer to the mock collector because collector_ gets cleared
// when it is passed to the StatusUploader constructor below.
MockDeviceStatusCollector* const mock_collector = collector_.get();
StatusUploader uploader(&client_, collector_.Pass(), task_runner_);
EXPECT_CALL(*mock_collector, GetDeviceStatus(_)).WillRepeatedly(Return(true));
EXPECT_CALL(*mock_collector, GetDeviceSessionStatus(_)).WillRepeatedly(
Return(true));
const base::TimeDelta expected_delay = base::TimeDelta::FromMilliseconds(
StatusUploader::kDefaultUploadDelayMs);
RunPendingUploadTaskAndCheckNext(uploader, expected_delay);
// Handle this response also, and ensure new task is queued.
RunPendingUploadTaskAndCheckNext(uploader, expected_delay);
// Now that the previous request was satisfied, a task to do the next
// upload should be queued again.
EXPECT_EQ(1U, task_runner_->GetPendingTasks().size());
}
TEST_F(StatusUploaderTest, ResetTimerAfterFailedStatusCollection) {
// Keep a pointer to the mock collector because collector_ gets cleared
// when it is passed to the StatusUploader constructor below.
MockDeviceStatusCollector* mock_collector = collector_.get();
StatusUploader uploader(&client_, collector_.Pass(), task_runner_);
EXPECT_CALL(*mock_collector, GetDeviceStatus(_)).WillOnce(Return(false));
EXPECT_CALL(*mock_collector, GetDeviceSessionStatus(_)).WillOnce(
Return(false));
task_runner_->RunPendingTasks();
// Make sure the next status upload is queued up.
EXPECT_EQ(1U, task_runner_->GetPendingTasks().size());
const base::TimeDelta expected_delay = base::TimeDelta::FromMilliseconds(
StatusUploader::kDefaultUploadDelayMs);
CheckPendingTaskDelay(uploader, expected_delay);
}
TEST_F(StatusUploaderTest, ChangeFrequency) {
// Keep a pointer to the mock collector because collector_ gets cleared
// when it is passed to the StatusUploader constructor below.
MockDeviceStatusCollector* const mock_collector = collector_.get();
StatusUploader uploader(&client_, collector_.Pass(), task_runner_);
EXPECT_CALL(*mock_collector, GetDeviceStatus(_)).WillRepeatedly(Return(true));
EXPECT_CALL(*mock_collector, GetDeviceSessionStatus(_)).WillRepeatedly(
Return(true));
// Change the frequency. The new frequency should be reflected in the timing
// used for the next callback.
const int new_delay = StatusUploader::kDefaultUploadDelayMs * 2;
settings_helper_.SetInteger(chromeos::kReportUploadFrequency, new_delay);
const base::TimeDelta expected_delay = base::TimeDelta::FromMilliseconds(
new_delay);
RunPendingUploadTaskAndCheckNext(uploader, expected_delay);
}
#if defined(USE_X11) || defined(USE_OZONE)
TEST_F(StatusUploaderTest, NoUploadAfterUserInput) {
StatusUploader uploader(&client_, collector_.Pass(), task_runner_);
// Should allow data upload before there is user input.
EXPECT_TRUE(uploader.IsSessionDataUploadAllowed());
// Now mock user input, and no session data should be allowed.
#if defined(USE_X11)
ui::ScopedXI2Event native_event;
const int kPointerDeviceId = 10;
std::vector<int> device_list;
device_list.push_back(kPointerDeviceId);
ui::TouchFactory::GetInstance()->SetPointerDeviceForTest(device_list);
native_event.InitGenericButtonEvent(
kPointerDeviceId, ui::ET_MOUSE_PRESSED, gfx::Point(),
ui::EF_LEFT_MOUSE_BUTTON | ui::EF_CONTROL_DOWN);
#elif defined(USE_OZONE)
ui::MouseEvent e(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
ui::EventTimeForNow(), 0, 0);
const ui::PlatformEvent& native_event = &e;
#endif
ui::UserActivityDetector::Get()->DidProcessEvent(native_event);
EXPECT_FALSE(uploader.IsSessionDataUploadAllowed());
}
#endif
TEST_F(StatusUploaderTest, NoUploadAfterVideoCapture) {
StatusUploader uploader(&client_, collector_.Pass(), task_runner_);
// Should allow data upload before there is video capture.
EXPECT_TRUE(uploader.IsSessionDataUploadAllowed());
// Now mock video capture, and no session data should be allowed.
MediaCaptureDevicesDispatcher::GetInstance()->OnMediaRequestStateChanged(
0, 0, 0, GURL("http://www.google.com"),
content::MEDIA_DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_OPENING);
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(uploader.IsSessionDataUploadAllowed());
}
} // namespace policy