[go: nahoru, domu]

blob: 40573bbf0e14c65607e572f9a115dc33237074f7 [file] [log] [blame]
// Copyright (c) 2012 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/ash/policy/status_collector/device_status_collector.h"
#include <stddef.h>
#include <stdint.h>
#include <iterator>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "ash/components/audio/cras_audio_handler.h"
#include "ash/components/disks/disk_mount_manager.h"
#include "ash/components/disks/mock_disk_mount_manager.h"
#include "ash/components/settings/cros_settings_names.h"
#include "ash/components/settings/timezone_settings.h"
#include "ash/components/tpm/stub_install_attributes.h"
#include "ash/constants/ash_features.h"
#include "base/bind.h"
#include "base/environment.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/path_service.h"
#include "base/ranges/algorithm.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/system/sys_info.h"
#include "base/test/scoped_chromeos_version_info.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_path_override.h"
#include "base/test/simple_test_clock.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/apps/app_service/publisher_host.h"
#include "chrome/browser/ash/app_mode/arc/arc_kiosk_app_manager.h"
#include "chrome/browser/ash/app_mode/kiosk_app_data.h"
#include "chrome/browser/ash/app_mode/kiosk_app_manager.h"
#include "chrome/browser/ash/app_mode/kiosk_cryptohome_remover.h"
#include "chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.h"
#include "chrome/browser/ash/crostini/crostini_pref_names.h"
#include "chrome/browser/ash/crostini/crostini_test_helper.h"
#include "chrome/browser/ash/guest_os/guest_os_registry_service.h"
#include "chrome/browser/ash/guest_os/guest_os_registry_service_factory.h"
#include "chrome/browser/ash/login/users/mock_user_manager.h"
#include "chrome/browser/ash/ownership/fake_owner_settings_service.h"
#include "chrome/browser/ash/policy/core/device_local_account.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/ash/settings/scoped_testing_cros_settings.h"
#include "chrome/browser/chrome_content_browser_client.h"
#include "chrome/browser/policy/profile_policy_connector.h"
#include "chrome/common/chrome_content_client.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/chrome_unit_test_suite.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "chromeos/dbus/attestation/attestation_client.h"
#include "chromeos/dbus/cicerone/cicerone_client.h"
#include "chromeos/dbus/concierge/concierge_client.h"
#include "chromeos/dbus/cros_disks/cros_disks_client.h"
#include "chromeos/dbus/cros_healthd/cros_healthd_client.h"
#include "chromeos/dbus/cros_healthd/fake_cros_healthd_client.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/power_manager/idle.pb.h"
#include "chromeos/dbus/seneschal/seneschal_client.h"
#include "chromeos/dbus/shill/shill_device_client.h"
#include "chromeos/dbus/shill/shill_ipconfig_client.h"
#include "chromeos/dbus/shill/shill_profile_client.h"
#include "chromeos/dbus/shill/shill_service_client.h"
#include "chromeos/dbus/tpm_manager/tpm_manager_client.h"
#include "chromeos/dbus/update_engine/fake_update_engine_client.h"
#include "chromeos/dbus/userdataauth/userdataauth_client.h"
#include "chromeos/dbus/vm_applications/apps.pb.h"
#include "chromeos/login/login_state/login_state.h"
#include "chromeos/network/network_handler.h"
#include "chromeos/network/network_handler_test_helper.h"
#include "chromeos/network/network_state.h"
#include "chromeos/network/network_state_handler.h"
#include "chromeos/system/fake_statistics_provider.h"
#include "components/account_id/account_id.h"
#include "components/ownership/mock_owner_key_util.h"
#include "components/policy/proto/device_management_backend.pb.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/testing_pref_service.h"
#include "components/services/app_service/public/cpp/app_registry_cache.h"
#include "components/services/app_service/public/cpp/app_types.h"
#include "components/services/app_service/public/cpp/features.h"
#include "components/session_manager/core/session_manager.h"
#include "components/upload_list/upload_list.h"
#include "components/user_manager/scoped_user_manager.h"
#include "components/user_manager/user_type.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_client.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_utils.h"
#include "mojo/core/embedder/embedder.h"
#include "storage/browser/file_system/external_mount_points.h"
#include "storage/browser/file_system/mount_points.h"
#include "storage/common/file_system/file_system_mount_option.h"
#include "storage/common/file_system/file_system_types.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
#include "ui/aura/env.h"
#include "ui/aura/test/test_windows.h"
using ::ash::disks::DiskMountManager;
using base::Time;
using base::test::ScopedChromeOSVersionInfo;
using ::testing::Return;
using ::testing::ReturnRef;
namespace em = enterprise_management;
namespace cros_healthd = chromeos::cros_healthd::mojom;
namespace {
// Test values for cros_healthd:
// Battery test values:
constexpr int kFakeBatteryCycleCount = 3;
constexpr int kExpectedBatteryVoltageNow = 12574; // (mV)
constexpr double kFakeBatteryVoltageNow =
kExpectedBatteryVoltageNow / 1000.0; // (V)
constexpr char kFakeBatteryVendor[] = "fake_battery_vendor";
constexpr char kFakeBatterySerial[] = "fake_battery_serial";
constexpr int kExpectedBatteryChargeFullDesign = 5275; // (mAh)
constexpr double kFakeBatteryChargeFullDesign =
kExpectedBatteryChargeFullDesign / 1000.0; // (Ah)
constexpr int kExpectedBatteryChargeFull = 5292; // (mAh)
constexpr double kFakeBatteryChargeFull =
kExpectedBatteryChargeFull / 1000.0; // (Ah)
constexpr int kExpectedBatteryVoltageMinDesign = 11550; // (mV)
constexpr double kFakeBatteryVoltageMinDesign =
kExpectedBatteryVoltageMinDesign / 1000.0; // (V)
constexpr char kFakeSmartBatteryManufactureDate[] = "2018-08-06";
constexpr int kFakeSmartBatteryTemperature = 3004;
constexpr int kZeroCInDeciKelvin = 2731;
constexpr char kFakeBatteryModel[] = "fake_battery_model";
constexpr int kExpectedBatteryChargeNow = 5281; // (mAh)
constexpr double kFakeBatteryChargeNow =
kExpectedBatteryChargeNow / 1000.0; // (Ah)
constexpr int kExpectedBatteryCurrentNow = 87659; // (mA)
constexpr double kFakeBatteryCurrentNow =
kExpectedBatteryCurrentNow / 1000.0; // (A)
constexpr char kFakeBatteryTechnology[] = "fake_battery_technology";
constexpr char kFakeBatteryStatus[] = "fake_battery_status";
// System test values:
const char kFakeFirstPowerDate[] = "2020-40";
const char kFakeManufactureDate[] = "2019-01-01";
const char kFakeSkuNumber[] = "ABCD&^A";
const char kFakeSerialNumber[] = "8607G03EDF";
constexpr char kFakeSystemModelName[] = "XX ModelName 007 XY";
constexpr char kFakeMarketingName[] = "Latitude 1234 Chromebook Enterprise";
constexpr char kFakeBiosVersion[] = "Google_BoardName.12200.68.0";
constexpr char kFakeBoardName[] = "BoardName";
constexpr char kFakeBoardVersion[] = "rev1234";
constexpr uint64_t kFakeChassisType = 9;
constexpr char kFakeProductName[] = "ProductName";
constexpr char kFakeVersionMilestone[] = "87";
constexpr char kFakeVersionBuildNumber[] = "13544";
constexpr char kFakeVersionPatchNumber[] = "59.0";
constexpr char kFakeVersionReleaseChannel[] = "stable-channel";
// System V2 test values:
constexpr char kFakeOsInfoCodeName[] = "OsInfo Code Name";
constexpr char kFakeOSInfoMarketingName[] = "OsInfo Marketing Name";
constexpr char kFakeOSInfoOemName[] = "OsInfo OEM Name";
constexpr cros_healthd::BootMode kFakeOsInfoBootMode =
cros_healthd::BootMode::kCrosSecure;
constexpr em::BootInfo::BootMethod kFakeOsInfoBootMethod =
em::BootInfo::CROS_SECURE;
constexpr char kFakeVpdInfoRegion[] = "VpdInfo Region";
constexpr char kFakeDmiInfoBiosVendor[] = "DMI Bios Vendor";
constexpr char kFakeDmiInfoBiosVersion[] = "DMI Bios Version";
constexpr char kFakeDmiInfoBoardName[] = "DMI Board Name";
constexpr char kFakeDmiInfoBoardVendor[] = "DMI Board Vendor";
constexpr char kFakeDmiInfoBoardVersion[] = "DMI Board Version";
constexpr char kFakeDmiInfoChassisVendor[] = "DMI Chassis Vendor";
constexpr uint64_t kFakeDmiInfoChassisType = 9;
constexpr char kFakeDmiInfoProductFamily[] = "DMI Product Family";
constexpr char kFakeDmiInfoSysVendor[] = "DMI System Vendor";
constexpr char kFakeDmiInfoProductName[] = "DMI Product Name";
constexpr char kFakeDmiInfoProductVersion[] = "DMI Product Version";
// CPU test values:
constexpr uint32_t kFakeNumTotalThreads = 8;
constexpr char kFakeModelName[] = "fake_cpu_model_name";
constexpr int32_t kFakeCpuTemperature = -189;
constexpr char kFakeCpuTemperatureLabel[] = "Fake CPU temperature";
constexpr cros_healthd::CpuArchitectureEnum kFakeMojoArchitecture =
cros_healthd::CpuArchitectureEnum::kX86_64;
constexpr em::CpuInfo::Architecture kFakeProtoArchitecture =
em::CpuInfo::X86_64;
constexpr bool kFakeKeylockerConfigurationState = false;
constexpr uint32_t kFakeMaxClockSpeed = 3400000;
constexpr uint32_t kFakeScalingMaxFrequency = 2700000;
constexpr uint32_t kFakeScalingCurFrequency = 2400000;
// Since this number is divided by the result of the sysconf(_SC_CLK_TCK)
// syscall, we need it to be 0 to avoid flaky tests,
constexpr uint64_t kFakeIdleTime = 0;
constexpr uint64_t kFakeUserTime = 789;
constexpr uint64_t kFakeSystemTime = 4680;
constexpr char kFakeCStateName[] = "fake_c_state_name";
constexpr uint64_t kFakeTimeInStateSinceLastBoot = 87;
// CPU Temperature test values:
constexpr int kFakeCpuTimestamp = 912;
// Storage test values:
constexpr char kFakeStoragePath[] = "fake_storage_path";
constexpr int kFakeStorageSize = 123;
constexpr char kFakeStorageType[] = "fake_storage_type";
constexpr uint8_t kFakeStorageManfid = 2;
constexpr char kFakeStorageName[] = "fake_storage_name";
constexpr int kFakeStorageSerial = 789;
constexpr uint64_t kFakeStorageBytesRead = 9070;
constexpr uint64_t kFakeStorageBytesWritten = 87653;
constexpr uint64_t kFakeStorageReadTimeSeconds = 23570;
constexpr uint64_t kFakeStorageWriteTimeSeconds = 5768;
constexpr uint64_t kFakeStorageIoTimeSeconds = 709;
constexpr uint64_t kFakeStorageDiscardTimeSeconds = 9869;
constexpr uint16_t kFakeOemid = 274;
constexpr uint64_t kFakePnm = 8321204;
constexpr uint8_t kFakePrv = 5;
constexpr uint64_t kFakeFwrev = 1704189236;
constexpr cros_healthd::StorageDevicePurpose kFakeMojoPurpose =
cros_healthd::StorageDevicePurpose::kBootDevice;
constexpr em::DiskInfo::DevicePurpose kFakeProtoPurpose =
em::DiskInfo::PURPOSE_BOOT;
// Timezone test values:
constexpr char kPosixTimezone[] = "MST7MDT,M3.2.0,M11.1.0";
constexpr char kTimezoneRegion[] = "America/Denver";
// Memory test values:
constexpr uint32_t kFakeTotalMemory = 1287312;
constexpr uint32_t kFakeFreeMemory = 981239;
constexpr uint32_t kFakeAvailableMemory = 98719321;
constexpr uint64_t kFakePageFaults = 896123761;
// Backlight test values:
constexpr char kFakeBacklightPath[] = "/sys/class/backlight/fake_backlight";
constexpr uint32_t kFakeMaxBrightness = 769;
constexpr uint32_t kFakeBrightness = 124;
// Fan test values:
constexpr uint32_t kFakeSpeedRpm = 1225;
// Stateful partition test values:
constexpr uint64_t kAvailableSpace = 777;
constexpr uint64_t kTotalSpace = 999;
constexpr char kFilesystem[] = "ext4";
constexpr char kMountSource[] = "/dev/mmcblk0p1";
// Bluetooth test values:
constexpr char kFakeBluetoothAdapterName[] = "Marty Byrde's BT Adapter";
constexpr char kFakeBluetoothAdapterAddress[] = "aa:bb:cc:dd:ee:ff";
constexpr bool kFakeBluetoothAdapterIsPowered = true;
constexpr uint32_t kFakeNumConnectedBluetoothDevices = 7;
// Tpm test values:
constexpr char kFakeTpmDidVid[] = "fake_tpm_did_vid";
// Bus Device test values:
constexpr uint8_t kFakeUnusedBusId = 1;
constexpr char kFakePciVendor[] = "pci_vendor";
constexpr char kFakePciProduct[] = "pci_product";
constexpr char kFakePciDriver[] = "pci_driver";
constexpr char kFakeUsbVendor[] = "usb_vendor";
constexpr char kFakeUsbProduct[] = "usb_product";
constexpr char kFakeUsbDriver0[] = "usb_driver_1";
constexpr char kFakeUsbDriver1[] = "usb_driver_2";
constexpr uint8_t kFakeUsbInterfaceNumber0 = 0;
constexpr uint8_t kFakeUsbInterfaceNumber1 = 1;
// Time delta representing 1 hour time interval.
constexpr base::TimeDelta kHour = base::Hours(1);
const int64_t kMillisecondsPerDay = Time::kMicrosecondsPerDay / 1000;
const char kKioskAccountId[] = "kiosk_user@localhost";
const char kArcKioskAccountId[] = "arc_kiosk_user@localhost";
const char kWebKioskAccountId[] = "web_kiosk_user@localhost";
const char kKioskAppId[] = "kiosk_app_id";
const char kArcKioskPackageName[] = "com.test.kioskapp";
const char kWebKioskAppUrl[] = "http://example.com";
const char kExternalMountPoint[] = "/a/b/c";
const char kPublicAccountId[] = "public_user@localhost";
const char kArcStatus[] = R"(
{
"applications":[
{
"packageName":"com.android.providers.telephony",
"versionName":"6.0.1",
"permissions":[ "android.permission.INTERNET" ]
}
],
"userEmail":"xxx@google.com"
})";
const char kDroidGuardInfo[] = "{\"droid_guard_info\":42}";
const char kShillFakeProfilePath[] = "/profile/user1/shill";
const char kShillFakeUserhash[] = "user1";
// Constants for Crostini reporting test cases:
const char kCrostiniUserEmail[] = "user0@managed.com";
const char kTerminaVmComponentVersion[] = "1.33.7";
const char kTerminaVmKernelVersion[] =
"4.19.56-05556-gca219a5b1086 #3 SMP PREEMPT Mon Jul 1 14:36:38 CEST 2019";
const char kActualLastLaunchTimeFormatted[] = "Sat, 1 Sep 2018 11:50:50 GMT";
const char kLastLaunchTimeWindowStartFormatted[] =
"Sat, 1 Sep 2018 00:00:00 GMT";
const int64_t kLastLaunchTimeWindowStartInJavaTime = 1535760000000;
const char kDefaultPlatformVersion[] = "1234.0.0";
// Constants for crash reporting test cases:
const char kTestUploadId[] = "0123456789abcdef";
const char kTestLocalID[] = "fedcba9876543210";
const char kTestCauseKernel[] = "kernel";
const char kTestCauseEC[] = "embedded-controller";
const char kTestCauseOther[] = "other";
class TestingDeviceStatusCollectorOptions {
public:
TestingDeviceStatusCollectorOptions() = default;
TestingDeviceStatusCollectorOptions(
const TestingDeviceStatusCollectorOptions&) = delete;
TestingDeviceStatusCollectorOptions& operator=(
const TestingDeviceStatusCollectorOptions&) = delete;
~TestingDeviceStatusCollectorOptions() = default;
policy::DeviceStatusCollector::VolumeInfoFetcher volume_info_fetcher;
policy::DeviceStatusCollector::CPUStatisticsFetcher cpu_fetcher;
policy::DeviceStatusCollector::CPUTempFetcher cpu_temp_fetcher;
policy::StatusCollector::AndroidStatusFetcher android_status_fetcher;
policy::DeviceStatusCollector::EMMCLifetimeFetcher emmc_lifetime_fetcher;
policy::DeviceStatusCollector::StatefulPartitionInfoFetcher
stateful_partition_info_fetcher;
policy::DeviceStatusCollector::GraphicsStatusFetcher graphics_status_fetcher;
policy::DeviceStatusCollector::CrashReportInfoFetcher
crash_report_info_fetcher;
std::unique_ptr<policy::AppInfoGenerator> app_info_generator;
};
class TestingDeviceStatusCollector : public policy::DeviceStatusCollector {
public:
// Note that that TpmStatusFetcher is null so the test exercises the
// production logic with fake tpm manager and attestation clients.
TestingDeviceStatusCollector(
PrefService* pref_service,
chromeos::system::StatisticsProvider* provider,
policy::ManagedSessionService* managed_session_service,
std::unique_ptr<TestingDeviceStatusCollectorOptions> options,
base::SimpleTestClock* clock)
: policy::DeviceStatusCollector(
pref_service,
provider,
managed_session_service,
options->volume_info_fetcher,
options->cpu_fetcher,
options->cpu_temp_fetcher,
options->android_status_fetcher,
policy::DeviceStatusCollector::TpmStatusFetcher(),
options->emmc_lifetime_fetcher,
options->stateful_partition_info_fetcher,
options->graphics_status_fetcher,
options->crash_report_info_fetcher,
clock),
test_clock_(*clock) {
// Set the baseline time to a fixed value (1 hour after day start) to
// prevent test flakiness due to a single activity period spanning two days.
test_clock_.SetNow(Time::Now().LocalMidnight() + kHour);
}
void Simulate(ui::IdleState* states, int len) {
for (int i = 0; i < len; i++) {
test_clock_.Advance(policy::DeviceStatusCollector::kIdlePollInterval);
ProcessIdleState(states[i]);
}
}
void set_max_stored_past_activity_interval(base::TimeDelta value) {
max_stored_past_activity_interval_ = value;
}
void set_max_stored_future_activity_interval(base::TimeDelta value) {
max_stored_future_activity_interval_ = value;
}
void set_kiosk_account(std::unique_ptr<policy::DeviceLocalAccount> account) {
kiosk_account_ = std::move(account);
}
std::unique_ptr<policy::DeviceLocalAccount> GetAutoLaunchedKioskSessionInfo()
override {
if (kiosk_account_)
return std::make_unique<policy::DeviceLocalAccount>(*kiosk_account_);
return nullptr;
}
std::string GetAppVersion(const std::string& app_id) override {
// Just return the app_id as the version - this makes it easy for tests
// to confirm that the correct app's version was requested.
return app_id;
}
std::string GetDMTokenForProfile(Profile* profile) const override {
// Return the profile user name (passed to CreateTestingProfile) to make it
// easy to confirm that the correct profile's DMToken was requested.
return profile->GetProfileUserName();
}
void RefreshSampleResourceUsage() {
SampleCpuUsage();
SampleMemoryUsage();
content::RunAllTasksUntilIdle();
}
protected:
void CheckIdleState() override {
// This should never be called in testing, as it results in a dbus call.
ADD_FAILURE();
}
private:
base::SimpleTestClock& test_clock_;
std::unique_ptr<policy::DeviceLocalAccount> kiosk_account_;
};
// Return the total number of active milliseconds contained in a device
// status report.
int64_t GetActiveMilliseconds(const em::DeviceStatusReportRequest& status) {
int64_t active_milliseconds = 0;
for (int i = 0; i < status.active_periods_size(); i++) {
active_milliseconds += status.active_periods(i).active_duration();
}
return active_milliseconds;
}
// Mock CPUStatisticsFetcher used to return an empty set of statistics.
std::string GetEmptyCPUStatistics() {
return std::string();
}
std::string GetFakeCPUStatistics(const std::string& fake) {
return fake;
}
// Mock VolumeInfoFetcher used to return empty VolumeInfo, to avoid warnings
// and test slowdowns from trying to fetch information about non-existent
// volumes.
std::vector<em::VolumeInfo> GetEmptyVolumeInfo(
const std::vector<std::string>& mount_points) {
return std::vector<em::VolumeInfo>();
}
std::vector<em::VolumeInfo> GetFakeVolumeInfo(
const std::vector<em::VolumeInfo>& volume_info,
const std::vector<std::string>& mount_points) {
EXPECT_EQ(volume_info.size(), mount_points.size());
// Make sure there's a matching mount point for every volume info.
for (const em::VolumeInfo& info : volume_info) {
bool found = false;
for (const std::string& mount_point : mount_points) {
if (info.volume_id() == mount_point) {
found = true;
break;
}
}
EXPECT_TRUE(found) << "Could not find matching mount point for "
<< info.volume_id();
}
return volume_info;
}
std::vector<em::CPUTempInfo> GetEmptyCPUTempInfo() {
return std::vector<em::CPUTempInfo>();
}
std::vector<em::CPUTempInfo> GetFakeCPUTempInfo(
const std::vector<em::CPUTempInfo>& cpu_temp_info) {
return cpu_temp_info;
}
void CallAndroidStatusReceiver(
policy::StatusCollector::AndroidStatusReceiver receiver,
const std::string& status,
const std::string& droid_guard_info) {
std::move(receiver).Run(status, droid_guard_info);
}
bool GetEmptyAndroidStatus(
policy::StatusCollector::AndroidStatusReceiver receiver) {
// Post it to the thread because this call is expected to be asynchronous.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&CallAndroidStatusReceiver, std::move(receiver), "", ""));
return true;
}
bool GetFakeAndroidStatus(
const std::string& status,
const std::string& droid_guard_info,
policy::StatusCollector::AndroidStatusReceiver receiver) {
// Post it to the thread because this call is expected to be asynchronous.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&CallAndroidStatusReceiver, std::move(receiver),
status, droid_guard_info));
return true;
}
em::DiskLifetimeEstimation GetEmptyEMMCLifetimeEstimation() {
return em::DiskLifetimeEstimation();
}
em::DiskLifetimeEstimation GetFakeEMMCLifetiemEstimation(
const em::DiskLifetimeEstimation& value) {
return value;
}
em::StatefulPartitionInfo GetEmptyStatefulPartitionInfo() {
return em::StatefulPartitionInfo();
}
em::StatefulPartitionInfo GetFakeStatefulPartitionInfo(
const em::StatefulPartitionInfo& value) {
return value;
}
bool SettingEnabled(const std::string& path) {
if (!ash::CrosSettings::Get()) {
return false;
}
bool setting;
if (!ash::CrosSettings::Get()->GetBoolean(path, &setting)) {
setting = false;
}
return setting;
}
cros_healthd::BatteryResultPtr CreateBatteryResult() {
return cros_healthd::BatteryResult::NewBatteryInfo(
cros_healthd::BatteryInfo::New(
kFakeBatteryCycleCount, kFakeBatteryVoltageNow, kFakeBatteryVendor,
kFakeBatterySerial, kFakeBatteryChargeFullDesign,
kFakeBatteryChargeFull, kFakeBatteryVoltageMinDesign,
kFakeBatteryModel, kFakeBatteryChargeNow, kFakeBatteryCurrentNow,
kFakeBatteryTechnology, kFakeBatteryStatus,
kFakeSmartBatteryManufactureDate,
cros_healthd::NullableUint64::New(kFakeSmartBatteryTemperature)));
}
cros_healthd::BatteryResultPtr CreateEmptyBatteryResult() {
return cros_healthd::BatteryResult::NewBatteryInfo(
cros_healthd::BatteryInfoPtr());
}
cros_healthd::NonRemovableBlockDeviceResultPtr CreateBlockDeviceResult() {
std::vector<cros_healthd::NonRemovableBlockDeviceInfoPtr> storage_vector;
storage_vector.push_back(cros_healthd::NonRemovableBlockDeviceInfo::New(
kFakeStorageBytesRead, kFakeStorageBytesWritten,
kFakeStorageReadTimeSeconds, kFakeStorageWriteTimeSeconds,
kFakeStorageIoTimeSeconds,
cros_healthd::NullableUint64::New(kFakeStorageDiscardTimeSeconds),
cros_healthd::BlockDeviceVendor::NewEmmcOemid(kFakeOemid),
cros_healthd::BlockDeviceProduct::NewEmmcPnm(kFakePnm),
cros_healthd::BlockDeviceRevision::NewEmmcPrv(kFakePrv), kFakeStorageName,
kFakeStorageSize,
cros_healthd::BlockDeviceFirmware::NewEmmcFwrev(kFakeFwrev),
kFakeStorageType, kFakeMojoPurpose, kFakeStoragePath, kFakeStorageManfid,
kFakeStorageSerial));
return cros_healthd::NonRemovableBlockDeviceResult::NewBlockDeviceInfo(
std::move(storage_vector));
}
cros_healthd::SystemResultPtr CreateSystemResult() {
return cros_healthd::SystemResult::NewSystemInfo(
cros_healthd::SystemInfo::New(
kFakeFirstPowerDate, kFakeManufactureDate, kFakeSkuNumber,
kFakeSerialNumber, kFakeSystemModelName, kFakeMarketingName,
kFakeBiosVersion, kFakeBoardName, kFakeBoardVersion,
cros_healthd::NullableUint64::New(kFakeChassisType), kFakeProductName,
cros_healthd::OsVersion::New(
kFakeVersionMilestone, kFakeVersionBuildNumber,
kFakeVersionPatchNumber, kFakeVersionReleaseChannel)));
}
cros_healthd::SystemResultV2Ptr CreateSystemResultV2() {
return cros_healthd::SystemResultV2::NewSystemInfoV2(
cros_healthd::SystemInfoV2::New(
cros_healthd::OsInfo::New(
kFakeOsInfoCodeName, kFakeOSInfoMarketingName,
cros_healthd::OsVersion::New(
kFakeVersionMilestone, kFakeVersionBuildNumber,
kFakeVersionPatchNumber, kFakeVersionReleaseChannel),
kFakeOsInfoBootMode, kFakeOSInfoOemName),
cros_healthd::VpdInfo::New(kFakeSerialNumber, kFakeVpdInfoRegion,
kFakeManufactureDate, kFakeFirstPowerDate,
kFakeSkuNumber, kFakeModelName),
cros_healthd::DmiInfo::New(
kFakeDmiInfoBiosVendor, kFakeDmiInfoBiosVersion,
kFakeDmiInfoBoardName, kFakeDmiInfoBoardVendor,
kFakeDmiInfoBoardVersion, kFakeDmiInfoChassisVendor,
cros_healthd::NullableUint64::New(kFakeDmiInfoChassisType),
kFakeDmiInfoProductFamily, kFakeDmiInfoProductName,
kFakeDmiInfoProductVersion, kFakeDmiInfoSysVendor)));
}
std::vector<cros_healthd::CpuCStateInfoPtr> CreateCStateInfo() {
std::vector<cros_healthd::CpuCStateInfoPtr> c_states;
c_states.push_back(cros_healthd::CpuCStateInfo::New(
kFakeCStateName, kFakeTimeInStateSinceLastBoot));
return c_states;
}
std::vector<cros_healthd::LogicalCpuInfoPtr> CreateLogicalCpu() {
std::vector<cros_healthd::LogicalCpuInfoPtr> logical_cpus;
logical_cpus.push_back(cros_healthd::LogicalCpuInfo::New(
kFakeMaxClockSpeed, kFakeScalingMaxFrequency, kFakeScalingCurFrequency,
kFakeUserTime, kFakeSystemTime, kFakeIdleTime, CreateCStateInfo()));
return logical_cpus;
}
std::vector<cros_healthd::PhysicalCpuInfoPtr> CreatePhysicalCpu() {
std::vector<cros_healthd::PhysicalCpuInfoPtr> physical_cpus;
physical_cpus.push_back(
cros_healthd::PhysicalCpuInfo::New(kFakeModelName, CreateLogicalCpu()));
return physical_cpus;
}
std::vector<cros_healthd::CpuTemperatureChannelPtr> CreateTemperatureChannel() {
std::vector<cros_healthd::CpuTemperatureChannelPtr> cpu_temps;
cpu_temps.push_back(cros_healthd::CpuTemperatureChannel::New(
kFakeCpuTemperatureLabel, kFakeCpuTemperature));
return cpu_temps;
}
cros_healthd::KeylockerInfoPtr CreateKeylockerInfo() {
return cros_healthd::KeylockerInfo::New(kFakeKeylockerConfigurationState);
}
cros_healthd::CpuResultPtr CreateCpuResult() {
return cros_healthd::CpuResult::NewCpuInfo(cros_healthd::CpuInfo::New(
kFakeNumTotalThreads, kFakeMojoArchitecture, CreatePhysicalCpu(),
CreateTemperatureChannel(), CreateKeylockerInfo()));
}
cros_healthd::TimezoneResultPtr CreateTimezoneResult() {
return cros_healthd::TimezoneResult::NewTimezoneInfo(
cros_healthd::TimezoneInfo::New(kPosixTimezone, kTimezoneRegion));
}
cros_healthd::MemoryResultPtr CreateMemoryResult() {
return cros_healthd::MemoryResult::NewMemoryInfo(
cros_healthd::MemoryInfo::New(kFakeTotalMemory, kFakeFreeMemory,
kFakeAvailableMemory, kFakePageFaults));
}
cros_healthd::BacklightResultPtr CreateBacklightResult() {
std::vector<cros_healthd::BacklightInfoPtr> backlight_vector;
backlight_vector.push_back(cros_healthd::BacklightInfo::New(
kFakeBacklightPath, kFakeMaxBrightness, kFakeBrightness));
return cros_healthd::BacklightResult::NewBacklightInfo(
std::move(backlight_vector));
}
cros_healthd::BacklightResultPtr CreateEmptyBacklightResult() {
std::vector<cros_healthd::BacklightInfoPtr> backlight_vector;
return cros_healthd::BacklightResult::NewBacklightInfo(
std::move(backlight_vector));
}
cros_healthd::FanResultPtr CreateFanResult() {
std::vector<cros_healthd::FanInfoPtr> fan_vector;
fan_vector.push_back(cros_healthd::FanInfo::New(kFakeSpeedRpm));
return cros_healthd::FanResult::NewFanInfo(std::move(fan_vector));
}
cros_healthd::StatefulPartitionResultPtr CreateStatefulPartitionResult() {
return cros_healthd::StatefulPartitionResult::NewPartitionInfo(
cros_healthd::StatefulPartitionInfo::New(kAvailableSpace, kTotalSpace,
kFilesystem, kMountSource));
}
cros_healthd::FanResultPtr CreateEmptyFanResult() {
std::vector<cros_healthd::FanInfoPtr> fan_vector;
return cros_healthd::FanResult::NewFanInfo(std::move(fan_vector));
}
cros_healthd::BluetoothResultPtr CreateBluetoothResult() {
std::vector<cros_healthd::BluetoothAdapterInfoPtr> adapter_info;
adapter_info.push_back(cros_healthd::BluetoothAdapterInfo::New(
kFakeBluetoothAdapterName, kFakeBluetoothAdapterAddress,
kFakeBluetoothAdapterIsPowered, kFakeNumConnectedBluetoothDevices));
return cros_healthd::BluetoothResult::NewBluetoothAdapterInfo(
std::move(adapter_info));
}
cros_healthd::TpmResultPtr CreateTpmResult() {
return cros_healthd::TpmResult::NewTpmInfo(cros_healthd::TpmInfo::New(
cros_healthd::TpmVersion::New(), cros_healthd::TpmStatus::New(),
cros_healthd::TpmDictionaryAttack::New(),
cros_healthd::TpmAttestation::New(),
cros_healthd::TpmSupportedFeatures::New(), kFakeTpmDidVid));
}
cros_healthd::TpmResultPtr CreatePartialTpmResult() {
return cros_healthd::TpmResult::NewTpmInfo(cros_healthd::TpmInfo::New(
cros_healthd::TpmVersion::New(), cros_healthd::TpmStatus::New(),
cros_healthd::TpmDictionaryAttack::New(),
cros_healthd::TpmAttestation::New(),
cros_healthd::TpmSupportedFeatures::New(),
absl::optional<std::string>()));
}
cros_healthd::BusResultPtr CreateBusResult() {
std::vector<cros_healthd::BusDevicePtr> bus_devices;
// pci bus device
cros_healthd::PciBusInfoPtr pci_bus_info;
pci_bus_info = cros_healthd::PciBusInfo::New(kFakeUnusedBusId, // class_id
kFakeUnusedBusId, // subclass_id
kFakeUnusedBusId, // prog_if_id
kFakeUnusedBusId, // vendor_id
kFakeUnusedBusId, // device_id
kFakePciDriver // driver
);
bus_devices.push_back(cros_healthd::BusDevice::New(
kFakePciVendor, // vendor_name
kFakePciProduct, // product_name
cros_healthd::BusDeviceClass::kEthernetController, // device_class
cros_healthd::BusInfo::NewPciBusInfo(std::move(pci_bus_info))));
// usb bus device
std::vector<cros_healthd::UsbBusInterfaceInfoPtr> usb_interfaces;
usb_interfaces.push_back(cros_healthd::UsbBusInterfaceInfo::New(
kFakeUsbInterfaceNumber0, // interface_number
kFakeUnusedBusId, // class_id
kFakeUnusedBusId, // subclass_id
kFakeUnusedBusId, // protocol_id
kFakeUsbDriver0 // driver
));
usb_interfaces.push_back(cros_healthd::UsbBusInterfaceInfo::New(
kFakeUsbInterfaceNumber1, // interface_number
kFakeUnusedBusId, // class_id
kFakeUnusedBusId, // subclass_id
kFakeUnusedBusId, // protocol_id
kFakeUsbDriver1 // driver
));
cros_healthd::UsbBusInfoPtr usb_bus_info;
usb_bus_info = cros_healthd::UsbBusInfo::New(kFakeUnusedBusId, // class_id
kFakeUnusedBusId, // subclass_id
kFakeUnusedBusId, // protocol_id
kFakeUnusedBusId, // vendor_id
kFakeUnusedBusId, // product_id
std::move(usb_interfaces));
bus_devices.push_back(cros_healthd::BusDevice::New(
kFakeUsbVendor, // vendor_name
kFakeUsbProduct, // product_name
cros_healthd::BusDeviceClass::kWirelessController, // device_class
cros_healthd::BusInfo::NewUsbBusInfo(std::move(usb_bus_info))));
return cros_healthd::BusResult::NewBusDevices(std::move(bus_devices));
}
// Set fake CrosHealthdData populated with arbitrary values based on enabled
// policies.
void SetFakeCrosHealthdData() {
auto telemetry_info = cros_healthd::TelemetryInfo::New();
cros_healthd::TelemetryInfo fake_info;
// Always gather system V2.
telemetry_info->system_result_v2 = CreateSystemResultV2();
if (SettingEnabled(ash::kReportDevicePowerStatus))
telemetry_info->battery_result = CreateBatteryResult();
if (SettingEnabled(ash::kReportDeviceStorageStatus))
telemetry_info->block_device_result = CreateBlockDeviceResult();
if (SettingEnabled(ash::kReportDeviceSystemInfo) ||
SettingEnabled(ash::kReportDeviceVpdInfo))
telemetry_info->system_result = CreateSystemResult();
if (SettingEnabled(ash::kReportDeviceCpuInfo))
telemetry_info->cpu_result = CreateCpuResult();
if (SettingEnabled(ash::kReportDeviceTimezoneInfo))
telemetry_info->timezone_result = CreateTimezoneResult();
if (SettingEnabled(ash::kReportDeviceMemoryInfo))
telemetry_info->memory_result = CreateMemoryResult();
if (SettingEnabled(ash::kReportDeviceBacklightInfo))
telemetry_info->backlight_result = CreateBacklightResult();
if (SettingEnabled(ash::kReportDeviceFanInfo))
telemetry_info->fan_result = CreateFanResult();
if (SettingEnabled(ash::kReportDeviceStorageStatus))
telemetry_info->stateful_partition_result = CreateStatefulPartitionResult();
if (SettingEnabled(ash::kReportDeviceBluetoothInfo))
telemetry_info->bluetooth_result = CreateBluetoothResult();
if (SettingEnabled(ash::kReportDeviceVersionInfo))
telemetry_info->tpm_result = CreateTpmResult();
if (SettingEnabled(ash::kReportDeviceNetworkConfiguration)) {
telemetry_info->bus_result = CreateBusResult();
}
chromeos::cros_healthd::FakeCrosHealthdClient::Get()
->SetProbeTelemetryInfoResponseForTesting(telemetry_info);
}
void GetEmptyGraphicsStatus(
policy::DeviceStatusCollector::GraphicsStatusReceiver receiver) {
std::move(receiver).Run(em::GraphicsStatus());
}
void GetFakeGraphicsStatus(
const em::GraphicsStatus& value,
policy::DeviceStatusCollector::GraphicsStatusReceiver receiver) {
std::move(receiver).Run(value);
}
void GetEmptyCrashReportInfo(
policy::DeviceStatusCollector::CrashReportInfoReceiver receiver) {
std::vector<em::CrashReportInfo> crash_report_infos;
std::move(receiver).Run(crash_report_infos);
}
void GetFakeCrashReportInfo(
const std::vector<em::CrashReportInfo>& crash_report_infos,
policy::DeviceStatusCollector::CrashReportInfoReceiver receiver) {
std::move(receiver).Run(crash_report_infos);
}
} // namespace
namespace policy {
// Though it is a unit test, this test is linked with browser_tests so that it
// runs in a separate process. The intention is to avoid overriding the timezone
// environment variable for other tests.
class DeviceStatusCollectorTest : public testing::Test {
public:
// TODO(b/216186861) Default all policies to false for each unit test
DeviceStatusCollectorTest()
: user_manager_(new ash::MockUserManager()),
user_manager_enabler_(base::WrapUnique(user_manager_)),
got_session_status_(false),
fake_kiosk_device_local_account_(
policy::DeviceLocalAccount::TYPE_KIOSK_APP,
kKioskAccountId,
kKioskAppId,
std::string() /* kiosk_app_update_url */),
fake_arc_kiosk_app_basic_info_(kArcKioskPackageName,
std::string() /* class_name */,
std::string() /* action */,
std::string() /* display_name */),
fake_arc_kiosk_device_local_account_(fake_arc_kiosk_app_basic_info_,
kArcKioskAccountId),
fake_web_kiosk_app_basic_info_(kWebKioskAppUrl,
std::string() /* title */,
std::string() /* icon_url */),
fake_web_kiosk_device_local_account_(fake_web_kiosk_app_basic_info_,
kWebKioskAccountId),
user_data_dir_override_(chrome::DIR_USER_DATA),
crash_dumps_dir_override_(chrome::DIR_CRASH_DUMPS),
update_engine_client_(new chromeos::FakeUpdateEngineClient) {
scoped_stub_install_attributes_.Get()->SetCloudManaged("managed.com",
"device_id");
EXPECT_CALL(*user_manager_, Shutdown()).Times(1);
// Ensure mojo is started, otherwise browser context keyed services that
// rely on mojo will explode.
mojo::core::Init();
// Although this is really a unit test which runs in the browser_tests
// binary, it doesn't get the unit setup which normally happens in the unit
// test binary.
ChromeUnitTestSuite::InitializeProviders();
ChromeUnitTestSuite::InitializeResourceBundle();
content::SetContentClient(&content_client_);
content::SetBrowserClientForTesting(&browser_content_client_);
// Run this test with a well-known timezone so that Time::LocalMidnight()
// returns the same values on all machines.
std::unique_ptr<base::Environment> env(base::Environment::Create());
env->SetVar("TZ", "UTC");
// Initialize our mock mounted disk volumes.
std::unique_ptr<ash::disks::MockDiskMountManager> mock_disk_mount_manager =
std::make_unique<ash::disks::MockDiskMountManager>();
AddMountPoint("/mount/volume1");
AddMountPoint("/mount/volume2");
EXPECT_CALL(*mock_disk_mount_manager, mount_points())
.WillRepeatedly(ReturnRef(mount_point_map_));
// Setup a fake file system that should show up in mount points.
storage::ExternalMountPoints::GetSystemInstance()->RevokeAllFileSystems();
storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
"c", storage::kFileSystemTypeLocal, storage::FileSystemMountOption(),
base::FilePath(kExternalMountPoint));
// Just verify that we are properly setting the mount points.
std::vector<storage::MountPoints::MountPointInfo> external_mount_points;
storage::ExternalMountPoints::GetSystemInstance()->AddMountPointInfosTo(
&external_mount_points);
EXPECT_FALSE(external_mount_points.empty());
// DiskMountManager takes ownership of the MockDiskMountManager.
DiskMountManager::InitializeForTesting(mock_disk_mount_manager.release());
TestingDeviceStatusCollector::RegisterPrefs(local_state_.registry());
TestingDeviceStatusCollector::RegisterProfilePrefs(
profile_pref_service_.registry());
// Set up a fake local state for KioskAppManager and KioskCryptohomeRemover.
TestingBrowserProcess::GetGlobal()->SetLocalState(&local_state_);
ash::KioskAppManager::RegisterPrefs(local_state_.registry());
ash::KioskCryptohomeRemover::RegisterPrefs(local_state_.registry());
// Use FakeUpdateEngineClient.
chromeos::DBusThreadManager::Initialize();
chromeos::DBusThreadManager::GetSetterForTesting()->SetUpdateEngineClient(
base::WrapUnique<chromeos::UpdateEngineClient>(update_engine_client_));
// Async tasks posted when calling `chromeos::DBusThreadManager::Initialize`
// need to be flushed.
base::RunLoop().RunUntilIdle();
chromeos::CrasAudioHandler::InitializeForTesting();
chromeos::UserDataAuthClient::InitializeFake();
chromeos::PowerManagerClient::InitializeFake();
chromeos::AttestationClient::InitializeFake();
chromeos::TpmManagerClient::InitializeFake();
chromeos::LoginState::Initialize();
chromeos::CrosHealthdClient::InitializeFake();
chromeos::CiceroneClient::InitializeFake();
chromeos::ConciergeClient::InitializeFake();
chromeos::SeneschalClient::InitializeFake();
}
DeviceStatusCollectorTest(const DeviceStatusCollectorTest&) = delete;
DeviceStatusCollectorTest& operator=(const DeviceStatusCollectorTest&) =
delete;
~DeviceStatusCollectorTest() override {
chromeos::SeneschalClient::Shutdown();
// |testing_profile_| must be destroyed while ConciergeClient is alive.
testing_profile_.reset();
chromeos::ConciergeClient::Shutdown();
chromeos::CiceroneClient::Shutdown();
chromeos::LoginState::Shutdown();
chromeos::TpmManagerClient::Shutdown();
chromeos::AttestationClient::Shutdown();
chromeos::PowerManagerClient::Shutdown();
chromeos::UserDataAuthClient::Shutdown();
chromeos::CrasAudioHandler::Shutdown();
ash::KioskAppManager::Shutdown();
chromeos::CrosHealthdClient::Shutdown();
chromeos::cros_healthd::ServiceConnection::GetInstance()->FlushForTesting();
TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr);
// Finish pending tasks.
content::RunAllTasksUntilIdle();
storage::ExternalMountPoints::GetSystemInstance()->RevokeAllFileSystems();
DiskMountManager::Shutdown();
}
void SetUp() override {
// Disable network interface reporting since it requires additional setup.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkStatus, false);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkConfiguration, false);
managed_session_service_ =
std::make_unique<policy::ManagedSessionService>();
RestartStatusCollector();
}
void TearDown() override {
status_collector_.reset();
managed_session_service_.reset();
}
protected:
void AddMountPoint(const std::string& mount_point) {
mount_point_map_.insert(DiskMountManager::MountPointMap::value_type(
mount_point, DiskMountManager::MountPointInfo(
mount_point, mount_point, chromeos::MOUNT_TYPE_DEVICE,
ash::disks::MOUNT_CONDITION_NONE)));
}
virtual void RestartStatusCollector(
std::unique_ptr<TestingDeviceStatusCollectorOptions> options) {
std::vector<em::VolumeInfo> expected_volume_info;
status_collector_ = std::make_unique<TestingDeviceStatusCollector>(
&local_state_, &fake_statistics_provider_,
managed_session_service_.get(), std::move(options), &test_clock_);
}
void DisableDefaultSettings() {
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceVersionInfo, false);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceActivityTimes, false);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceBootMode, false);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkInterfaces, false);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceUsers, false);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceHardwareStatus, false);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceSessionStatus, false);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceAudioStatus, false);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkConfiguration, false);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkStatus, false);
}
void RestartStatusCollector() {
RestartStatusCollector(CreateEmptyDeviceStatusCollectorOptions());
}
void WriteUploadLog(const std::string& log_data) {
ASSERT_TRUE(base::WriteFile(log_path(), log_data));
}
base::FilePath log_path() {
base::FilePath crash_dir_path;
base::PathService::Get(chrome::DIR_CRASH_DUMPS, &crash_dir_path);
return crash_dir_path.AppendASCII("uploads.log");
}
std::unique_ptr<TestingDeviceStatusCollectorOptions>
CreateEmptyDeviceStatusCollectorOptions() {
auto options = std::make_unique<TestingDeviceStatusCollectorOptions>();
options->volume_info_fetcher = base::BindRepeating(&GetEmptyVolumeInfo);
options->cpu_fetcher = base::BindRepeating(&GetEmptyCPUStatistics);
options->cpu_temp_fetcher = base::BindRepeating(&GetEmptyCPUTempInfo);
options->android_status_fetcher =
base::BindRepeating(&GetEmptyAndroidStatus);
options->emmc_lifetime_fetcher =
base::BindRepeating(&GetEmptyEMMCLifetimeEstimation);
options->stateful_partition_info_fetcher =
base::BindRepeating(&GetEmptyStatefulPartitionInfo);
options->graphics_status_fetcher =
base::BindRepeating(&GetEmptyGraphicsStatus);
options->crash_report_info_fetcher =
base::BindRepeating(&GetEmptyCrashReportInfo);
options->app_info_generator =
std::make_unique<policy::AppInfoGenerator>(nullptr, base::Days(0));
return options;
}
void GetStatus() {
device_status_.Clear();
session_status_.Clear();
got_session_status_ = false;
run_loop_ = std::make_unique<base::RunLoop>();
status_collector_->GetStatusAsync(base::BindRepeating(
&DeviceStatusCollectorTest::OnStatusReceived, base::Unretained(this)));
run_loop_->Run();
run_loop_.reset();
}
void OnStatusReceived(StatusCollectorParams callback_params) {
if (callback_params.device_status)
device_status_ = *callback_params.device_status;
got_session_status_ = callback_params.session_status != nullptr;
if (got_session_status_)
session_status_ = *callback_params.session_status;
EXPECT_TRUE(run_loop_);
run_loop_->Quit();
}
void MockUserWithTypeAndAffiliation(const AccountId& account_id,
user_manager::UserType user_type,
bool is_affiliated) {
user_manager_->AddUserWithAffiliationAndType(account_id, is_affiliated,
user_type);
// The user just added will be the active user because there's only one
// user.
user_manager::User* user = user_manager_->GetActiveUser();
// Build a profile with profile name=account e-mail because our testing
// version of GetDMTokenForProfile returns the profile name.
TestingProfile::Builder profile_builder;
profile_builder.SetProfileName(account_id.GetUserEmail());
testing_profile_ = profile_builder.Build();
ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
user, testing_profile_.get());
EXPECT_CALL(*user_manager_, IsLoggedInAsKioskApp())
.WillRepeatedly(Return(false));
EXPECT_CALL(*user_manager_, FindUser(account_id))
.WillRepeatedly(Return(user));
}
void MockRegularUserWithAffiliation(const AccountId& account_id,
bool is_affiliated) {
MockUserWithTypeAndAffiliation(account_id, user_manager::USER_TYPE_REGULAR,
is_affiliated);
}
void MockRunningKioskApp(const DeviceLocalAccount& account,
const DeviceLocalAccount::Type& type) {
std::vector<DeviceLocalAccount> accounts;
accounts.push_back(account);
user_manager::User* user = user_manager_->CreateKioskAppUser(
AccountId::FromUserEmail(account.user_id));
if (type == DeviceLocalAccount::TYPE_KIOSK_APP) {
EXPECT_CALL(*user_manager_, IsLoggedInAsKioskApp())
.WillRepeatedly(Return(true));
} else if (type == DeviceLocalAccount::TYPE_ARC_KIOSK_APP) {
EXPECT_CALL(*user_manager_, IsLoggedInAsArcKioskApp())
.WillRepeatedly(Return(true));
} else if (type == DeviceLocalAccount::TYPE_WEB_KIOSK_APP) {
EXPECT_CALL(*user_manager_, IsLoggedInAsWebKioskApp())
.WillRepeatedly(Return(true));
} else {
FAIL() << "Unexpected kiosk app type.";
}
testing_profile_ = std::make_unique<TestingProfile>();
ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
user, testing_profile_.get());
SetDeviceLocalAccounts(&owner_settings_service_, accounts);
}
std::unique_ptr<ScopedChromeOSVersionInfo> MockPlatformVersion(
const std::string& platform_version) {
const std::string lsb_release = base::StringPrintf(
"CHROMEOS_RELEASE_VERSION=%s", platform_version.c_str());
return std::make_unique<ScopedChromeOSVersionInfo>(lsb_release,
base::Time::Now());
}
void MockAutoLaunchKioskAppWithRequiredPlatformVersion(
const DeviceLocalAccount& auto_launch_app_account,
const std::string& required_platform_version) {
ash::KioskAppManager* manager = ash::KioskAppManager::Get();
manager->AddAppForTest(
auto_launch_app_account.kiosk_app_id,
AccountId::FromUserEmail(auto_launch_app_account.user_id),
GURL("http://cws/"), // Dummy URL to avoid setup ExtensionsClient.
required_platform_version);
manager->SetEnableAutoLaunch(true);
std::vector<DeviceLocalAccount> accounts;
accounts.push_back(auto_launch_app_account);
SetDeviceLocalAccounts(&owner_settings_service_, accounts);
owner_settings_service_.SetString(
ash::kAccountsPrefDeviceLocalAccountAutoLoginId,
auto_launch_app_account.account_id);
base::RunLoop().RunUntilIdle();
ASSERT_EQ(required_platform_version,
manager->GetAutoLaunchAppRequiredPlatformVersion());
}
void MockAutoLaunchArcKioskApp(
const DeviceLocalAccount& auto_launch_app_account) {
arc_kiosk_app_manager_ = std::make_unique<chromeos::ArcKioskAppManager>();
arc_kiosk_app_manager_->AddAutoLaunchAppForTest(
auto_launch_app_account.arc_kiosk_app_info.package_name(),
auto_launch_app_account.arc_kiosk_app_info,
AccountId::FromUserEmail(auto_launch_app_account.user_id));
std::vector<DeviceLocalAccount> accounts;
accounts.push_back(auto_launch_app_account);
SetDeviceLocalAccounts(&owner_settings_service_, accounts);
owner_settings_service_.SetString(
ash::kAccountsPrefDeviceLocalAccountAutoLoginId,
auto_launch_app_account.account_id);
base::RunLoop().RunUntilIdle();
}
void MockAutoLaunchWebKioskApp(
const DeviceLocalAccount& auto_launch_app_account) {
web_kiosk_app_manager_ = std::make_unique<ash::WebKioskAppManager>();
web_kiosk_app_manager_->AddAppForTesting(
AccountId::FromUserEmail(auto_launch_app_account.user_id),
GURL(auto_launch_app_account.web_kiosk_app_info.url()));
std::vector<DeviceLocalAccount> accounts;
accounts.push_back(auto_launch_app_account);
SetDeviceLocalAccounts(&owner_settings_service_, accounts);
owner_settings_service_.SetString(
ash::kAccountsPrefDeviceLocalAccountAutoLoginId,
auto_launch_app_account.account_id);
base::RunLoop().RunUntilIdle();
}
// Convenience method.
int64_t ActivePeriodMilliseconds() {
return policy::DeviceStatusCollector::kIdlePollInterval.InMilliseconds();
}
// Since this is a unit test running in browser_tests we must do additional
// unit test setup and make a TestingBrowserProcess. Must be first member.
TestingBrowserProcessInitializer initializer_;
content::BrowserTaskEnvironment task_environment_;
ChromeContentClient content_client_;
ChromeContentBrowserClient browser_content_client_;
chromeos::system::ScopedFakeStatisticsProvider fake_statistics_provider_;
DiskMountManager::MountPointMap mount_point_map_;
ash::ScopedStubInstallAttributes scoped_stub_install_attributes_;
ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
ash::FakeOwnerSettingsService owner_settings_service_{
scoped_testing_cros_settings_.device_settings(), nullptr};
// local_state_ should be destructed after TestingProfile.
TestingPrefServiceSimple local_state_;
// Only set after MockRunningKioskApp was called.
std::unique_ptr<TestingProfile> testing_profile_;
// Only set after MockAutoLaunchArcKioskApp was called.
std::unique_ptr<chromeos::ArcKioskAppManager> arc_kiosk_app_manager_;
// Only set after MockAutoLaunchWebKioskApp was called.
std::unique_ptr<ash::WebKioskAppManager> web_kiosk_app_manager_;
ash::MockUserManager* const user_manager_;
user_manager::ScopedUserManager user_manager_enabler_;
em::DeviceStatusReportRequest device_status_;
em::SessionStatusReportRequest session_status_;
bool got_session_status_;
TestingPrefServiceSimple profile_pref_service_;
std::unique_ptr<policy::ManagedSessionService> managed_session_service_;
std::unique_ptr<TestingDeviceStatusCollector> status_collector_;
const policy::DeviceLocalAccount fake_kiosk_device_local_account_;
const policy::ArcKioskAppBasicInfo fake_arc_kiosk_app_basic_info_;
const policy::DeviceLocalAccount fake_arc_kiosk_device_local_account_;
const policy::WebKioskAppBasicInfo fake_web_kiosk_app_basic_info_;
const policy::DeviceLocalAccount fake_web_kiosk_device_local_account_;
base::ScopedPathOverride user_data_dir_override_;
base::ScopedPathOverride crash_dumps_dir_override_;
chromeos::FakeUpdateEngineClient* const update_engine_client_;
std::unique_ptr<base::RunLoop> run_loop_;
base::test::ScopedFeatureList scoped_feature_list_;
base::SimpleTestClock test_clock_;
apps::ScopedOmitBorealisAppsForTesting scoped_omit_borealis_apps_for_testing_;
apps::ScopedOmitBuiltInAppsForTesting scoped_omit_built_in_apps_for_testing_;
apps::ScopedOmitPluginVmAppsForTesting
scoped_omit_plugin_vm_apps_for_testing_;
// This property is required to instantiate the session manager, a singleton
// which is used by the device status collector.
session_manager::SessionManager session_manager_;
};
TEST_F(DeviceStatusCollectorTest, AllIdle) {
DisableDefaultSettings();
ui::IdleState test_states[] = {ui::IDLE_STATE_IDLE, ui::IDLE_STATE_IDLE,
ui::IDLE_STATE_IDLE};
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceActivityTimes, true);
// Test reporting with no data.
GetStatus();
EXPECT_EQ(0, device_status_.active_periods_size());
EXPECT_EQ(0, GetActiveMilliseconds(device_status_));
// Test reporting with a single idle sample.
status_collector_->Simulate(test_states, 1);
GetStatus();
EXPECT_EQ(0, device_status_.active_periods_size());
EXPECT_EQ(0, GetActiveMilliseconds(device_status_));
// Test reporting with multiple consecutive idle samples.
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(ui::IdleState));
GetStatus();
EXPECT_EQ(0, device_status_.active_periods_size());
EXPECT_EQ(0, GetActiveMilliseconds(device_status_));
}
TEST_F(DeviceStatusCollectorTest, AllActive) {
DisableDefaultSettings();
ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
ui::IDLE_STATE_ACTIVE};
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceActivityTimes, true);
// Test a single active sample.
status_collector_->Simulate(test_states, 1);
GetStatus();
EXPECT_EQ(1, device_status_.active_periods_size());
EXPECT_EQ(1 * ActivePeriodMilliseconds(),
GetActiveMilliseconds(device_status_));
device_status_.clear_active_periods(); // Clear the result protobuf.
// Test multiple consecutive active samples.
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(ui::IdleState));
GetStatus();
EXPECT_EQ(1, device_status_.active_periods_size());
EXPECT_EQ(4 * ActivePeriodMilliseconds(),
GetActiveMilliseconds(device_status_));
}
TEST_F(DeviceStatusCollectorTest, MixedStates) {
DisableDefaultSettings();
ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_IDLE,
ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
ui::IDLE_STATE_IDLE, ui::IDLE_STATE_IDLE,
ui::IDLE_STATE_ACTIVE};
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceActivityTimes, true);
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(ui::IdleState));
GetStatus();
EXPECT_EQ(4 * ActivePeriodMilliseconds(),
GetActiveMilliseconds(device_status_));
}
// For kiosks report total uptime instead of only active periods.
TEST_F(DeviceStatusCollectorTest, MixedStatesForKiosk) {
DisableDefaultSettings();
ui::IdleState test_states[] = {
ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_IDLE, ui::IDLE_STATE_ACTIVE,
ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_IDLE, ui::IDLE_STATE_IDLE,
};
chromeos::LoginState::Get()->SetLoggedInState(
chromeos::LoginState::LOGGED_IN_ACTIVE,
chromeos::LoginState::LOGGED_IN_USER_KIOSK);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceActivityTimes, true);
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(ui::IdleState));
GetStatus();
EXPECT_EQ(6 * ActivePeriodMilliseconds(),
GetActiveMilliseconds(device_status_));
}
// For Arc kiosks report total uptime instead of only active periods.
TEST_F(DeviceStatusCollectorTest, MixedStatesForArcKiosk) {
DisableDefaultSettings();
ui::IdleState test_states[] = {
ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_IDLE, ui::IDLE_STATE_ACTIVE,
ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_IDLE,
};
chromeos::LoginState::Get()->SetLoggedInState(
chromeos::LoginState::LOGGED_IN_ACTIVE,
chromeos::LoginState::LOGGED_IN_USER_KIOSK);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceActivityTimes, true);
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(ui::IdleState));
GetStatus();
EXPECT_EQ(5 * ActivePeriodMilliseconds(),
GetActiveMilliseconds(device_status_));
}
TEST_F(DeviceStatusCollectorTest, StateKeptInPref) {
DisableDefaultSettings();
ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_IDLE,
ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
ui::IDLE_STATE_IDLE, ui::IDLE_STATE_IDLE};
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceActivityTimes, true);
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(ui::IdleState));
// Process the list a second time after restarting the collector. It should be
// able to count the active periods found by the original collector, because
// the results are stored in a pref.
RestartStatusCollector(CreateEmptyDeviceStatusCollectorOptions());
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(ui::IdleState));
GetStatus();
EXPECT_EQ(6 * ActivePeriodMilliseconds(),
GetActiveMilliseconds(device_status_));
}
TEST_F(DeviceStatusCollectorTest, ActivityNotWrittenToProfilePref) {
DisableDefaultSettings();
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceActivityTimes, true);
EXPECT_TRUE(profile_pref_service_.GetDictionary(prefs::kUserActivityTimes)
->DictEmpty());
ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
ui::IDLE_STATE_ACTIVE};
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(ui::IdleState));
GetStatus();
EXPECT_EQ(1, device_status_.active_periods_size());
EXPECT_EQ(3 * ActivePeriodMilliseconds(),
GetActiveMilliseconds(device_status_));
// Nothing should be written to profile pref service, because it is only used
// for consumer reporting.
EXPECT_TRUE(profile_pref_service_.GetDictionary(prefs::kUserActivityTimes)
->DictEmpty());
}
TEST_F(DeviceStatusCollectorTest, MaxStoredPeriods) {
DisableDefaultSettings();
ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_IDLE};
const int kMaxDays = 10;
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceActivityTimes, true);
status_collector_->set_max_stored_past_activity_interval(
base::Days(kMaxDays - 1));
status_collector_->set_max_stored_future_activity_interval(base::Days(1));
test_clock_.SetNow(Time::Now().LocalMidnight());
// Simulate 12 active periods.
for (int i = 0; i < kMaxDays + 2; i++) {
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(ui::IdleState));
// Advance the simulated clock by a day.
test_clock_.Advance(base::Days(1));
}
// Check that we don't exceed the max number of periods.
GetStatus();
EXPECT_EQ(kMaxDays, device_status_.active_periods_size());
// Simulate some future times.
for (int i = 0; i < kMaxDays + 2; i++) {
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(ui::IdleState));
// Advance the simulated clock by a day.
test_clock_.Advance(base::Days(1));
}
// Set the clock back so the previous simulated times are in the future.
test_clock_.Advance(-base::Days(20));
// Collect one more data point to trigger pruning.
status_collector_->Simulate(test_states, 1);
// Check that we don't exceed the max number of periods.
device_status_.clear_active_periods();
GetStatus();
EXPECT_LT(device_status_.active_periods_size(), kMaxDays);
}
TEST_F(DeviceStatusCollectorTest, ActivityTimesEnabledByDefault) {
// Device activity times should be reported by default.
ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
ui::IDLE_STATE_ACTIVE};
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(ui::IdleState));
GetStatus();
EXPECT_EQ(1, device_status_.active_periods_size());
EXPECT_EQ(3 * ActivePeriodMilliseconds(),
GetActiveMilliseconds(device_status_));
}
TEST_F(DeviceStatusCollectorTest, ActivityTimesOff) {
// Device activity times should not be reported while disabled.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceActivityTimes, false);
ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
ui::IDLE_STATE_ACTIVE};
status_collector_->Simulate(test_states,
sizeof(test_states) / sizeof(ui::IdleState));
GetStatus();
EXPECT_EQ(0, device_status_.active_periods_size());
EXPECT_EQ(0, GetActiveMilliseconds(device_status_));
}
TEST_F(DeviceStatusCollectorTest, ActivityCrossingMidnight) {
DisableDefaultSettings();
ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE};
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceActivityTimes, true);
// Set the baseline time to 20 seconds before midnight.
test_clock_.SetNow(Time::Now().LocalMidnight() - base::Seconds(20));
status_collector_->Simulate(test_states, 1);
GetStatus();
ASSERT_EQ(2, device_status_.active_periods_size());
em::ActiveTimePeriod period0 = device_status_.active_periods(0);
em::ActiveTimePeriod period1 = device_status_.active_periods(1);
EXPECT_EQ(ActivePeriodMilliseconds() - 10000, period0.active_duration());
EXPECT_EQ(10000, period1.active_duration());
em::TimePeriod time_period0 = period0.time_period();
em::TimePeriod time_period1 = period1.time_period();
EXPECT_EQ(time_period0.end_timestamp(), time_period1.start_timestamp());
// Ensure that the start and end times for the period are a day apart.
EXPECT_EQ(time_period0.end_timestamp() - time_period0.start_timestamp(),
kMillisecondsPerDay);
EXPECT_EQ(time_period1.end_timestamp() - time_period1.start_timestamp(),
kMillisecondsPerDay);
}
TEST_F(DeviceStatusCollectorTest, ActivityTimesKeptUntilSubmittedSuccessfully) {
DisableDefaultSettings();
ui::IdleState test_states[] = {
ui::IDLE_STATE_ACTIVE,
ui::IDLE_STATE_ACTIVE,
};
// Make sure CPU stats get reported in time. If we don't run this, the second
// call to |GetStatus()| will contain these stats, but the first call won't
// and the EXPECT_EQ test below fails.
base::RunLoop().RunUntilIdle();
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceActivityTimes, true);
status_collector_->Simulate(test_states, 2);
GetStatus();
EXPECT_EQ(2 * ActivePeriodMilliseconds(),
GetActiveMilliseconds(device_status_));
em::DeviceStatusReportRequest first_status(device_status_);
// The collector returns the same activity times again.
GetStatus();
int period_count = first_status.active_periods_size();
EXPECT_EQ(period_count, device_status_.active_periods_size());
for (int n = 0; n < period_count; ++n) {
EXPECT_EQ(first_status.active_periods(n).SerializeAsString(),
device_status_.active_periods(n).SerializeAsString());
}
// After indicating a successful submit, the submitted status gets cleared,
// and prior activity is no longer showing.
status_collector_->Simulate(test_states, 1);
status_collector_->OnSubmittedSuccessfully();
GetStatus();
EXPECT_EQ(0, GetActiveMilliseconds(device_status_));
}
TEST_F(DeviceStatusCollectorTest, ActivityNoUser) {
DisableDefaultSettings();
scoped_feature_list_.InitAndEnableFeature(
features::kActivityReportingSessionType);
ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
ui::IDLE_STATE_ACTIVE};
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceActivityTimes, true);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceUsers, true);
EXPECT_FALSE(status_collector_->IsReportingActivityTimes());
EXPECT_FALSE(status_collector_->IsReportingUsers());
status_collector_->Simulate(test_states, 3);
GetStatus();
EXPECT_EQ(1, device_status_.active_periods_size());
EXPECT_TRUE(device_status_.active_periods(0).user_email().empty());
EXPECT_FALSE(device_status_.active_periods(0).has_session_type());
}
TEST_F(DeviceStatusCollectorTest, ActivityWithPublicSessionUser) {
DisableDefaultSettings();
scoped_feature_list_.InitAndEnableFeature(
features::kActivityReportingSessionType);
ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
ui::IDLE_STATE_ACTIVE};
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceActivityTimes, true);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceUsers, true);
const AccountId public_account_id(AccountId::FromUserEmail(
"public@public-accounts.device-local.localhost"));
user_manager_->CreatePublicAccountUser(public_account_id);
EXPECT_FALSE(status_collector_->IsReportingActivityTimes());
EXPECT_FALSE(status_collector_->IsReportingUsers());
status_collector_->Simulate(test_states, 3);
GetStatus();
EXPECT_EQ(1, device_status_.active_periods_size());
EXPECT_TRUE(device_status_.active_periods(0).user_email().empty());
EXPECT_EQ(em::ActiveTimePeriod::SESSION_MANAGED_GUEST,
device_status_.active_periods(0).session_type());
}
TEST_F(DeviceStatusCollectorTest, ActivityWithKioskUser) {
DisableDefaultSettings();
scoped_feature_list_.InitAndEnableFeature(
features::kActivityReportingSessionType);
ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
ui::IDLE_STATE_ACTIVE};
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceActivityTimes, true);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceUsers, true);
const AccountId public_account_id(
AccountId::FromUserEmail("public@web-kiosk-apps.device-local.localhost"));
user_manager_->CreatePublicAccountUser(public_account_id);
EXPECT_FALSE(status_collector_->IsReportingActivityTimes());
EXPECT_FALSE(status_collector_->IsReportingUsers());
status_collector_->Simulate(test_states, 3);
GetStatus();
EXPECT_EQ(1, device_status_.active_periods_size());
EXPECT_TRUE(device_status_.active_periods(0).user_email().empty());
EXPECT_EQ(em::ActiveTimePeriod::SESSION_WEB_KIOSK,
device_status_.active_periods(0).session_type());
}
TEST_F(DeviceStatusCollectorTest, ActivityWithAffiliatedUser) {
DisableDefaultSettings();
scoped_feature_list_.InitAndEnableFeature(
features::kActivityReportingSessionType);
ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
ui::IDLE_STATE_ACTIVE};
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceActivityTimes, true);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceUsers, true);
const AccountId account_id0(AccountId::FromUserEmail("user0@managed.com"));
user_manager_->AddUserWithAffiliationAndType(account_id0, true,
user_manager::USER_TYPE_REGULAR);
EXPECT_TRUE(status_collector_->IsReportingActivityTimes());
EXPECT_TRUE(status_collector_->IsReportingUsers());
status_collector_->Simulate(test_states, 3);
GetStatus();
EXPECT_EQ(1, device_status_.active_periods_size());
EXPECT_EQ(account_id0.GetUserEmail(),
device_status_.active_periods(0).user_email());
EXPECT_EQ(em::ActiveTimePeriod::SESSION_AFFILIATED_USER,
device_status_.active_periods(0).session_type());
device_status_.clear_active_periods(); // Clear the result protobuf.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceUsers, false);
EXPECT_TRUE(status_collector_->IsReportingActivityTimes());
EXPECT_FALSE(status_collector_->IsReportingUsers());
status_collector_->Simulate(test_states, 3);
GetStatus();
EXPECT_EQ(1, device_status_.active_periods_size());
EXPECT_TRUE(device_status_.active_periods(0).user_email().empty());
EXPECT_FALSE(device_status_.active_periods(0).has_session_type());
}
TEST_F(DeviceStatusCollectorTest, ActivityWithNotAffiliatedUser) {
DisableDefaultSettings();
scoped_feature_list_.InitAndEnableFeature(
features::kActivityReportingSessionType);
ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
ui::IDLE_STATE_ACTIVE};
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceActivityTimes, true);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceUsers, true);
const AccountId account_id0(AccountId::FromUserEmail("user0@managed.com"));
user_manager_->AddUserWithAffiliationAndType(account_id0, false,
user_manager::USER_TYPE_REGULAR);
EXPECT_FALSE(status_collector_->IsReportingActivityTimes());
EXPECT_FALSE(status_collector_->IsReportingUsers());
status_collector_->Simulate(test_states, 3);
GetStatus();
EXPECT_EQ(1, device_status_.active_periods_size());
EXPECT_TRUE(device_status_.active_periods(0).user_email().empty());
EXPECT_FALSE(device_status_.active_periods(0).has_session_type());
device_status_.clear_active_periods(); // Clear the result protobuf.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceUsers, false);
EXPECT_FALSE(status_collector_->IsReportingActivityTimes());
EXPECT_FALSE(status_collector_->IsReportingUsers());
status_collector_->Simulate(test_states, 3);
GetStatus();
EXPECT_EQ(1, device_status_.active_periods_size());
EXPECT_TRUE(device_status_.active_periods(0).user_email().empty());
EXPECT_FALSE(device_status_.active_periods(0).has_session_type());
}
TEST_F(DeviceStatusCollectorTest, DevSwitchBootMode) {
// Test that boot mode data is reported by default.
fake_statistics_provider_.SetMachineStatistic(
chromeos::system::kDevSwitchBootKey,
chromeos::system::kDevSwitchBootValueVerified);
GetStatus();
EXPECT_EQ("Verified", device_status_.boot_mode());
// Test that boot mode data is not reported if the pref turned off.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceBootMode, false);
GetStatus();
EXPECT_FALSE(device_status_.has_boot_mode());
// Turn the pref on, and check that the status is reported iff the
// statistics provider returns valid data.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceBootMode, true);
fake_statistics_provider_.SetMachineStatistic(
chromeos::system::kDevSwitchBootKey, "(error)");
GetStatus();
EXPECT_FALSE(device_status_.has_boot_mode());
fake_statistics_provider_.SetMachineStatistic(
chromeos::system::kDevSwitchBootKey, " ");
GetStatus();
EXPECT_FALSE(device_status_.has_boot_mode());
fake_statistics_provider_.SetMachineStatistic(
chromeos::system::kDevSwitchBootKey,
chromeos::system::kDevSwitchBootValueVerified);
GetStatus();
EXPECT_EQ("Verified", device_status_.boot_mode());
fake_statistics_provider_.SetMachineStatistic(
chromeos::system::kDevSwitchBootKey,
chromeos::system::kDevSwitchBootValueDev);
GetStatus();
EXPECT_EQ("Dev", device_status_.boot_mode());
}
TEST_F(DeviceStatusCollectorTest, WriteProtectSwitch) {
DisableDefaultSettings();
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceSystemInfo, true);
fake_statistics_provider_.SetMachineStatistic(
chromeos::system::kFirmwareWriteProtectCurrentKey,
chromeos::system::kFirmwareWriteProtectCurrentValueOn);
GetStatus();
EXPECT_TRUE(device_status_.write_protect_switch());
fake_statistics_provider_.SetMachineStatistic(
chromeos::system::kFirmwareWriteProtectCurrentKey, "(error)");
GetStatus();
EXPECT_FALSE(device_status_.has_write_protect_switch());
fake_statistics_provider_.SetMachineStatistic(
chromeos::system::kFirmwareWriteProtectCurrentKey, " ");
GetStatus();
EXPECT_FALSE(device_status_.has_write_protect_switch());
fake_statistics_provider_.SetMachineStatistic(
chromeos::system::kFirmwareWriteProtectCurrentKey,
chromeos::system::kFirmwareWriteProtectCurrentValueOn);
GetStatus();
EXPECT_TRUE(device_status_.write_protect_switch());
fake_statistics_provider_.SetMachineStatistic(
chromeos::system::kFirmwareWriteProtectCurrentKey,
chromeos::system::kFirmwareWriteProtectCurrentValueOff);
GetStatus();
EXPECT_FALSE(device_status_.write_protect_switch());
}
TEST_F(DeviceStatusCollectorTest, VersionInfo) {
// Expect the version info to be reported by default.
GetStatus();
EXPECT_TRUE(device_status_.has_browser_version());
EXPECT_TRUE(device_status_.has_channel());
EXPECT_TRUE(device_status_.has_os_version());
EXPECT_TRUE(device_status_.has_firmware_version());
EXPECT_TRUE(device_status_.has_tpm_version_info());
// Expect tpm version info is still set (with an empty one) regardless of
// D-Bus error.
chromeos::TpmManagerClient::Get()
->GetTestInterface()
->mutable_version_info_reply()
->set_status(::tpm_manager::STATUS_DBUS_ERROR);
GetStatus();
EXPECT_TRUE(device_status_.has_browser_version());
EXPECT_TRUE(device_status_.has_channel());
EXPECT_TRUE(device_status_.has_os_version());
EXPECT_TRUE(device_status_.has_firmware_version());
EXPECT_TRUE(device_status_.has_tpm_version_info());
// Reset the version info reply just in case the rest of tests get affected.
chromeos::TpmManagerClient::Get()
->GetTestInterface()
->mutable_version_info_reply()
->clear_status();
// When the pref to collect this data is not enabled, expect that none of
// the fields are present in the protobuf.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceVersionInfo, false);
GetStatus();
EXPECT_FALSE(device_status_.has_browser_version());
EXPECT_FALSE(device_status_.has_channel());
EXPECT_FALSE(device_status_.has_os_version());
EXPECT_FALSE(device_status_.has_firmware_version());
EXPECT_FALSE(device_status_.has_tpm_version_info());
DisableDefaultSettings();
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceVersionInfo, true);
GetStatus();
EXPECT_TRUE(device_status_.has_browser_version());
EXPECT_TRUE(device_status_.has_channel());
EXPECT_TRUE(device_status_.has_os_version());
EXPECT_TRUE(device_status_.has_firmware_version());
EXPECT_TRUE(device_status_.has_tpm_version_info());
// Check that the browser version is not empty. OS version & firmware don't
// have any reasonable values inside the unit test, so those aren't checked.
EXPECT_NE("", device_status_.browser_version());
}
TEST_F(DeviceStatusCollectorTest, ReportUsers) {
const AccountId public_account_id(
AccountId::FromUserEmail("public@localhost"));
const AccountId account_id0(AccountId::FromUserEmail("user0@managed.com"));
const AccountId account_id1(AccountId::FromUserEmail("user1@managed.com"));
const AccountId account_id2(AccountId::FromUserEmail("user2@managed.com"));
const AccountId account_id3(AccountId::FromUserEmail("user3@unmanaged.com"));
const AccountId account_id4(AccountId::FromUserEmail("user4@managed.com"));
const AccountId account_id5(AccountId::FromUserEmail("user5@managed.com"));
user_manager_->CreatePublicAccountUser(public_account_id);
user_manager_->AddUserWithAffiliationAndType(account_id0, true,
user_manager::USER_TYPE_REGULAR);
user_manager_->AddUserWithAffiliationAndType(account_id1, true,
user_manager::USER_TYPE_REGULAR);
user_manager_->AddUserWithAffiliationAndType(account_id2, true,
user_manager::USER_TYPE_REGULAR);
user_manager_->AddUserWithAffiliationAndType(account_id3, false,
user_manager::USER_TYPE_REGULAR);
user_manager_->AddUserWithAffiliationAndType(account_id4, true,
user_manager::USER_TYPE_REGULAR);
user_manager_->AddUserWithAffiliationAndType(account_id5, true,
user_manager::USER_TYPE_REGULAR);
// Verify that users are reported by default.
GetStatus();
EXPECT_EQ(6, device_status_.users_size());
// Verify that users are reported after enabling the setting.
DisableDefaultSettings();
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceUsers, true);
GetStatus();
EXPECT_EQ(6, device_status_.users_size());
EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, device_status_.users(0).type());
EXPECT_EQ(account_id0.GetUserEmail(), device_status_.users(0).email());
EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, device_status_.users(1).type());
EXPECT_EQ(account_id1.GetUserEmail(), device_status_.users(1).email());
EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, device_status_.users(2).type());
EXPECT_EQ(account_id2.GetUserEmail(), device_status_.users(2).email());
EXPECT_EQ(em::DeviceUser::USER_TYPE_UNMANAGED,
device_status_.users(3).type());
EXPECT_FALSE(device_status_.users(3).has_email());
EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, device_status_.users(4).type());
EXPECT_EQ(account_id4.GetUserEmail(), device_status_.users(4).email());
EXPECT_EQ(em::DeviceUser::USER_TYPE_MANAGED, device_status_.users(5).type());
EXPECT_EQ(account_id5.GetUserEmail(), device_status_.users(5).email());
// Verify that users are no longer reported if setting is disabled.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceUsers, false);
GetStatus();
EXPECT_EQ(0, device_status_.users_size());
}
TEST_F(DeviceStatusCollectorTest, TestVolumeInfo) {
DisableDefaultSettings();
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceStorageStatus, true);
std::vector<std::string> expected_mount_points;
std::vector<em::VolumeInfo> expected_volume_info;
int size = 12345678;
for (const auto& mount_info :
DiskMountManager::GetInstance()->mount_points()) {
expected_mount_points.push_back(mount_info.first);
}
expected_mount_points.push_back(kExternalMountPoint);
for (const std::string& mount_point : expected_mount_points) {
em::VolumeInfo info;
info.set_volume_id(mount_point);
// Just put unique numbers in for storage_total/free.
info.set_storage_total(size++);
info.set_storage_free(size++);
expected_volume_info.push_back(info);
}
EXPECT_FALSE(expected_volume_info.empty());
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->volume_info_fetcher =
base::BindRepeating(&GetFakeVolumeInfo, expected_volume_info);
RestartStatusCollector(std::move(options));
// Force finishing tasks posted by ctor of DeviceStatusCollector.
content::RunAllTasksUntilIdle();
GetStatus();
EXPECT_EQ(expected_mount_points.size(),
static_cast<size_t>(device_status_.volume_infos_size()));
// Walk the returned VolumeInfo to make sure it matches.
for (const em::VolumeInfo& expected_info : expected_volume_info) {
bool found = false;
for (const em::VolumeInfo& info : device_status_.volume_infos()) {
if (info.volume_id() == expected_info.volume_id()) {
EXPECT_EQ(expected_info.storage_total(), info.storage_total());
EXPECT_EQ(expected_info.storage_free(), info.storage_free());
found = true;
break;
}
}
EXPECT_TRUE(found) << "No matching VolumeInfo for "
<< expected_info.volume_id();
}
}
TEST_F(DeviceStatusCollectorTest, TestSystemFreeRamInfo) {
DisableDefaultSettings();
const int sample_count =
static_cast<const int>(DeviceStatusCollector::kMaxResourceUsageSamples);
std::vector<int64_t> timestamp_lowerbounds;
std::vector<int64_t> timestamp_upperbounds;
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceMemoryInfo, true);
// Refresh our samples. Sample more than kMaxHardwareSamples times to
// make sure that the code correctly caps the number of cached samples.
status_collector_->RefreshSampleResourceUsage();
base::RunLoop().RunUntilIdle();
for (int i = 0; i < sample_count; ++i) {
timestamp_lowerbounds.push_back(base::Time::Now().ToJavaTime());
status_collector_->RefreshSampleResourceUsage();
base::RunLoop().RunUntilIdle();
timestamp_upperbounds.push_back(base::Time::Now().ToJavaTime());
}
GetStatus();
EXPECT_TRUE(device_status_.has_system_ram_total());
EXPECT_GT(device_status_.system_ram_total(), 0);
EXPECT_EQ(sample_count, device_status_.system_ram_free_infos().size());
for (int i = 0; i < sample_count; ++i) {
// Make sure 0 < free RAM < total Ram.
EXPECT_GT(device_status_.system_ram_free_infos(i).size_in_bytes(), 0);
EXPECT_LT(device_status_.system_ram_free_infos(i).size_in_bytes(),
device_status_.system_ram_total());
// Make sure timestamp is in a valid range though we cannot inject specific
// test values.
EXPECT_GE(device_status_.system_ram_free_infos(i).timestamp(),
timestamp_lowerbounds[i]);
EXPECT_LE(device_status_.system_ram_free_infos(i).timestamp(),
timestamp_upperbounds[i]);
}
}
TEST_F(DeviceStatusCollectorTest, TestCPUInfos) {
DisableDefaultSettings();
// Mock 100% CPU usage.
std::string full_cpu_usage("cpu 500 0 500 0 0 0 0");
int64_t timestamp_lowerbound = base::Time::Now().ToJavaTime();
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->cpu_fetcher =
base::BindRepeating(&GetFakeCPUStatistics, full_cpu_usage);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceCpuInfo, true);
RestartStatusCollector(std::move(options));
// Force finishing tasks posted by ctor of DeviceStatusCollector.
content::RunAllTasksUntilIdle();
int64_t timestamp_upperbound = base::Time::Now().ToJavaTime();
GetStatus();
ASSERT_EQ(1, device_status_.cpu_utilization_infos().size());
EXPECT_EQ(100, device_status_.cpu_utilization_infos(0).cpu_utilization_pct());
EXPECT_GE(device_status_.cpu_utilization_infos(0).timestamp(),
timestamp_lowerbound);
EXPECT_LE(device_status_.cpu_utilization_infos(0).timestamp(),
timestamp_upperbound);
// Now sample CPU usage again (active usage counters will not increase
// so should show 0% cpu usage).
timestamp_lowerbound = base::Time::Now().ToJavaTime();
status_collector_->RefreshSampleResourceUsage();
base::RunLoop().RunUntilIdle();
timestamp_upperbound = base::Time::Now().ToJavaTime();
GetStatus();
ASSERT_EQ(2, device_status_.cpu_utilization_infos().size());
EXPECT_EQ(0, device_status_.cpu_utilization_infos(1).cpu_utilization_pct());
EXPECT_GE(device_status_.cpu_utilization_infos(1).timestamp(),
timestamp_lowerbound);
EXPECT_LE(device_status_.cpu_utilization_infos(1).timestamp(),
timestamp_upperbound);
// Now store a bunch of 0% cpu usage and make sure we cap the max number of
// samples.
const int sample_count =
static_cast<const int>(DeviceStatusCollector::kMaxResourceUsageSamples);
std::vector<int64_t> timestamp_lowerbounds;
std::vector<int64_t> timestamp_upperbounds;
for (int i = 0; i < sample_count; ++i) {
timestamp_lowerbounds.push_back(base::Time::Now().ToJavaTime());
status_collector_->RefreshSampleResourceUsage();
base::RunLoop().RunUntilIdle();
timestamp_upperbounds.push_back(base::Time::Now().ToJavaTime());
}
GetStatus();
// Should not be more than kMaxResourceUsageSamples, and they should all show
// the CPU is idle.
EXPECT_EQ(sample_count, device_status_.cpu_utilization_infos().size());
for (int i = 0; i < sample_count; ++i) {
EXPECT_EQ(device_status_.cpu_utilization_infos(i).cpu_utilization_pct(), 0);
// Make sure timestamp is in a valid range though we cannot inject specific
// test values.
EXPECT_GE(device_status_.cpu_utilization_infos(i).timestamp(),
timestamp_lowerbounds[i]);
EXPECT_LE(device_status_.cpu_utilization_infos(i).timestamp(),
timestamp_upperbounds[i]);
}
}
TEST_F(DeviceStatusCollectorTest, TestCPUTemp) {
DisableDefaultSettings();
std::vector<em::CPUTempInfo> expected_temp_info;
int cpu_cnt = 12;
int64_t timestamp_lowerbound = base::Time::Now().ToJavaTime();
for (int i = 0; i < cpu_cnt; ++i) {
em::CPUTempInfo info;
info.set_cpu_temp(i * 10 + 100);
info.set_cpu_label(base::StringPrintf("Core %d", i));
info.set_timestamp(kFakeCpuTimestamp);
expected_temp_info.push_back(info);
}
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->cpu_temp_fetcher =
base::BindRepeating(&GetFakeCPUTempInfo, expected_temp_info);
RestartStatusCollector(std::move(options));
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceCpuInfo, true);
// Force finishing tasks posted by ctor of DeviceStatusCollector.
content::RunAllTasksUntilIdle();
GetStatus();
int64_t timestamp_upperbound = base::Time::Now().ToJavaTime();
EXPECT_EQ(expected_temp_info.size(),
static_cast<size_t>(device_status_.cpu_temp_infos_size()));
// Walk the returned CPUTempInfo to make sure it matches.
for (const em::CPUTempInfo& expected_info : expected_temp_info) {
bool found = false;
for (const em::CPUTempInfo& info : device_status_.cpu_temp_infos()) {
if (info.cpu_label() == expected_info.cpu_label()) {
EXPECT_EQ(expected_info.cpu_temp(), info.cpu_temp());
EXPECT_GE(info.timestamp(), timestamp_lowerbound);
EXPECT_LE(info.timestamp(), timestamp_upperbound);
found = true;
break;
}
}
EXPECT_TRUE(found) << "No matching CPUTempInfo for "
<< expected_info.cpu_label();
}
}
TEST_F(DeviceStatusCollectorTest, TestDiskLifetimeEstimation) {
DisableDefaultSettings();
em::DiskLifetimeEstimation est;
est.set_slc(10);
est.set_mlc(15);
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->emmc_lifetime_fetcher =
base::BindRepeating(&GetFakeEMMCLifetiemEstimation, est);
RestartStatusCollector(std::move(options));
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceStorageStatus, true);
// Force finishing tasks posted by ctor of DeviceStatusCollector.
content::RunAllTasksUntilIdle();
GetStatus();
EXPECT_TRUE(device_status_.storage_status().has_lifetime_estimation());
EXPECT_TRUE(device_status_.storage_status().lifetime_estimation().has_slc());
EXPECT_TRUE(device_status_.storage_status().lifetime_estimation().has_mlc());
EXPECT_EQ(est.slc(),
device_status_.storage_status().lifetime_estimation().slc());
EXPECT_EQ(est.mlc(),
device_status_.storage_status().lifetime_estimation().mlc());
}
TEST_F(DeviceStatusCollectorTest, KioskAndroidReporting) {
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->android_status_fetcher =
base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo);
RestartStatusCollector(std::move(options));
status_collector_->set_kiosk_account(
std::make_unique<DeviceLocalAccount>(fake_kiosk_device_local_account_));
MockRunningKioskApp(fake_kiosk_device_local_account_,
DeviceLocalAccount::TYPE_KIOSK_APP);
testing_profile_->GetPrefs()->SetBoolean(prefs::kReportArcStatusEnabled,
true);
GetStatus();
EXPECT_EQ(kArcStatus, session_status_.android_status().status_payload());
EXPECT_EQ(kDroidGuardInfo,
session_status_.android_status().droid_guard_info());
// Expect no User DM Token for kiosk sessions.
EXPECT_FALSE(session_status_.has_user_dm_token());
}
TEST_F(DeviceStatusCollectorTest, NoKioskAndroidReportingWhenDisabled) {
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->android_status_fetcher =
base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo);
RestartStatusCollector(std::move(options));
// Mock Kiosk app, so some session status is reported
status_collector_->set_kiosk_account(
std::make_unique<DeviceLocalAccount>(fake_kiosk_device_local_account_));
MockRunningKioskApp(fake_kiosk_device_local_account_,
DeviceLocalAccount::TYPE_KIOSK_APP);
GetStatus();
EXPECT_TRUE(got_session_status_);
// Note that this relies on the fact that kReportArcStatusEnabled is false by
// default.
EXPECT_FALSE(session_status_.has_android_status());
}
TEST_F(DeviceStatusCollectorTest, RegularUserAndroidReporting) {
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->android_status_fetcher =
base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo);
RestartStatusCollector(std::move(options));
const AccountId account_id(AccountId::FromUserEmail("user0@managed.com"));
MockRegularUserWithAffiliation(account_id, true);
testing_profile_->GetPrefs()->SetBoolean(prefs::kReportArcStatusEnabled,
true);
GetStatus();
EXPECT_TRUE(got_session_status_);
EXPECT_EQ(kArcStatus, session_status_.android_status().status_payload());
EXPECT_EQ(kDroidGuardInfo,
session_status_.android_status().droid_guard_info());
// In tests, GetUserDMToken returns the e-mail for easy verification.
EXPECT_EQ(account_id.GetUserEmail(), session_status_.user_dm_token());
}
TEST_F(DeviceStatusCollectorTest, RegularUserCrostiniReporting) {
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->android_status_fetcher =
base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo);
RestartStatusCollector(std::move(options));
const AccountId account_id(AccountId::FromUserEmail(kCrostiniUserEmail));
MockRegularUserWithAffiliation(account_id, true);
testing_profile_->GetPrefs()->SetBoolean(
crostini::prefs::kReportCrostiniUsageEnabled, true);
testing_profile_->GetPrefs()->SetString(
crostini::prefs::kCrostiniLastLaunchTerminaComponentVersion,
kTerminaVmComponentVersion);
testing_profile_->GetPrefs()->SetInt64(
crostini::prefs::kCrostiniLastLaunchTimeWindowStart,
kLastLaunchTimeWindowStartInJavaTime);
GetStatus();
EXPECT_TRUE(got_session_status_);
EXPECT_EQ(kLastLaunchTimeWindowStartInJavaTime,
session_status_.crostini_status()
.last_launch_time_window_start_timestamp());
EXPECT_EQ(kTerminaVmComponentVersion,
session_status_.crostini_status().last_launch_vm_image_version());
// In tests, GetUserDMToken returns the e-mail for easy verification.
EXPECT_EQ(account_id.GetUserEmail(), session_status_.user_dm_token());
}
TEST_F(DeviceStatusCollectorTest, RegularUserCrostiniReportingNoData) {
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->android_status_fetcher =
base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo);
RestartStatusCollector(std::move(options));
const AccountId account_id(AccountId::FromUserEmail(kCrostiniUserEmail));
MockRegularUserWithAffiliation(account_id, true);
testing_profile_->GetPrefs()->SetBoolean(
crostini::prefs::kReportCrostiniUsageEnabled, true);
GetStatus();
// Currently, only AndroidStatus and Crostini usage reporting is done for
// regular users. If there is no reporting in both cases, no
// UserSessionStatusRequest is filled at all. Note that this test case relies
// on the fact that kReportArcStatusEnabled is false by default.
EXPECT_FALSE(got_session_status_);
}
TEST_F(DeviceStatusCollectorTest, CrostiniTerminaVmKernelVersionReporting) {
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->android_status_fetcher =
base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo);
RestartStatusCollector(std::move(options));
// Prerequisites for any Crostini reporting to take place:
const AccountId account_id(AccountId::FromUserEmail(kCrostiniUserEmail));
MockRegularUserWithAffiliation(account_id, true);
testing_profile_->GetPrefs()->SetBoolean(
crostini::prefs::kReportCrostiniUsageEnabled, true);
testing_profile_->GetPrefs()->SetInt64(
crostini::prefs::kCrostiniLastLaunchTimeWindowStart,
kLastLaunchTimeWindowStartInJavaTime);
testing_profile_->GetPrefs()->SetBoolean(crostini::prefs::kCrostiniEnabled,
true);
// Set the kernel version to be reported in our cache:
testing_profile_->GetPrefs()->SetString(
crostini::prefs::kCrostiniLastLaunchTerminaKernelVersion,
kTerminaVmKernelVersion);
// Check that the kernel version is reported as to the feature flag default:
GetStatus();
EXPECT_TRUE(got_session_status_);
EXPECT_EQ(kTerminaVmKernelVersion,
session_status_.crostini_status().last_launch_vm_kernel_version());
// Check that nothing is reported when the feature flag is disabled:
scoped_feature_list_.InitAndDisableFeature(
features::kCrostiniAdditionalEnterpriseReporting);
GetStatus();
EXPECT_TRUE(got_session_status_);
EXPECT_TRUE(session_status_.crostini_status()
.last_launch_vm_kernel_version()
.empty());
}
TEST_F(DeviceStatusCollectorTest, CrostiniAppUsageReporting) {
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->android_status_fetcher =
base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo);
RestartStatusCollector(std::move(options));
const AccountId account_id(AccountId::FromUserEmail(kCrostiniUserEmail));
MockRegularUserWithAffiliation(account_id, true);
testing_profile_->GetPrefs()->SetBoolean(
crostini::prefs::kReportCrostiniUsageEnabled, true);
testing_profile_->GetPrefs()->SetString(
crostini::prefs::kCrostiniLastLaunchTerminaComponentVersion,
kTerminaVmComponentVersion);
testing_profile_->GetPrefs()->SetInt64(
crostini::prefs::kCrostiniLastLaunchTimeWindowStart,
kLastLaunchTimeWindowStartInJavaTime);
testing_profile_->GetPrefs()->SetBoolean(crostini::prefs::kCrostiniEnabled,
true);
scoped_feature_list_.InitAndEnableFeature(
features::kCrostiniAdditionalEnterpriseReporting);
const std::string desktop_file_id = "vim";
const std::string package_id =
"vim;2:8.0.0197-4+deb9u1;amd64;installed:debian-stable";
vm_tools::apps::ApplicationList app_list =
crostini::CrostiniTestHelper::BasicAppList(
desktop_file_id, crostini::kCrostiniDefaultVmName,
crostini::kCrostiniDefaultContainerName);
app_list.mutable_apps(0)->set_package_id(package_id);
auto* registry_service =
guest_os::GuestOsRegistryServiceFactory::GetForProfile(
testing_profile_.get());
registry_service->UpdateApplicationList(app_list);
base::Time last_launch_time;
EXPECT_TRUE(base::Time::FromString(kActualLastLaunchTimeFormatted,
&last_launch_time));
test_clock_.SetNow(last_launch_time);
registry_service->SetClockForTesting(&test_clock_);
registry_service->AppLaunched(crostini::CrostiniTestHelper::GenerateAppId(
desktop_file_id, crostini::kCrostiniDefaultVmName,
crostini::kCrostiniDefaultContainerName));
GetStatus();
EXPECT_TRUE(got_session_status_);
EXPECT_EQ(2, session_status_.crostini_status().installed_apps_size());
EXPECT_EQ(desktop_file_id,
session_status_.crostini_status().installed_apps()[0].app_name());
EXPECT_EQ(em::CROSTINI_APP_TYPE_INTERACTIVE,
session_status_.crostini_status().installed_apps()[0].app_type());
base::Time last_launch_time_coarsed;
EXPECT_TRUE(base::Time::FromString(kLastLaunchTimeWindowStartFormatted,
&last_launch_time_coarsed));
EXPECT_EQ(kLastLaunchTimeWindowStartInJavaTime,
session_status_.crostini_status()
.installed_apps()[0]
.last_launch_time_window_start_timestamp());
EXPECT_EQ(
"vim",
session_status_.crostini_status().installed_apps()[0].package_name());
EXPECT_EQ(
"2:8.0.0197-4+deb9u1",
session_status_.crostini_status().installed_apps()[0].package_version());
EXPECT_EQ("Terminal",
session_status_.crostini_status().installed_apps()[1].app_name());
EXPECT_EQ(em::CROSTINI_APP_TYPE_TERMINAL,
session_status_.crostini_status().installed_apps()[1].app_type());
EXPECT_EQ(
std::string(),
session_status_.crostini_status().installed_apps()[1].package_name());
EXPECT_EQ(
std::string(),
session_status_.crostini_status().installed_apps()[1].package_version());
EXPECT_EQ(0, session_status_.crostini_status()
.installed_apps()[1]
.last_launch_time_window_start_timestamp());
// In tests, GetUserDMToken returns the e-mail for easy verification.
EXPECT_EQ(account_id.GetUserEmail(), session_status_.user_dm_token());
}
TEST_F(DeviceStatusCollectorTest,
TerminalAppIsNotReportedIfCrostiniHasBeenRemoved) {
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->android_status_fetcher =
base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo);
RestartStatusCollector(std::move(options));
const AccountId account_id(AccountId::FromUserEmail(kCrostiniUserEmail));
MockRegularUserWithAffiliation(account_id, true);
testing_profile_->GetPrefs()->SetBoolean(
crostini::prefs::kReportCrostiniUsageEnabled, true);
testing_profile_->GetPrefs()->SetString(
crostini::prefs::kCrostiniLastLaunchTerminaComponentVersion,
kTerminaVmComponentVersion);
testing_profile_->GetPrefs()->SetInt64(
crostini::prefs::kCrostiniLastLaunchTimeWindowStart,
kLastLaunchTimeWindowStartInJavaTime);
testing_profile_->GetPrefs()->SetBoolean(crostini::prefs::kCrostiniEnabled,
false);
scoped_feature_list_.InitAndEnableFeature(
features::kCrostiniAdditionalEnterpriseReporting);
GetStatus();
EXPECT_TRUE(got_session_status_);
// crostini::prefs::kCrostiniEnabled is set to false, but there
// is general last launch information. This means Crostini has been
// disabled after it has been used. We still report general last launch
// information but do not want to jump into application reporting, because
// the registry always has the terminal, even if Crostini has been
// uninstalled.
EXPECT_EQ(kLastLaunchTimeWindowStartInJavaTime,
session_status_.crostini_status()
.last_launch_time_window_start_timestamp());
EXPECT_EQ(0, session_status_.crostini_status().installed_apps_size());
}
TEST_F(DeviceStatusCollectorTest, NoRegularUserReportingByDefault) {
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->android_status_fetcher =
base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo);
RestartStatusCollector(std::move(options));
const AccountId account_id(AccountId::FromUserEmail("user0@managed.com"));
MockRegularUserWithAffiliation(account_id, true);
GetStatus();
// Currently, only AndroidStatus and Crostini usage reporting is done for
// regular users. If both are disabled, no UserSessionStatusRequest is filled
// at all. Note that this test case relies on the fact that
// kReportArcStatusEnabled and kReportCrostiniUsageEnabled are false by
// default.
EXPECT_FALSE(got_session_status_);
}
TEST_F(DeviceStatusCollectorTest,
NoRegularUserAndroidReportingWhenNotAffiliated) {
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->android_status_fetcher =
base::BindRepeating(&GetFakeAndroidStatus, kArcStatus, kDroidGuardInfo);
RestartStatusCollector(std::move(options));
const AccountId account_id(AccountId::FromUserEmail("user0@managed.com"));
MockRegularUserWithAffiliation(account_id, false);
testing_profile_->GetPrefs()->SetBoolean(prefs::kReportArcStatusEnabled,
true);
GetStatus();
// Currently, only AndroidStatus reporting is done for regular users. If that
// is disabled, no UserSessionStatusRequest is filled at all.
EXPECT_FALSE(got_session_status_);
}
TEST_F(DeviceStatusCollectorTest, TpmStatusReporting) {
DisableDefaultSettings();
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceSecurityStatus, true);
auto* tpm_status_reply = chromeos::TpmManagerClient::Get()
->GetTestInterface()
->mutable_nonsensitive_status_reply();
tpm_status_reply->set_is_enabled(true);
tpm_status_reply->set_is_owned(true);
tpm_status_reply->set_is_owner_password_present(false);
auto* enrollment_status_reply = chromeos::AttestationClient::Get()
->GetTestInterface()
->mutable_status_reply();
enrollment_status_reply->set_prepared_for_enrollment(true);
enrollment_status_reply->set_enrolled(false);
auto* da_info_reply = chromeos::TpmManagerClient::Get()
->GetTestInterface()
->mutable_dictionary_attack_info_reply();
da_info_reply->set_dictionary_attack_counter(5);
da_info_reply->set_dictionary_attack_threshold(10);
da_info_reply->set_dictionary_attack_lockout_in_effect(false);
da_info_reply->set_dictionary_attack_lockout_seconds_remaining(0);
auto* supported_features_reply = chromeos::TpmManagerClient::Get()
->GetTestInterface()
->mutable_supported_features_reply();
supported_features_reply->set_is_allowed(false);
supported_features_reply->set_support_pinweaver(false);
supported_features_reply->set_support_runtime_selection(false);
supported_features_reply->set_support_u2f(false);
GetStatus();
EXPECT_TRUE(device_status_.has_tpm_status_info());
EXPECT_EQ(tpm_status_reply->is_enabled(),
device_status_.tpm_status_info().enabled());
EXPECT_EQ(tpm_status_reply->is_owned(),
device_status_.tpm_status_info().owned());
EXPECT_EQ(tpm_status_reply->is_owned() &&
!tpm_status_reply->is_owner_password_present(),
device_status_.tpm_status_info().tpm_initialized());
EXPECT_EQ(enrollment_status_reply->prepared_for_enrollment(),
device_status_.tpm_status_info().attestation_prepared());
EXPECT_EQ(enrollment_status_reply->enrolled(),
device_status_.tpm_status_info().attestation_enrolled());
EXPECT_EQ(static_cast<int32_t>(da_info_reply->dictionary_attack_counter()),
device_status_.tpm_status_info().dictionary_attack_counter());
EXPECT_EQ(static_cast<int32_t>(da_info_reply->dictionary_attack_threshold()),
device_status_.tpm_status_info().dictionary_attack_threshold());
EXPECT_EQ(
da_info_reply->dictionary_attack_lockout_in_effect(),
device_status_.tpm_status_info().dictionary_attack_lockout_in_effect());
EXPECT_EQ(static_cast<int32_t>(
da_info_reply->dictionary_attack_lockout_seconds_remaining()),
device_status_.tpm_status_info()
.dictionary_attack_lockout_seconds_remaining());
EXPECT_EQ(false, device_status_.tpm_status_info().boot_lockbox_finalized());
EXPECT_EQ(tpm_status_reply->is_owner_password_present(),
device_status_.tpm_status_info().owner_password_is_present());
EXPECT_EQ(
supported_features_reply->is_allowed(),
device_status_.tpm_status_info().tpm_supported_features().is_allowed());
EXPECT_EQ(supported_features_reply->support_pinweaver(),
device_status_.tpm_status_info()
.tpm_supported_features()
.support_pinweaver());
EXPECT_EQ(supported_features_reply->support_runtime_selection(),
device_status_.tpm_status_info()
.tpm_supported_features()
.support_runtime_selection());
EXPECT_EQ(
supported_features_reply->support_u2f(),
device_status_.tpm_status_info().tpm_supported_features().support_u2f());
}
// Checks if tpm status is partially reported even if any error happens
// among the multiple D-Bus calls.
TEST_F(DeviceStatusCollectorTest, TpmStatusReportingAnyDBusError) {
DisableDefaultSettings();
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceSecurityStatus, true);
auto* tpm_status_reply = chromeos::TpmManagerClient::Get()
->GetTestInterface()
->mutable_nonsensitive_status_reply();
auto* enrollment_status_reply = chromeos::AttestationClient::Get()
->GetTestInterface()
->mutable_status_reply();
auto* da_info_reply = chromeos::TpmManagerClient::Get()
->GetTestInterface()
->mutable_dictionary_attack_info_reply();
auto* supported_features_reply = chromeos::TpmManagerClient::Get()
->GetTestInterface()
->mutable_supported_features_reply();
tpm_status_reply->set_status(::tpm_manager::STATUS_DBUS_ERROR);
enrollment_status_reply->set_prepared_for_enrollment(true);
GetStatus();
EXPECT_EQ(enrollment_status_reply->prepared_for_enrollment(),
device_status_.tpm_status_info().attestation_prepared());
EXPECT_TRUE(device_status_.tpm_status_info().has_tpm_supported_features());
// Reset the error status.
tpm_status_reply->set_status(::tpm_manager::STATUS_SUCCESS);
RestartStatusCollector();
enrollment_status_reply->set_status(::attestation::STATUS_DBUS_ERROR);
da_info_reply->set_dictionary_attack_counter(5);
GetStatus();
// Reset the error status.
EXPECT_EQ(static_cast<int32_t>(da_info_reply->dictionary_attack_counter()),
device_status_.tpm_status_info().dictionary_attack_counter());
// Reset the error status.
enrollment_status_reply->set_status(::attestation::STATUS_SUCCESS);
RestartStatusCollector();
da_info_reply->set_status(::tpm_manager::STATUS_DBUS_ERROR);
tpm_status_reply->set_is_enabled(true);
GetStatus();
EXPECT_TRUE(device_status_.has_tpm_status_info());
EXPECT_EQ(tpm_status_reply->is_enabled(),
device_status_.tpm_status_info().enabled());
// Reset the error status.
da_info_reply->set_status(::tpm_manager::STATUS_SUCCESS);
RestartStatusCollector();
supported_features_reply->set_status(::tpm_manager::STATUS_DBUS_ERROR);
tpm_status_reply->set_is_enabled(true);
GetStatus();
EXPECT_TRUE(device_status_.has_tpm_status_info());
EXPECT_EQ(tpm_status_reply->is_enabled(),
device_status_.tpm_status_info().enabled());
EXPECT_FALSE(device_status_.tpm_status_info().has_tpm_supported_features());
// Reset the error status (for symmetry).
supported_features_reply->set_status(::tpm_manager::STATUS_SUCCESS);
}
TEST_F(DeviceStatusCollectorTest, NoTimeZoneReporting) {
// Time zone is not reported in enterprise reports.
const AccountId account_id(AccountId::FromUserEmail("user0@managed.com"));
MockRegularUserWithAffiliation(account_id, true);
GetStatus();
EXPECT_FALSE(session_status_.has_time_zone());
}
TEST_F(DeviceStatusCollectorTest, NoSessionStatusIfNoSession) {
// Should not report session status if we don't have an active kiosk app or an
// active user session.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceSessionStatus, true);
GetStatus();
EXPECT_FALSE(got_session_status_);
}
TEST_F(DeviceStatusCollectorTest, NoSessionStatusIfSessionReportingDisabled) {
// Should not report session status if session status reporting is disabled.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceSessionStatus, false);
// ReportDeviceSessionStatus only controls Kiosk reporting, ARC reporting
// has to be disabled serarately.
status_collector_->set_kiosk_account(
std::make_unique<policy::DeviceLocalAccount>(
fake_kiosk_device_local_account_));
// Set up a device-local account for single-app kiosk mode.
MockRunningKioskApp(fake_kiosk_device_local_account_,
DeviceLocalAccount::TYPE_KIOSK_APP);
testing_profile_->GetPrefs()->SetBoolean(prefs::kReportArcStatusEnabled,
false);
GetStatus();
EXPECT_FALSE(got_session_status_);
}
TEST_F(DeviceStatusCollectorTest, ReportKioskSessionStatus) {
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceSessionStatus, true);
status_collector_->set_kiosk_account(
std::make_unique<policy::DeviceLocalAccount>(
fake_kiosk_device_local_account_));
// Set up a device-local account for single-app kiosk mode.
MockRunningKioskApp(fake_kiosk_device_local_account_,
DeviceLocalAccount::TYPE_KIOSK_APP);
GetStatus();
EXPECT_TRUE(got_session_status_);
ASSERT_EQ(1, session_status_.installed_apps_size());
EXPECT_EQ(kKioskAccountId, session_status_.device_local_account_id());
const em::AppStatus app = session_status_.installed_apps(0);
EXPECT_EQ(kKioskAppId, app.app_id());
// Test code just sets the version to the app ID.
EXPECT_EQ(kKioskAppId, app.extension_version());
EXPECT_FALSE(app.has_status());
EXPECT_FALSE(app.has_error());
// Expect no User DM Token for kiosk sessions.
EXPECT_FALSE(session_status_.has_user_dm_token());
}
TEST_F(DeviceStatusCollectorTest, ReportArcKioskSessionStatus) {
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceSessionStatus, true);
status_collector_->set_kiosk_account(
std::make_unique<policy::DeviceLocalAccount>(
fake_arc_kiosk_device_local_account_));
// Set up a device-local account for single-app ARC kiosk mode.
MockRunningKioskApp(fake_arc_kiosk_device_local_account_,
DeviceLocalAccount::TYPE_ARC_KIOSK_APP);
GetStatus();
EXPECT_TRUE(got_session_status_);
ASSERT_EQ(1, session_status_.installed_apps_size());
EXPECT_EQ(kArcKioskAccountId, session_status_.device_local_account_id());
const em::AppStatus app = session_status_.installed_apps(0);
EXPECT_EQ(kArcKioskPackageName, app.app_id());
EXPECT_TRUE(app.extension_version().empty());
EXPECT_FALSE(app.has_status());
EXPECT_FALSE(app.has_error());
// Expect no User DM Token for kiosk sessions.
EXPECT_FALSE(session_status_.has_user_dm_token());
}
TEST_F(DeviceStatusCollectorTest, ReportWebKioskSessionStatus) {
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceSessionStatus, true);
status_collector_->set_kiosk_account(
std::make_unique<policy::DeviceLocalAccount>(
fake_web_kiosk_device_local_account_));
// Set up a device-local account for single-app Web kiosk mode.
MockRunningKioskApp(fake_web_kiosk_device_local_account_,
DeviceLocalAccount::TYPE_WEB_KIOSK_APP);
GetStatus();
EXPECT_TRUE(got_session_status_);
ASSERT_EQ(1, session_status_.installed_apps_size());
EXPECT_EQ(kWebKioskAccountId, session_status_.device_local_account_id());
const em::AppStatus app = session_status_.installed_apps(0);
EXPECT_EQ(kWebKioskAppUrl, app.app_id());
EXPECT_FALSE(app.has_status());
EXPECT_FALSE(app.has_error());
// Expect no User DM Token for kiosk sessions.
EXPECT_FALSE(session_status_.has_user_dm_token());
}
TEST_F(DeviceStatusCollectorTest, NoOsUpdateStatusByDefault) {
auto scoped_version = MockPlatformVersion(kDefaultPlatformVersion);
MockAutoLaunchKioskAppWithRequiredPlatformVersion(
fake_kiosk_device_local_account_, kDefaultPlatformVersion);
GetStatus();
EXPECT_FALSE(device_status_.has_os_update_status());
}
TEST_F(DeviceStatusCollectorTest, ReportOsUpdateStatusUpToDate) {
DisableDefaultSettings();
auto scoped_version = MockPlatformVersion(kDefaultPlatformVersion);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportOsUpdateStatus, true);
const char* kRequiredPlatformVersions[] = {"1234", "1234.0", "1234.0.0"};
for (size_t i = 0; i < std::size(kRequiredPlatformVersions); ++i) {
MockAutoLaunchKioskAppWithRequiredPlatformVersion(
fake_kiosk_device_local_account_, kRequiredPlatformVersions[i]);
GetStatus();
ASSERT_TRUE(device_status_.has_os_update_status())
<< "Required platform version=" << kRequiredPlatformVersions[i];
EXPECT_EQ(em::OsUpdateStatus::OS_UP_TO_DATE,
device_status_.os_update_status().update_status())
<< "Required platform version=" << kRequiredPlatformVersions[i];
EXPECT_EQ(kRequiredPlatformVersions[i],
device_status_.os_update_status().new_required_platform_version())
<< "Required platform version=" << kRequiredPlatformVersions[i];
}
}
TEST_F(DeviceStatusCollectorTest, ReportOsUpdateStatusUpToDate_NonKiosk) {
DisableDefaultSettings();
auto scoped_version = MockPlatformVersion(kDefaultPlatformVersion);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportOsUpdateStatus, true);
GetStatus();
ASSERT_TRUE(device_status_.has_os_update_status());
EXPECT_EQ(em::OsUpdateStatus::OS_UP_TO_DATE,
device_status_.os_update_status().update_status());
ASSERT_TRUE(device_status_.os_update_status().has_last_checked_timestamp());
ASSERT_TRUE(device_status_.os_update_status().has_last_reboot_timestamp());
ASSERT_FALSE(device_status_.os_update_status().has_new_platform_version());
}
TEST_F(DeviceStatusCollectorTest, ReportOsUpdateStatus) {
DisableDefaultSettings();
auto scoped_version = MockPlatformVersion(kDefaultPlatformVersion);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportOsUpdateStatus, true);
MockAutoLaunchKioskAppWithRequiredPlatformVersion(
fake_kiosk_device_local_account_, "1235");
update_engine::StatusResult update_status;
update_status.set_current_operation(update_engine::Operation::IDLE);
GetStatus();
ASSERT_TRUE(device_status_.has_os_update_status());
EXPECT_EQ(em::OsUpdateStatus::OS_IMAGE_DOWNLOAD_NOT_STARTED,
device_status_.os_update_status().update_status());
const update_engine::Operation kUpdateEngineOps[] = {
update_engine::Operation::DOWNLOADING,
update_engine::Operation::VERIFYING,
update_engine::Operation::FINALIZING,
};
for (size_t i = 0; i < std::size(kUpdateEngineOps); ++i) {
update_status.set_current_operation(kUpdateEngineOps[i]);
update_status.set_new_version("1235.1.2");
update_engine_client_->PushLastStatus(update_status);
GetStatus();
ASSERT_TRUE(device_status_.has_os_update_status());
EXPECT_EQ(em::OsUpdateStatus::OS_IMAGE_DOWNLOAD_IN_PROGRESS,
device_status_.os_update_status().update_status());
EXPECT_EQ("1235.1.2",
device_status_.os_update_status().new_platform_version());
EXPECT_EQ(
"1235",
device_status_.os_update_status().new_required_platform_version());
}
update_status.set_current_operation(
update_engine::Operation::UPDATED_NEED_REBOOT);
update_engine_client_->PushLastStatus(update_status);
GetStatus();
ASSERT_TRUE(device_status_.has_os_update_status());
EXPECT_EQ(em::OsUpdateStatus::OS_UPDATE_NEED_REBOOT,
device_status_.os_update_status().update_status());
}
TEST_F(DeviceStatusCollectorTest, ReportOsUpdateStatus_NonKiosk) {
DisableDefaultSettings();
auto scoped_version = MockPlatformVersion(kDefaultPlatformVersion);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportOsUpdateStatus, true);
update_engine::StatusResult update_status;
update_status.set_current_operation(update_engine::Operation::IDLE);
GetStatus();
ASSERT_TRUE(device_status_.has_os_update_status());
EXPECT_EQ(em::OsUpdateStatus::OS_UP_TO_DATE,
device_status_.os_update_status().update_status());
ASSERT_TRUE(device_status_.os_update_status().has_last_checked_timestamp());
ASSERT_TRUE(device_status_.os_update_status().has_last_reboot_timestamp());
ASSERT_FALSE(
device_status_.os_update_status().has_new_required_platform_version());
const update_engine::Operation kUpdateEngineOps[] = {
update_engine::Operation::DOWNLOADING,
update_engine::Operation::VERIFYING,
update_engine::Operation::FINALIZING,
};
for (size_t i = 0; i < std::size(kUpdateEngineOps); ++i) {
update_status.set_current_operation(kUpdateEngineOps[i]);
update_status.set_new_version("1235.1.2");
update_engine_client_->PushLastStatus(update_status);
GetStatus();
ASSERT_TRUE(device_status_.has_os_update_status());
EXPECT_EQ(em::OsUpdateStatus::OS_IMAGE_DOWNLOAD_IN_PROGRESS,
device_status_.os_update_status().update_status());
EXPECT_EQ("1235.1.2",
device_status_.os_update_status().new_platform_version());
ASSERT_TRUE(device_status_.os_update_status().has_last_checked_timestamp());
ASSERT_TRUE(device_status_.os_update_status().has_last_reboot_timestamp());
ASSERT_FALSE(
device_status_.os_update_status().has_new_required_platform_version());
}
update_status.set_current_operation(
update_engine::Operation::UPDATED_NEED_REBOOT);
update_engine_client_->PushLastStatus(update_status);
GetStatus();
ASSERT_TRUE(device_status_.has_os_update_status());
EXPECT_EQ(em::OsUpdateStatus::OS_UPDATE_NEED_REBOOT,
device_status_.os_update_status().update_status());
ASSERT_TRUE(device_status_.os_update_status().has_last_checked_timestamp());
ASSERT_TRUE(device_status_.os_update_status().has_last_reboot_timestamp());
ASSERT_FALSE(
device_status_.os_update_status().has_new_required_platform_version());
}
TEST_F(DeviceStatusCollectorTest, NoLastCheckedTimestampByDefault) {
auto scoped_version = MockPlatformVersion(kDefaultPlatformVersion);
MockAutoLaunchKioskAppWithRequiredPlatformVersion(
fake_kiosk_device_local_account_, kDefaultPlatformVersion);
GetStatus();
EXPECT_FALSE(device_status_.os_update_status().has_last_checked_timestamp());
}
TEST_F(DeviceStatusCollectorTest, ReportLastCheckedTimestamp) {
DisableDefaultSettings();
auto scoped_version = MockPlatformVersion(kDefaultPlatformVersion);
MockAutoLaunchKioskAppWithRequiredPlatformVersion(
fake_kiosk_device_local_account_, kDefaultPlatformVersion);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportOsUpdateStatus, true);
// Check update multiple times, the timestamp stored in device status should
// change accordingly.
const int64 kLastCheckedTimes[] = {10, 20, 30};
for (size_t i = 0; i < std::size(kLastCheckedTimes); ++i) {
update_engine::StatusResult update_status;
update_status.set_new_version(kDefaultPlatformVersion);
update_status.set_last_checked_time(kLastCheckedTimes[i]);
update_engine_client_->PushLastStatus(update_status);
GetStatus();
ASSERT_TRUE(device_status_.os_update_status().has_last_checked_timestamp());
// The timestamp precision in UpdateEngine is in seconds, but the
// DeviceStatusCollector is in milliseconds. Therefore, the number should be
// multiplied by 1000 before validation.
ASSERT_EQ(kLastCheckedTimes[i] * 1000,
device_status_.os_update_status().last_checked_timestamp());
}
}
TEST_F(DeviceStatusCollectorTest, NoLastRebootTimestampByDefault) {
auto scoped_version = MockPlatformVersion(kDefaultPlatformVersion);
MockAutoLaunchKioskAppWithRequiredPlatformVersion(
fake_kiosk_device_local_account_, kDefaultPlatformVersion);
GetStatus();
EXPECT_FALSE(device_status_.os_update_status().has_last_reboot_timestamp());
}
TEST_F(DeviceStatusCollectorTest, ReportLastRebootTimestamp) {
DisableDefaultSettings();
auto scoped_version = MockPlatformVersion(kDefaultPlatformVersion);
MockAutoLaunchKioskAppWithRequiredPlatformVersion(
fake_kiosk_device_local_account_, kDefaultPlatformVersion);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportOsUpdateStatus, true);
GetStatus();
ASSERT_TRUE(device_status_.os_update_status().has_last_reboot_timestamp());
// No good way to inject specific last reboot timestamp of the test machine,
// so just make sure UnixEpoch < RebootTime < Now.
EXPECT_GT(device_status_.os_update_status().last_reboot_timestamp(),
base::Time::UnixEpoch().ToJavaTime());
EXPECT_LT(device_status_.os_update_status().last_reboot_timestamp(),
base::Time::Now().ToJavaTime());
}
TEST_F(DeviceStatusCollectorTest, NoRunningKioskAppByDefault) {
auto scoped_version = MockPlatformVersion(kDefaultPlatformVersion);
MockAutoLaunchKioskAppWithRequiredPlatformVersion(
fake_kiosk_device_local_account_, kDefaultPlatformVersion);
status_collector_->set_kiosk_account(
std::make_unique<policy::DeviceLocalAccount>(
fake_kiosk_device_local_account_));
MockRunningKioskApp(fake_kiosk_device_local_account_,
DeviceLocalAccount::TYPE_KIOSK_APP);
GetStatus();
EXPECT_FALSE(device_status_.has_running_kiosk_app());
}
TEST_F(DeviceStatusCollectorTest, NoRunningKioskAppWhenNotInKioskSession) {
DisableDefaultSettings();
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportRunningKioskApp, true);
auto scoped_version = MockPlatformVersion(kDefaultPlatformVersion);
MockAutoLaunchKioskAppWithRequiredPlatformVersion(
fake_kiosk_device_local_account_, kDefaultPlatformVersion);
GetStatus();
EXPECT_FALSE(device_status_.has_running_kiosk_app());
}
TEST_F(DeviceStatusCollectorTest, ReportRunningKioskApp) {
DisableDefaultSettings();
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportRunningKioskApp, true);
auto scoped_version = MockPlatformVersion(kDefaultPlatformVersion);
MockAutoLaunchKioskAppWithRequiredPlatformVersion(
fake_kiosk_device_local_account_, "1235");
MockRunningKioskApp(fake_kiosk_device_local_account_,
DeviceLocalAccount::TYPE_KIOSK_APP);
status_collector_->set_kiosk_account(
std::make_unique<policy::DeviceLocalAccount>(
fake_kiosk_device_local_account_));
GetStatus();
ASSERT_TRUE(device_status_.has_running_kiosk_app());
const em::AppStatus app = device_status_.running_kiosk_app();
EXPECT_EQ(kKioskAppId, app.app_id());
EXPECT_EQ("1235", app.required_platform_version());
EXPECT_FALSE(app.has_status());
EXPECT_FALSE(app.has_error());
}
TEST_F(DeviceStatusCollectorTest, ReportRunningArcKioskApp) {
DisableDefaultSettings();
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportRunningKioskApp, true);
MockAutoLaunchArcKioskApp(fake_arc_kiosk_device_local_account_);
MockRunningKioskApp(fake_arc_kiosk_device_local_account_,
DeviceLocalAccount::TYPE_ARC_KIOSK_APP);
status_collector_->set_kiosk_account(
std::make_unique<policy::DeviceLocalAccount>(
fake_arc_kiosk_device_local_account_));
GetStatus();
ASSERT_TRUE(device_status_.has_running_kiosk_app());
const em::AppStatus app = device_status_.running_kiosk_app();
EXPECT_EQ(kArcKioskPackageName, app.app_id());
EXPECT_TRUE(app.extension_version().empty());
EXPECT_TRUE(app.required_platform_version().empty());
EXPECT_FALSE(app.has_status());
EXPECT_FALSE(app.has_error());
}
TEST_F(DeviceStatusCollectorTest, ReportRunningWebKioskApp) {
DisableDefaultSettings();
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportRunningKioskApp, true);
MockAutoLaunchWebKioskApp(fake_web_kiosk_device_local_account_);
MockRunningKioskApp(fake_web_kiosk_device_local_account_,
DeviceLocalAccount::TYPE_WEB_KIOSK_APP);
status_collector_->set_kiosk_account(
std::make_unique<policy::DeviceLocalAccount>(
fake_web_kiosk_device_local_account_));
GetStatus();
ASSERT_TRUE(device_status_.has_running_kiosk_app());
const em::AppStatus app = device_status_.running_kiosk_app();
EXPECT_EQ(kWebKioskAppUrl, app.app_id());
EXPECT_FALSE(app.has_status());
EXPECT_FALSE(app.has_error());
}
TEST_F(DeviceStatusCollectorTest, TestSoundVolume) {
// Expect the sound volume to be reported by default (default sound volume
// used in testing is 75).
GetStatus();
EXPECT_EQ(75, device_status_.sound_volume());
// When the pref to collect this data is not enabled, expect that the field
// isn't present in the protobuf.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceAudioStatus, false);
GetStatus();
EXPECT_FALSE(device_status_.has_sound_volume());
// Try setting a custom volume value and check that it matches.
DisableDefaultSettings();
const int kCustomVolume = 42;
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceAudioStatus, true);
chromeos::CrasAudioHandler::Get()->SetOutputVolumePercent(kCustomVolume);
GetStatus();
EXPECT_EQ(kCustomVolume, device_status_.sound_volume());
}
TEST_F(DeviceStatusCollectorTest, TestStatefulPartitionInfo) {
DisableDefaultSettings();
// Create a fake stateful partition info and populate it with some arbitrary
// values.
em::StatefulPartitionInfo fakeStatefulPartitionInfo;
fakeStatefulPartitionInfo.set_available_space(350);
fakeStatefulPartitionInfo.set_total_space(500);
fakeStatefulPartitionInfo.set_mount_source("mount_source");
fakeStatefulPartitionInfo.set_filesystem(kFilesystem);
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->stateful_partition_info_fetcher = base::BindRepeating(
&GetFakeStatefulPartitionInfo, fakeStatefulPartitionInfo);
RestartStatusCollector(std::move(options));
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceStorageStatus, true);
GetStatus();
EXPECT_TRUE(device_status_.has_stateful_partition_info());
EXPECT_EQ(fakeStatefulPartitionInfo.available_space(),
device_status_.stateful_partition_info().available_space());
EXPECT_EQ(fakeStatefulPartitionInfo.total_space(),
device_status_.stateful_partition_info().total_space());
EXPECT_EQ(fakeStatefulPartitionInfo.mount_source(),
device_status_.stateful_partition_info().mount_source());
EXPECT_EQ(fakeStatefulPartitionInfo.filesystem(),
device_status_.stateful_partition_info().filesystem());
}
TEST_F(DeviceStatusCollectorTest, TestGraphicsStatus) {
DisableDefaultSettings();
// Create a fake graphics status and populate it with some arbitrary values.
em::GraphicsStatus fakeGraphicsStatus;
// Create a fake display and populate it with some arbitrary values.
uint64 num_displays = 0;
for (uint64 i = 0; i < num_displays; i++) {
em::DisplayInfo* display_info = fakeGraphicsStatus.add_displays();
display_info->set_resolution_width(1920 * i);
display_info->set_resolution_height(1080 * i);
display_info->set_refresh_rate(60 * i);
display_info->set_is_internal(i == 1);
}
em::GraphicsAdapterInfo* graphics_info = fakeGraphicsStatus.mutable_adapter();
graphics_info->set_name("fake_adapter_name");
graphics_info->set_driver_version("fake_driver_version");
graphics_info->set_device_id(12345);
graphics_info->set_system_ram_usage(15 * 1024 * 1024);
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->graphics_status_fetcher =
base::BindRepeating(&GetFakeGraphicsStatus, fakeGraphicsStatus);
RestartStatusCollector(std::move(options));
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceGraphicsStatus, true);
GetStatus();
EXPECT_TRUE(device_status_.has_graphics_status());
for (uint64 i = 0; i < num_displays; i++) {
EXPECT_EQ(fakeGraphicsStatus.displays(i).resolution_width(),
device_status_.graphics_status().displays(i).resolution_width());
EXPECT_EQ(fakeGraphicsStatus.displays(i).resolution_height(),
device_status_.graphics_status().displays(i).resolution_height());
EXPECT_EQ(fakeGraphicsStatus.displays(i).refresh_rate(),
device_status_.graphics_status().displays(i).refresh_rate());
EXPECT_EQ(fakeGraphicsStatus.displays(i).is_internal(),
device_status_.graphics_status().displays(i).is_internal());
}
EXPECT_EQ(fakeGraphicsStatus.adapter().name(),
device_status_.graphics_status().adapter().name());
EXPECT_EQ(fakeGraphicsStatus.adapter().driver_version(),
device_status_.graphics_status().adapter().driver_version());
EXPECT_EQ(fakeGraphicsStatus.adapter().device_id(),
device_status_.graphics_status().adapter().device_id());
EXPECT_EQ(fakeGraphicsStatus.adapter().system_ram_usage(),
device_status_.graphics_status().adapter().system_ram_usage());
// Change the policy to not report display and graphics statuses
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceGraphicsStatus, false);
GetStatus();
EXPECT_FALSE(device_status_.has_graphics_status());
}
TEST_F(DeviceStatusCollectorTest, TestCrashReportInfo) {
DisableDefaultSettings();
// Create sample crash reports.
std::vector<em::CrashReportInfo> expected_crash_report_infos;
const base::Time now = base::Time::Now();
const int report_cnt = 5;
for (int i = 0; i < report_cnt; ++i) {
base::Time timestamp = now - base::Hours(30) * i;
em::CrashReportInfo info;
info.set_capture_timestamp(timestamp.ToJavaTime());
info.set_remote_id(base::StringPrintf("remote_id %d", i));
info.set_cause(base::StringPrintf("cause %d", i));
info.set_upload_status(em::CrashReportInfo::UPLOAD_STATUS_UPLOADED);
expected_crash_report_infos.push_back(info);
}
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->crash_report_info_fetcher =
base::BindRepeating(&GetFakeCrashReportInfo, expected_crash_report_infos);
RestartStatusCollector(std::move(options));
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceCrashReportInfo, true);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kStatsReportingPref, true);
GetStatus();
EXPECT_EQ(report_cnt, device_status_.crash_report_infos_size());
// Walk the returned CrashReportInfo to make sure it matches.
for (const em::CrashReportInfo& expected_info : expected_crash_report_infos) {
bool found = false;
for (const em::CrashReportInfo& info :
device_status_.crash_report_infos()) {
if (info.remote_id() == expected_info.remote_id()) {
EXPECT_EQ(expected_info.capture_timestamp(), info.capture_timestamp());
EXPECT_EQ(expected_info.remote_id(), info.remote_id());
EXPECT_EQ(expected_info.cause(), info.cause());
EXPECT_EQ(expected_info.upload_status(), info.upload_status());
found = true;
break;
}
}
EXPECT_TRUE(found) << "No matching CrashReportInfo for "
<< expected_info.remote_id();
}
// Get the status again to make sure that the data keeps consistent.
GetStatus();
EXPECT_EQ(report_cnt, device_status_.crash_report_infos_size());
}
TEST_F(DeviceStatusCollectorTest,
TestCrashReportInfo_TurnOffReportDeviceCrashReportInfo) {
DisableDefaultSettings();
// Create sample crash reports.
std::vector<em::CrashReportInfo> expected_crash_report_infos;
const base::Time now = base::Time::Now();
const int report_cnt = 5;
for (int i = 0; i < report_cnt; ++i) {
base::Time timestamp = now - base::Hours(30) * i;
em::CrashReportInfo info;
info.set_capture_timestamp(timestamp.ToJavaTime());
info.set_remote_id(base::StringPrintf("remote_id %d", i));
info.set_cause(base::StringPrintf("cause %d", i));
info.set_upload_status(em::CrashReportInfo::UPLOAD_STATUS_UPLOADED);
expected_crash_report_infos.push_back(info);
}
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->crash_report_info_fetcher =
base::BindRepeating(&GetFakeCrashReportInfo, expected_crash_report_infos);
RestartStatusCollector(std::move(options));
// Turn off kReportDeviceCrashReportInfo, but turn on kStatsReportingPref.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceCrashReportInfo, false);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kStatsReportingPref, true);
GetStatus();
EXPECT_EQ(0, device_status_.crash_report_infos_size());
}
TEST_F(DeviceStatusCollectorTest,
TestCrashReportInfo_TurnOffStatsReportingPref) {
DisableDefaultSettings();
// Create sample crash reports.
std::vector<em::CrashReportInfo> expected_crash_report_infos;
const base::Time now = base::Time::Now();
const int report_cnt = 5;
for (int i = 0; i < report_cnt; ++i) {
base::Time timestamp = now - base::Hours(30) * i;
em::CrashReportInfo info;
info.set_capture_timestamp(timestamp.ToJavaTime());
info.set_remote_id(base::StringPrintf("remote_id %d", i));
info.set_cause(base::StringPrintf("cause %d", i));
info.set_upload_status(em::CrashReportInfo::UPLOAD_STATUS_UPLOADED);
expected_crash_report_infos.push_back(info);
}
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->crash_report_info_fetcher =
base::BindRepeating(&GetFakeCrashReportInfo, expected_crash_report_infos);
RestartStatusCollector(std::move(options));
// Turn on kReportDeviceCrashReportInfo, but turn off kStatsReportingPref.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceCrashReportInfo, true);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kStatsReportingPref, false);
GetStatus();
EXPECT_EQ(0, device_status_.crash_report_infos_size());
}
TEST_F(DeviceStatusCollectorTest, TestCrashReportInfo_DeviceRestartOnly) {
DisableDefaultSettings();
// Create a test uploads.log file with three kinds of source. The first two
// lead to device restart, the third doesn't.
std::vector<std::string> causes = {kTestCauseKernel, kTestCauseEC,
kTestCauseOther};
base::Time timestamp = base::Time::Now() - base::Hours(1);
std::stringstream stream;
for (int i = 0; i <= 2; ++i) {
stream << "{";
stream << "\"upload_time\":\"" << timestamp.ToTimeT() << "\",";
stream << "\"upload_id\":\"" << kTestUploadId << "\",";
stream << "\"local_id\":\"" << kTestLocalID << "\",";
stream << "\"capture_time\":\"" << timestamp.ToTimeT() << "\",";
stream << "\"state\":"
<< static_cast<int>(UploadList::UploadInfo::State::Uploaded) << ",";
stream << "\"source\":\"" << causes[i] << "\"";
stream << "}" << std::endl;
}
WriteUploadLog(stream.str());
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->crash_report_info_fetcher =
DeviceStatusCollector::CrashReportInfoFetcher();
RestartStatusCollector(std::move(options));
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceCrashReportInfo, true);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kStatsReportingPref, true);
GetStatus();
EXPECT_EQ(2, device_status_.crash_report_infos_size());
// Walk the returned CrashReportInfo to make sure it matches.
const em::CrashReportInfo& info0 = device_status_.crash_report_infos(0);
EXPECT_EQ(timestamp.ToTimeT() * 1000, info0.capture_timestamp());
EXPECT_EQ(kTestUploadId, info0.remote_id());
EXPECT_EQ(kTestCauseEC, info0.cause());
EXPECT_EQ(em::CrashReportInfo::UPLOAD_STATUS_UPLOADED, info0.upload_status());
const em::CrashReportInfo& info1 = device_status_.crash_report_infos(1);
EXPECT_EQ(timestamp.ToTimeT() * 1000, info1.capture_timestamp());
EXPECT_EQ(kTestUploadId, info1.remote_id());
EXPECT_EQ(kTestCauseKernel, info1.cause());
EXPECT_EQ(em::CrashReportInfo::UPLOAD_STATUS_UPLOADED, info1.upload_status());
}
TEST_F(DeviceStatusCollectorTest, TestCrashReportInfo_LastDayUploadedOnly) {
DisableDefaultSettings();
// Create a test uploads.log file. One |upload_time| is within last 24 hours,
// the other is not.
base::Time now = base::Time::Now();
base::Time timestamps[] = {now - base::Hours(22), now - base::Hours(24)};
std::stringstream stream;
for (int i = 0; i <= 1; ++i) {
stream << "{";
stream << "\"upload_time\":\"" << timestamps[i].ToTimeT() << "\",";
stream << "\"upload_id\":\"" << kTestUploadId << "\",";
stream << "\"local_id\":\"" << kTestLocalID << "\",";
stream << "\"capture_time\":\"" << timestamps[i].ToTimeT() << "\",";
stream << "\"state\":"
<< static_cast<int>(UploadList::UploadInfo::State::Uploaded) << ",";
stream << "\"source\":\"" << kTestCauseKernel << "\"";
stream << "}" << std::endl;
}
WriteUploadLog(stream.str());
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->crash_report_info_fetcher =
DeviceStatusCollector::CrashReportInfoFetcher();
RestartStatusCollector(std::move(options));
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceCrashReportInfo, true);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kStatsReportingPref, true);
GetStatus();
EXPECT_EQ(1, device_status_.crash_report_infos_size());
// Walk the returned CrashReportInfo to make sure it matches.
const em::CrashReportInfo& info = device_status_.crash_report_infos(0);
EXPECT_EQ(timestamps[0].ToTimeT() * 1000, info.capture_timestamp());
EXPECT_EQ(kTestUploadId, info.remote_id());
EXPECT_EQ(kTestCauseKernel, info.cause());
EXPECT_EQ(em::CrashReportInfo::UPLOAD_STATUS_UPLOADED, info.upload_status());
}
TEST_F(DeviceStatusCollectorTest, TestCrashReportInfo_CrashReportEntryMaxSize) {
DisableDefaultSettings();
// Create a test uploads.log file with 200 entries. Only the last 100 is
// included.
base::Time timestamp = base::Time::Now() - base::Hours(1);
const int report_cnt = 200;
std::stringstream stream;
for (int i = 1; i <= report_cnt; ++i) {
stream << "{";
stream << "\"upload_time\":\"" << timestamp.ToTimeT() << "\",";
stream << "\"upload_id\":\"" << i << "\",";
stream << "\"local_id\":\"" << kTestLocalID << "\",";
stream << "\"capture_time\":\"" << timestamp.ToTimeT() << "\",";
stream << "\"state\":"
<< static_cast<int>(UploadList::UploadInfo::State::Uploaded) << ",";
stream << "\"source\":\"" << kTestCauseKernel << "\"";
stream << "}" << std::endl;
}
WriteUploadLog(stream.str());
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->crash_report_info_fetcher =
DeviceStatusCollector::CrashReportInfoFetcher();
RestartStatusCollector(std::move(options));
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceCrashReportInfo, true);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kStatsReportingPref, true);
GetStatus();
EXPECT_EQ(100, device_status_.crash_report_infos_size());
// Walk the returned CrashReportInfo to make sure it matches.
for (int i = 0; i < 100; i++) {
const em::CrashReportInfo& info = device_status_.crash_report_infos(i);
EXPECT_EQ(timestamp.ToTimeT() * 1000, info.capture_timestamp());
EXPECT_EQ(base::NumberToString(report_cnt - i), info.remote_id());
EXPECT_EQ(kTestCauseKernel, info.cause());
EXPECT_EQ(em::CrashReportInfo::UPLOAD_STATUS_UPLOADED,
info.upload_status());
}
}
TEST_F(DeviceStatusCollectorTest, TestCrashReportInfo_LegacyCSV) {
DisableDefaultSettings();
// Create a test uploads.log file in the legacy CSV format. All such kind of
// record will be ignored because the required source filed is not existing.
base::Time timestamp = base::Time::Now() - base::Hours(1);
std::string test_entry =
base::StringPrintf("%" PRId64, static_cast<int64_t>(timestamp.ToTimeT()));
test_entry += ",";
test_entry.append(kTestUploadId);
test_entry += ",";
test_entry.append(kTestLocalID);
WriteUploadLog(test_entry);
auto options = CreateEmptyDeviceStatusCollectorOptions();
options->crash_report_info_fetcher =
DeviceStatusCollector::CrashReportInfoFetcher();
RestartStatusCollector(std::move(options));
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceCrashReportInfo, true);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kStatsReportingPref, true);
GetStatus();
EXPECT_EQ(0, device_status_.crash_report_infos_size());
}
TEST_F(DeviceStatusCollectorTest, TestHealthdBacklightInfo) {
DisableDefaultSettings();
SetFakeCrosHealthdData();
GetStatus();
EXPECT_EQ(device_status_.backlight_info_size(), 0);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceBacklightInfo, true);
SetFakeCrosHealthdData();
GetStatus();
// Verify the backlight info.
ASSERT_EQ(device_status_.backlight_info_size(), 1);
const auto& backlight = device_status_.backlight_info(0);
EXPECT_EQ(backlight.path(), kFakeBacklightPath);
EXPECT_EQ(backlight.max_brightness(), kFakeMaxBrightness);
EXPECT_EQ(backlight.brightness(), kFakeBrightness);
}
TEST_F(DeviceStatusCollectorTest, TestHealthdPowerStatus) {
DisableDefaultSettings();
SetFakeCrosHealthdData();
GetStatus();
EXPECT_FALSE(device_status_.has_power_status());
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDevicePowerStatus, true);
SetFakeCrosHealthdData();
GetStatus();
// Verify the battery data.
ASSERT_TRUE(device_status_.has_power_status());
ASSERT_EQ(device_status_.power_status().batteries_size(), 1);
const auto& battery = device_status_.power_status().batteries(0);
EXPECT_EQ(battery.serial(), kFakeBatterySerial);
EXPECT_EQ(battery.manufacturer(), kFakeBatteryVendor);
EXPECT_EQ(battery.design_capacity(), kExpectedBatteryChargeFullDesign);
EXPECT_EQ(battery.full_charge_capacity(), kExpectedBatteryChargeFull);
EXPECT_EQ(battery.cycle_count(), kFakeBatteryCycleCount);
EXPECT_EQ(battery.design_min_voltage(), kExpectedBatteryVoltageMinDesign);
EXPECT_EQ(battery.manufacture_date(), kFakeSmartBatteryManufactureDate);
EXPECT_EQ(battery.technology(), kFakeBatteryTechnology);
// Verify the battery sample data.
ASSERT_EQ(battery.samples_size(), 1);
const auto& battery_sample = battery.samples(0);
EXPECT_EQ(battery_sample.voltage(), kExpectedBatteryVoltageNow);
EXPECT_EQ(battery_sample.remaining_capacity(), kExpectedBatteryChargeNow);
EXPECT_EQ(battery_sample.temperature(),
(kFakeSmartBatteryTemperature - kZeroCInDeciKelvin) / 10);
EXPECT_EQ(battery_sample.current(), kExpectedBatteryCurrentNow);
EXPECT_EQ(battery_sample.status(), kFakeBatteryStatus);
}
TEST_F(DeviceStatusCollectorTest, TestHealthdMemoryInfo) {
DisableDefaultSettings();
SetFakeCrosHealthdData();
GetStatus();
EXPECT_FALSE(device_status_.has_memory_info());
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceMemoryInfo, true);
SetFakeCrosHealthdData();
GetStatus();
// Verify the memory info.
ASSERT_TRUE(device_status_.has_memory_info());
EXPECT_EQ(device_status_.memory_info().total_memory_kib(), kFakeTotalMemory);
EXPECT_EQ(device_status_.memory_info().free_memory_kib(), kFakeFreeMemory);
EXPECT_EQ(device_status_.memory_info().available_memory_kib(),
kFakeAvailableMemory);
EXPECT_EQ(device_status_.memory_info().page_faults_since_last_boot(),
kFakePageFaults);
}
TEST_F(DeviceStatusCollectorTest, TestHealthdCpuInfo) {
DisableDefaultSettings();
SetFakeCrosHealthdData();
GetStatus();
EXPECT_FALSE(device_status_.has_global_cpu_info());
EXPECT_EQ(device_status_.cpu_info_size(), 0);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceCpuInfo, true);
SetFakeCrosHealthdData();
GetStatus();
// Verify the CPU data.
ASSERT_TRUE(device_status_.has_global_cpu_info());
EXPECT_EQ(device_status_.global_cpu_info().num_total_threads(),
kFakeNumTotalThreads);
// Verify the physical CPU.
ASSERT_EQ(device_status_.cpu_info_size(), 1);
const auto& cpu = device_status_.cpu_info(0);
EXPECT_EQ(cpu.model_name(), kFakeModelName);
EXPECT_EQ(cpu.architecture(), kFakeProtoArchitecture);
EXPECT_EQ(cpu.max_clock_speed_khz(), kFakeMaxClockSpeed);
// Verify the logical CPU.
ASSERT_EQ(cpu.logical_cpus_size(), 1);
const auto& logical_cpu = cpu.logical_cpus(0);
EXPECT_EQ(logical_cpu.scaling_max_frequency_khz(), kFakeScalingMaxFrequency);
EXPECT_EQ(logical_cpu.scaling_current_frequency_khz(),
kFakeScalingCurFrequency);
EXPECT_EQ(logical_cpu.idle_time_seconds(), kFakeIdleTime);
// Verify the C-state data.
ASSERT_EQ(logical_cpu.c_states_size(), 1);
const auto& c_state = logical_cpu.c_states(0);
EXPECT_EQ(c_state.name(), kFakeCStateName);
EXPECT_EQ(c_state.time_in_state_since_last_boot_us(),
kFakeTimeInStateSinceLastBoot);
}
TEST_F(DeviceStatusCollectorTest, TestHealthdStorageStatus) {
DisableDefaultSettings();
SetFakeCrosHealthdData();
GetStatus();
EXPECT_FALSE(device_status_.has_storage_status());
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceStorageStatus, true);
SetFakeCrosHealthdData();
GetStatus();
// Verify the storage data.
ASSERT_TRUE(device_status_.has_storage_status());
ASSERT_EQ(device_status_.storage_status().disks_size(), 1);
const auto& disk = device_status_.storage_status().disks(0);
EXPECT_EQ(disk.size(), kFakeStorageSize);
EXPECT_EQ(disk.type(), kFakeStorageType);
EXPECT_EQ(disk.manufacturer(), base::NumberToString(kFakeStorageManfid));
EXPECT_EQ(disk.model(), kFakeStorageName);
EXPECT_EQ(disk.serial(), base::NumberToString(kFakeStorageSerial));
EXPECT_EQ(disk.bytes_read_since_last_boot(), kFakeStorageBytesRead);
EXPECT_EQ(disk.bytes_written_since_last_boot(), kFakeStorageBytesWritten);
EXPECT_EQ(disk.read_time_seconds_since_last_boot(),
kFakeStorageReadTimeSeconds);
EXPECT_EQ(disk.write_time_seconds_since_last_boot(),
kFakeStorageWriteTimeSeconds);
EXPECT_EQ(disk.io_time_seconds_since_last_boot(), kFakeStorageIoTimeSeconds);
EXPECT_EQ(disk.discard_time_seconds_since_last_boot(),
kFakeStorageDiscardTimeSeconds);
ASSERT_TRUE(disk.has_emmc_oemid());
EXPECT_EQ(disk.emmc_oemid(), kFakeOemid);
ASSERT_TRUE(disk.has_emmc_pnm());
EXPECT_EQ(disk.emmc_pnm(), kFakePnm);
ASSERT_TRUE(disk.has_emmc_hardware_rev());
EXPECT_EQ(disk.emmc_hardware_rev(), kFakePrv);
ASSERT_TRUE(disk.has_emmc_firmware_rev());
EXPECT_EQ(disk.emmc_firmware_rev(), kFakeFwrev);
EXPECT_EQ(disk.purpose(), kFakeProtoPurpose);
}
TEST_F(DeviceStatusCollectorTest, TestHealthdTimeZoneInfo) {
DisableDefaultSettings();
SetFakeCrosHealthdData();
GetStatus();
EXPECT_FALSE(device_status_.has_timezone_info());
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceTimezoneInfo, true);
SetFakeCrosHealthdData();
GetStatus();
// Verify the Timezone info.
ASSERT_TRUE(device_status_.has_timezone_info());
EXPECT_EQ(device_status_.timezone_info().posix(), kPosixTimezone);
EXPECT_EQ(device_status_.timezone_info().region(), kTimezoneRegion);
}
TEST_F(DeviceStatusCollectorTest, TestHealthdFanInfo) {
DisableDefaultSettings();
SetFakeCrosHealthdData();
GetStatus();
EXPECT_EQ(device_status_.fan_info_size(), 0);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceFanInfo, true);
SetFakeCrosHealthdData();
GetStatus();
// Verify the fan info.
ASSERT_EQ(device_status_.fan_info_size(), 1);
const auto& fan = device_status_.fan_info(0);
EXPECT_EQ(fan.speed_rpm(), kFakeSpeedRpm);
}
TEST_F(DeviceStatusCollectorTest, TestHealthdBluetoothInfo) {
DisableDefaultSettings();
SetFakeCrosHealthdData();
GetStatus();
EXPECT_EQ(device_status_.bluetooth_adapter_info_size(), 0);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceBluetoothInfo, true);
SetFakeCrosHealthdData();
GetStatus();
// Verify the Bluetooth info.
ASSERT_EQ(device_status_.bluetooth_adapter_info_size(), 1);
const auto& adapter = device_status_.bluetooth_adapter_info(0);
EXPECT_EQ(adapter.name(), kFakeBluetoothAdapterName);
EXPECT_EQ(adapter.address(), kFakeBluetoothAdapterAddress);
EXPECT_EQ(adapter.powered(), kFakeBluetoothAdapterIsPowered);
EXPECT_EQ(adapter.num_connected_devices(), kFakeNumConnectedBluetoothDevices);
}
TEST_F(DeviceStatusCollectorTest, TestHealthdVersionInfo) {
DisableDefaultSettings();
SetFakeCrosHealthdData();
GetStatus();
EXPECT_FALSE(device_status_.has_tpm_version_info());
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceVersionInfo, true);
SetFakeCrosHealthdData();
GetStatus();
// Verify the Tpm info.
ASSERT_TRUE(device_status_.has_tpm_version_info());
const auto& tpm = device_status_.tpm_version_info();
EXPECT_EQ(tpm.did_vid(), kFakeTpmDidVid);
}
TEST_F(DeviceStatusCollectorTest, TestCrosHealthdInfoOptional) {
DisableDefaultSettings();
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceCpuInfo, true);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDevicePowerStatus, true);
auto telemetry_info = cros_healthd::TelemetryInfo::New();
telemetry_info->battery_result = CreateEmptyBatteryResult();
telemetry_info->backlight_result = CreateEmptyBacklightResult();
telemetry_info->fan_result = CreateEmptyFanResult();
chromeos::cros_healthd::FakeCrosHealthdClient::Get()
->SetProbeTelemetryInfoResponseForTesting(telemetry_info);
GetStatus();
// Verify the battery data is empty
EXPECT_FALSE(device_status_.has_power_status());
// Verify the backlight info is empty.
EXPECT_EQ(device_status_.backlight_info_size(), 0);
// Verify the fan info is empty.
EXPECT_EQ(device_status_.fan_info_size(), 0);
}
TEST_F(DeviceStatusCollectorTest, TestUnsetTpmInfo) {
DisableDefaultSettings();
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceVersionInfo, true);
auto telemetry_info = cros_healthd::TelemetryInfo::New();
telemetry_info->tpm_result = CreatePartialTpmResult();
GetStatus();
// Verify the Tpm info is unset without crashing.
ASSERT_TRUE(device_status_.has_tpm_version_info());
const auto& tpm = device_status_.tpm_version_info();
EXPECT_EQ(tpm.did_vid(), "");
}
TEST_F(DeviceStatusCollectorTest, TestPartialCrosHealthdInfo) {
DisableDefaultSettings();
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceCpuInfo, true);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDevicePowerStatus, true);
SetFakeCrosHealthdData();
GetStatus();
// Verify the CPU data.
ASSERT_EQ(device_status_.cpu_info_size(), 1);
const auto& cpu = device_status_.cpu_info(0);
EXPECT_EQ(cpu.model_name(), kFakeModelName);
EXPECT_EQ(cpu.architecture(), kFakeProtoArchitecture);
EXPECT_EQ(cpu.max_clock_speed_khz(), kFakeMaxClockSpeed);
// Verify the battery data.
ASSERT_TRUE(device_status_.has_power_status());
ASSERT_EQ(device_status_.power_status().batteries_size(), 1);
const auto& battery = device_status_.power_status().batteries(0);
EXPECT_EQ(battery.serial(), kFakeBatterySerial);
EXPECT_EQ(battery.manufacturer(), kFakeBatteryVendor);
EXPECT_EQ(battery.design_capacity(), kExpectedBatteryChargeFullDesign);
EXPECT_EQ(battery.full_charge_capacity(), kExpectedBatteryChargeFull);
EXPECT_EQ(battery.cycle_count(), kFakeBatteryCycleCount);
EXPECT_EQ(battery.design_min_voltage(), kExpectedBatteryVoltageMinDesign);
EXPECT_EQ(battery.manufacture_date(), kFakeSmartBatteryManufactureDate);
EXPECT_EQ(battery.technology(), kFakeBatteryTechnology);
// Verify the battery sample data.
ASSERT_EQ(battery.samples_size(), 1);
const auto& battery_sample = battery.samples(0);
EXPECT_EQ(battery_sample.voltage(), kExpectedBatteryVoltageNow);
EXPECT_EQ(battery_sample.remaining_capacity(), kExpectedBatteryChargeNow);
EXPECT_EQ(battery_sample.temperature(),
(kFakeSmartBatteryTemperature - kZeroCInDeciKelvin) / 10);
EXPECT_EQ(battery_sample.current(), kExpectedBatteryCurrentNow);
EXPECT_EQ(battery_sample.status(), kFakeBatteryStatus);
EXPECT_FALSE(device_status_.has_memory_info());
EXPECT_FALSE(device_status_.has_timezone_info());
EXPECT_FALSE(device_status_.has_system_status());
// Some smbios info from SystemResult V2 is always reported by default.
EXPECT_TRUE(device_status_.has_smbios_info());
EXPECT_FALSE(device_status_.has_boot_info());
EXPECT_FALSE(device_status_.has_storage_status());
EXPECT_EQ(device_status_.backlight_info_size(), 0);
EXPECT_EQ(device_status_.fan_info_size(), 0);
}
// Test ReportDeviceSystemInfo and ReportDeviceVpdInfo together because they
// are highly coupled.
TEST_F(DeviceStatusCollectorTest, TestCrosHealthdVpdAndSystemInfo) {
// When the vpd reporting policy is turned on and the system reporting
// property is turned off, we only expect the protobuf to only have vpd info.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceSystemInfo, false);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceVpdInfo, true);
SetFakeCrosHealthdData();
GetStatus();
// Verify the only vpd info is populated.
ASSERT_TRUE(device_status_.has_system_status());
EXPECT_EQ(device_status_.system_status().first_power_date(),
kFakeFirstPowerDate);
EXPECT_EQ(device_status_.system_status().manufacture_date(),
kFakeManufactureDate);
EXPECT_EQ(device_status_.system_status().vpd_sku_number(), kFakeSkuNumber);
EXPECT_EQ(device_status_.system_status().vpd_serial_number(),
kFakeSerialNumber);
ASSERT_FALSE(device_status_.system_status().has_marketing_name());
ASSERT_FALSE(device_status_.system_status().has_bios_version());
ASSERT_FALSE(device_status_.system_status().has_board_name());
ASSERT_FALSE(device_status_.system_status().has_board_version());
ASSERT_FALSE(device_status_.system_status().has_chassis_type());
ASSERT_FALSE(device_status_.system_status().has_product_name());
// Verify the system info v2 is not populated excluding vendor, product name,
// and product version.
ASSERT_TRUE(device_status_.has_smbios_info());
EXPECT_TRUE(device_status_.smbios_info().has_sys_vendor());
EXPECT_TRUE(device_status_.smbios_info().has_product_name());
EXPECT_TRUE(device_status_.smbios_info().has_product_version());
EXPECT_FALSE(device_status_.smbios_info().has_bios_version());
EXPECT_FALSE(device_status_.has_boot_info());
// When the system reporting policy is turned on and the vpd reporting policy
// is turned off, we expect the protobuf to have all system info except the
// subset of vpd info.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceSystemInfo, true);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceVpdInfo, false);
SetFakeCrosHealthdData();
GetStatus();
// Verify all system info except vpd info exists.
ASSERT_TRUE(device_status_.has_system_status());
ASSERT_FALSE(device_status_.system_status().has_first_power_date());
ASSERT_FALSE(device_status_.system_status().has_manufacture_date());
ASSERT_FALSE(device_status_.system_status().has_vpd_sku_number());
EXPECT_EQ(device_status_.system_status().marketing_name(),
kFakeMarketingName);
EXPECT_EQ(device_status_.system_status().bios_version(), kFakeBiosVersion);
EXPECT_EQ(device_status_.system_status().board_name(), kFakeBoardName);
EXPECT_EQ(device_status_.system_status().board_version(), kFakeBoardVersion);
EXPECT_EQ(device_status_.system_status().chassis_type(), kFakeChassisType);
EXPECT_EQ(device_status_.system_status().product_name(), kFakeProductName);
// Verify system info V2 exists too.
ASSERT_TRUE(device_status_.has_smbios_info());
EXPECT_EQ(device_status_.smbios_info().product_name(),
kFakeDmiInfoProductName);
EXPECT_EQ(device_status_.smbios_info().product_version(),
kFakeDmiInfoProductVersion);
EXPECT_EQ(device_status_.smbios_info().sys_vendor(), kFakeDmiInfoSysVendor);
EXPECT_EQ(device_status_.smbios_info().bios_version(),
kFakeDmiInfoBiosVersion);
ASSERT_TRUE(device_status_.has_boot_info());
EXPECT_EQ(device_status_.boot_info().boot_method(), kFakeOsInfoBootMethod);
// Even with both settings off vendor, product name, and product version
// should be reported.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceSystemInfo, false);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceVpdInfo, false);
SetFakeCrosHealthdData();
GetStatus();
ASSERT_TRUE(device_status_.has_smbios_info());
EXPECT_TRUE(device_status_.smbios_info().has_sys_vendor());
EXPECT_TRUE(device_status_.smbios_info().has_product_name());
EXPECT_TRUE(device_status_.smbios_info().has_product_version());
}
TEST_F(DeviceStatusCollectorTest, GenerateAppInfo) {
DisableDefaultSettings();
const AccountId account_id(AccountId::FromUserEmail("user0@managed.com"));
MockRegularUserWithAffiliation(account_id, true);
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceAppInfo, true);
managed_session_service_->OnUserProfileLoaded(account_id);
auto* app_proxy =
apps::AppServiceProxyFactory::GetForProfile(testing_profile_.get());
auto app1 = std::make_unique<apps::App>(apps::AppType::kChromeApp, "id");
auto app2 = std::make_unique<apps::App>(apps::AppType::kChromeApp, "id2");
if (base::FeatureList::IsEnabled(apps::kAppServiceOnAppUpdateWithoutMojom)) {
std::vector<apps::AppPtr> apps;
apps.push_back(std::move(app1));
apps.push_back(std::move(app2));
app_proxy->AppRegistryCache().OnApps(std::move(apps),
apps::AppType::kUnknown,
/*should_notify_initialized=*/false);
} else {
std::vector<apps::mojom::AppPtr> mojom_deltas;
mojom_deltas.push_back(apps::ConvertAppToMojomApp(app1));
mojom_deltas.push_back(apps::ConvertAppToMojomApp(app2));
app_proxy->AppRegistryCache().OnApps(std::move(mojom_deltas),
apps::mojom::AppType::kUnknown,
/*should_notify_initialized=*/false);
}
// Start app instance
base::Time start_time;
EXPECT_TRUE(base::Time::FromString("29-MAR-2020 1:30pm", &start_time));
test_clock_.SetNow(start_time);
// Env::CreateInstance must be called for test window.
auto env = aura::Env::CreateInstance();
std::unique_ptr<aura::Window> window(
aura::test::CreateTestWindowWithId(/*id=*/0, nullptr));
apps::InstanceParams params("id", window.get());
params.state = std::make_pair(apps::InstanceState::kStarted, start_time);
app_proxy->InstanceRegistry().CreateOrUpdateInstance(std::move(params));
base::Time report_time;
EXPECT_TRUE(base::Time::FromString("30-MAR-2020 2:30pm", &report_time));
test_clock_.SetNow(report_time);
GetStatus();
base::Time reported_start_time;
base::Time reported_end_time;
EXPECT_EQ(session_status_.app_infos(0).app_id(), "id");
EXPECT_EQ(session_status_.app_infos(0).active_time_periods_size(), 2);
auto first_activity = session_status_.app_infos(0).active_time_periods()[0];
EXPECT_TRUE(
base::Time::FromUTCString("29-MAR-2020 12:00am", &reported_start_time));
EXPECT_TRUE(
base::Time::FromUTCString("29-MAR-2020 10:30am", &reported_end_time));
EXPECT_EQ(first_activity.start_timestamp(), reported_start_time.ToJavaTime());
EXPECT_EQ(first_activity.end_timestamp(), reported_end_time.ToJavaTime());
auto second_activity = session_status_.app_infos(0).active_time_periods()[1];
EXPECT_TRUE(
base::Time::FromUTCString("30-MAR-2020 12:00am", &reported_start_time));
EXPECT_TRUE(
base::Time::FromUTCString("30-MAR-2020 2:30pm", &reported_end_time));
EXPECT_EQ(second_activity.start_timestamp(),
reported_start_time.ToJavaTime());
EXPECT_EQ(second_activity.end_timestamp(), reported_end_time.ToJavaTime());
EXPECT_EQ(session_status_.app_infos(1).app_id(), "id2");
EXPECT_EQ(session_status_.app_infos(1).active_time_periods_size(), 0);
}
struct FakeSimSlotInfo {
std::string object_path;
std::string eid;
bool is_active;
uint32_t physical_slot;
} kFakeSimSlots[] = {{"euicc_path", "123", true, 1},
{"euicc_path2", "234", false, 2}};
// Fake device state.
struct FakeDeviceData {
const char* device_path;
const char* type;
const char* object_path;
const char* mac_address;
const char* meid;
const char* imei;
const char* mdn;
const char* iccid;
int expected_type; // proto enum type value, -1 for not present.
};
static const FakeDeviceData kFakeDevices[] = {
{"/device/ethernet", shill::kTypeEthernet, "ethernet", "112233445566", "",
"", "", "", em::NetworkInterface::TYPE_ETHERNET},
{"/device/cellular1", shill::kTypeCellular, "cellular1", "abcdefabcdef",
"A10000009296F2", "", "test_mdn", "test_iccid",
em::NetworkInterface::TYPE_CELLULAR},
{"/device/cellular2", shill::kTypeCellular, "cellular2", "abcdefabcdef",
"test_mdn", "test_iccid", "352099001761481", "",
em::NetworkInterface::TYPE_CELLULAR},
{"/device/wifi", shill::kTypeWifi, "wifi", "aabbccddeeff", "", "", "", "",
em::NetworkInterface::TYPE_WIFI},
{"/device/vpn", shill::kTypeVPN, "vpn", "", "", "", "", "", -1},
};
// Fake network state.
struct FakeNetworkState {
const char* name;
const char* device_path;
const char* type;
int signal_strength;
int expected_signal_strength;
const char* connection_status;
int expected_state;
const char* address;
const char* gateway;
bool visible;
};
// List of fake networks - primarily used to make sure that signal strength
// and connection state are properly populated in status reports. Note that
// by convention shill will not report a signal strength of 0 for a visible
// network, so we use 1 below.
static const FakeNetworkState kFakeNetworks[] = {
{"offline", "/device/wifi", shill::kTypeWifi, 35, -85, shill::kStateOffline,
em::NetworkState::OFFLINE, "", "", true},
{"ethernet", "/device/ethernet", shill::kTypeEthernet, 0, 0,
shill::kStateOnline, em::NetworkState::ONLINE, "192.168.0.1", "8.8.8.8",
true},
{"wifi", "/device/wifi", shill::kTypeWifi, 23, -97,
shill::kStateNoConnectivity, em::NetworkState::PORTAL, "", "", true},
{"idle", "/device/cellular1", shill::kTypeCellular, 0, 0, shill::kStateIdle,
em::NetworkState::IDLE, "", "", true},
{"not_visible", "/device/wifi", shill::kTypeWifi, 0, 0, shill::kStateIdle,
em::NetworkState::IDLE, "", "", false},
{"association", "/device/cellular1", shill::kTypeCellular, 0, 0,
shill::kStateAssociation, em::NetworkState::ASSOCIATION, "", "", true},
{"config", "/device/cellular1", shill::kTypeCellular, 0, 0,
shill::kStateConfiguration, em::NetworkState::CONFIGURATION, "", "", true},
// Set signal strength for this network to -20, but expected strength to 0
// to test that we only report signal_strength for wifi connections.
{"ready", "/device/cellular1", shill::kTypeCellular, -20, 0,
shill::kStateReady, em::NetworkState::READY, "", "", true},
{"failure", "/device/wifi", shill::kTypeWifi, 1, -119, shill::kStateFailure,
em::NetworkState::FAILURE, "", "", true},
{"activation-failure", "/device/cellular1", shill::kTypeCellular, 0, 0,
shill::kStateActivationFailure, em::NetworkState::ACTIVATION_FAILURE, "",
"", true},
{"unknown", "", shill::kTypeWifi, 1, -119, shill::kStateIdle,
em::NetworkState::IDLE, "", "", true},
};
static const FakeNetworkState kUnconfiguredNetwork = {"unconfigured",
"/device/unconfigured",
shill::kTypeWifi,
35,
-85,
shill::kStateOffline,
em::NetworkState::OFFLINE,
"",
""};
class DeviceStatusCollectorNetworkTest : public DeviceStatusCollectorTest {
protected:
void SetUp() override {
RestartStatusCollector();
chromeos::ShillDeviceClient::TestInterface* device_client =
network_handler_test_helper_.device_test();
chromeos::ShillServiceClient::TestInterface* service_client =
network_handler_test_helper_.service_test();
chromeos::ShillIPConfigClient::TestInterface* ip_config_client =
network_handler_test_helper_.ip_config_test();
device_client->ClearDevices();
service_client->ClearServices();
for (const FakeDeviceData& dev : kFakeDevices) {
device_client->AddDevice(dev.device_path, dev.type, dev.object_path);
if (*dev.mac_address) {
device_client->SetDeviceProperty(
dev.device_path, shill::kAddressProperty,
base::Value(dev.mac_address), /*notify_changed=*/true);
}
if (*dev.meid) {
device_client->SetDeviceProperty(dev.device_path, shill::kMeidProperty,
base::Value(dev.meid),
/*notify_changed=*/true);
}
if (*dev.imei) {
device_client->SetDeviceProperty(dev.device_path, shill::kImeiProperty,
base::Value(dev.imei),
/*notify_changed=*/true);
}
if (*dev.mdn) {
device_client->SetDeviceProperty(dev.device_path, shill::kMdnProperty,
base::Value(dev.mdn),
/*notify_changed=*/true);
}
if (*dev.iccid) {
device_client->SetDeviceProperty(dev.device_path, shill::kIccidProperty,
base::Value(dev.iccid),
/*notify_changed=*/true);
}
}
for (const auto& slotInfo : kFakeSimSlots) {
chromeos::HermesManagerClient::Get()->GetTestInterface()->AddEuicc(
dbus::ObjectPath(slotInfo.object_path), slotInfo.eid,
slotInfo.is_active, slotInfo.physical_slot);
}
network_handler_test_helper_.profile_test()->AddProfile(
kShillFakeProfilePath, kShillFakeUserhash);
// Now add services for every fake network.
for (const FakeNetworkState& fake_network : kFakeNetworks) {
// Shill forces non-visible networks to report a disconnected state.
bool is_visible = fake_network.connection_status != shill::kStateIdle;
service_client->AddService(fake_network.name /* service_path */,
fake_network.name /* guid */,
fake_network.name, fake_network.type,
fake_network.connection_status, is_visible);
service_client->SetServiceProperty(
fake_network.name, shill::kSignalStrengthProperty,
base::Value(fake_network.signal_strength));
service_client->SetServiceProperty(fake_network.name,
shill::kDeviceProperty,
base::Value(fake_network.device_path));
// Set the profile so this shows up as a configured network.
service_client->SetServiceProperty(fake_network.name,
shill::kProfileProperty,
base::Value(kShillFakeProfilePath));
if (strlen(fake_network.address) > 0) {
// Set the IP config.
base::DictionaryValue ip_config_properties;
ip_config_properties.SetKey(shill::kAddressProperty,
base::Value(fake_network.address));
ip_config_properties.SetKey(shill::kGatewayProperty,
base::Value(fake_network.gateway));
const std::string kIPConfigPath = "test_ip_config";
ip_config_client->AddIPConfig(kIPConfigPath, ip_config_properties);
service_client->SetServiceProperty(fake_network.name,
shill::kIPConfigProperty,
base::Value(kIPConfigPath));
}
}
// Now add an unconfigured network - it should not show up in the
// reported list of networks because it doesn't have a profile specified.
service_client->AddService(kUnconfiguredNetwork.name, /* service_path */
kUnconfiguredNetwork.name /* guid */,
kUnconfiguredNetwork.name /* name */,
kUnconfiguredNetwork.type /* type */,
kUnconfiguredNetwork.connection_status,
true /* visible */);
service_client->SetServiceProperty(
kUnconfiguredNetwork.name, shill::kSignalStrengthProperty,
base::Value(kUnconfiguredNetwork.signal_strength));
service_client->SetServiceProperty(
kUnconfiguredNetwork.name, shill::kDeviceProperty,
base::Value(kUnconfiguredNetwork.device_path));
// Flush out pending state updates.
base::RunLoop().RunUntilIdle();
chromeos::NetworkStateHandler::NetworkStateList state_list;
chromeos::NetworkStateHandler* network_state_handler =
chromeos::NetworkHandler::Get()->network_state_handler();
network_state_handler->GetNetworkListByType(
chromeos::NetworkTypePattern::Default(),
true, // configured_only
false, // visible_only,
0, // no limit to number of results
&state_list);
ASSERT_EQ(std::size(kFakeNetworks), state_list.size());
}
void TearDown() override { DeviceStatusCollectorTest::TearDown(); }
void ClearNetworkData() {
chromeos::ShillDeviceClient::TestInterface* device_client =
network_handler_test_helper_.device_test();
chromeos::ShillServiceClient::TestInterface* service_client =
network_handler_test_helper_.service_test();
device_client->ClearDevices();
service_client->ClearServices();
base::RunLoop().RunUntilIdle();
}
virtual void VerifyReporting() = 0;
private:
chromeos::NetworkHandlerTestHelper network_handler_test_helper_;
};
class DeviceStatusCollectorNetworkInterfacesTest
: public DeviceStatusCollectorNetworkTest {
protected:
void VerifyReporting() override {
int count = 0;
for (const FakeDeviceData& dev : kFakeDevices) {
if (dev.expected_type == -1)
continue;
// Find the corresponding entry in reporting data.
bool found_match = false;
google::protobuf::RepeatedPtrField<em::NetworkInterface>::const_iterator
iface;
for (iface = device_status_.network_interfaces().begin();
iface != device_status_.network_interfaces().end(); ++iface) {
// Check whether type, field presence and field values match.
if (dev.expected_type == iface->type() &&
iface->has_mac_address() == !!*dev.mac_address &&
iface->has_meid() == !!*dev.meid &&
iface->has_imei() == !!*dev.imei &&
iface->has_mdn() == !!*dev.mdn &&
iface->has_iccid() == !!*dev.iccid &&
iface->mac_address() == dev.mac_address &&
iface->meid() == dev.meid && iface->imei() == dev.imei &&
iface->device_path() == dev.device_path &&
iface->mdn() == dev.mdn && iface->iccid() == dev.iccid &&
(iface->type() != em::NetworkInterface::TYPE_CELLULAR ||
base::ranges::equal(iface->eids().begin(), iface->eids().end(),
kFakeSimSlots,
kFakeSimSlots + std::size(kFakeSimSlots),
base::ranges::equal_to(), base::identity(),
&FakeSimSlotInfo::eid))) {
found_match = true;
break;
}
}
EXPECT_TRUE(found_match);
count++;
}
EXPECT_EQ(count, device_status_.network_interfaces_size());
}
};
// TODO(crbug.com/1253206): Revive this test.
TEST_F(DeviceStatusCollectorNetworkInterfacesTest, DISABLED_TestNoInterfaces) {
ClearNetworkData();
DisableDefaultSettings();
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkConfiguration, true);
// If no interfaces are found, nothing should be reported.
GetStatus();
EXPECT_EQ(device_status_.SerializeAsString(), "");
}
TEST_F(DeviceStatusCollectorNetworkInterfacesTest, Default) {
scoped_feature_list_.InitAndEnableFeature(ash::features::kESimPolicy);
// Network interfaces should be reported by default, i.e if the policy is
// not set.
GetStatus();
VerifyReporting();
// Network interfaces should be reported if the policy is set to true.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkConfiguration, true);
GetStatus();
VerifyReporting();
// Network interfaces should not be reported if the policy is set to false.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkConfiguration, false);
GetStatus();
EXPECT_EQ(0, device_status_.network_interfaces_size());
}
TEST_F(DeviceStatusCollectorNetworkInterfacesTest, IfUnaffiliatedUser) {
scoped_feature_list_.InitAndEnableFeature(ash::features::kESimPolicy);
// Network interfaces should be reported for unaffiliated users.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkConfiguration, true);
const AccountId account_id0(AccountId::FromUserEmail("user0@managed.com"));
user_manager_->AddUserWithAffiliationAndType(account_id0, false,
user_manager::USER_TYPE_REGULAR);
GetStatus();
VerifyReporting();
}
TEST_F(DeviceStatusCollectorNetworkInterfacesTest, IfAffiliatedUser) {
scoped_feature_list_.InitAndEnableFeature(ash::features::kESimPolicy);
// Network interfaces should be reported for affiliated users.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkConfiguration, true);
const AccountId account_id0(AccountId::FromUserEmail("user0@managed.com"));
user_manager_->AddUserWithAffiliationAndType(account_id0, true,
user_manager::USER_TYPE_REGULAR);
GetStatus();
VerifyReporting();
}
TEST_F(DeviceStatusCollectorNetworkInterfacesTest, IfPublicSession) {
scoped_feature_list_.InitAndEnableFeature(ash::features::kESimPolicy);
// Network interfaces should be reported if in public session.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkConfiguration, true);
user_manager_->CreatePublicAccountUser(
AccountId::FromUserEmail(kPublicAccountId));
EXPECT_CALL(*user_manager_, IsLoggedInAsPublicAccount())
.WillRepeatedly(Return(true));
GetStatus();
VerifyReporting();
}
TEST_F(DeviceStatusCollectorNetworkInterfacesTest, IfKioskMode) {
scoped_feature_list_.InitAndEnableFeature(ash::features::kESimPolicy);
// Network interfaces should be reported if in kiosk mode.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkConfiguration, true);
user_manager_->CreateKioskAppUser(AccountId::FromUserEmail(kKioskAccountId));
EXPECT_CALL(*user_manager_, IsLoggedInAsKioskApp())
.WillRepeatedly(Return(true));
GetStatus();
VerifyReporting();
}
TEST_F(DeviceStatusCollectorNetworkInterfacesTest, TestCrosHealthdBusInfo) {
// Create a fake response from cros_healthd and populate it with some
// test values.
// Because this data collection is gated by the
// kReportDeviceNetworkConfiguration policy, this test uses the
// DeviceStatusCollectorNetworkInterfacesTest class.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkConfiguration, true);
SetFakeCrosHealthdData();
GetStatus();
// Verify the Network Adapter (bus device) info.
ASSERT_EQ(device_status_.network_adapter_info_size(), 2);
// Verify the PCI device.
const auto& network_adapter_0 = device_status_.network_adapter_info(0);
EXPECT_EQ(network_adapter_0.vendor_name(), kFakePciVendor);
EXPECT_EQ(network_adapter_0.device_name(), kFakePciProduct);
EXPECT_EQ(network_adapter_0.device_class(), em::ETHERNET_CONTROLLER);
EXPECT_EQ(network_adapter_0.bus_type(), em::PCI_BUS);
EXPECT_EQ(network_adapter_0.driver_size(), 1);
EXPECT_EQ(network_adapter_0.driver(0), kFakePciDriver);
// Verify the USB device.
const auto& network_adapter_1 = device_status_.network_adapter_info(1);
EXPECT_EQ(network_adapter_1.vendor_name(), kFakeUsbVendor);
EXPECT_EQ(network_adapter_1.device_name(), kFakeUsbProduct);
EXPECT_EQ(network_adapter_1.device_class(), em::WIRELESS_CONTROLLER);
EXPECT_EQ(network_adapter_1.bus_type(), em::USB_BUS);
EXPECT_EQ(network_adapter_1.driver_size(), 2);
EXPECT_EQ(network_adapter_1.driver(kFakeUsbInterfaceNumber0),
kFakeUsbDriver0);
EXPECT_EQ(network_adapter_1.driver(kFakeUsbInterfaceNumber1),
kFakeUsbDriver1);
}
class DeviceStatusCollectorNetworkStateTest
: public DeviceStatusCollectorNetworkTest {
protected:
void VerifyReporting() override {
EXPECT_EQ(std::size(kFakeNetworks),
static_cast<size_t>(device_status_.network_states_size()));
for (const FakeNetworkState& state : kFakeNetworks) {
bool found_match = false;
for (const em::NetworkState& proto_state :
device_status_.network_states()) {
// Make sure every item has a matching entry in the proto.
bool should_have_signal_strength = state.expected_signal_strength != 0;
if (proto_state.has_device_path() == (strlen(state.device_path) > 0) &&
proto_state.has_signal_strength() == should_have_signal_strength &&
proto_state.signal_strength() == state.expected_signal_strength &&
proto_state.connection_state() == state.expected_state) {
if (proto_state.has_ip_address())
EXPECT_EQ(proto_state.ip_address(), state.address);
else
EXPECT_EQ(0U, strlen(state.address));
if (proto_state.has_gateway())
EXPECT_EQ(proto_state.gateway(), state.gateway);
else
EXPECT_EQ(0U, strlen(state.gateway));
found_match = true;
break;
}
}
EXPECT_TRUE(found_match) << "No matching state for fake network "
<< " (" << state.name << ")";
}
}
};
TEST_F(DeviceStatusCollectorNetworkStateTest, Default) {
// Network state should not be reported by default, i.e if the policy is not
// set.
GetStatus();
EXPECT_EQ(0, device_status_.network_states_size());
// Mock that the device is in kiosk mode to report network state.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkStatus, true);
user_manager_->CreateKioskAppUser(AccountId::FromUserEmail(kKioskAccountId));
EXPECT_CALL(*user_manager_, IsLoggedInAsKioskApp())
.WillRepeatedly(Return(true));
GetStatus();
VerifyReporting();
// Network state should not be reported if the policy is set to false.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkStatus, false);
GetStatus();
EXPECT_EQ(0, device_status_.network_states_size());
// Network state should be reported if the policy is set to true.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkStatus, true);
GetStatus();
VerifyReporting();
}
// TODO(crbug.com/1253206): Revive this test.
TEST_F(DeviceStatusCollectorNetworkStateTest, DISABLED_TestNoNetworks) {
ClearNetworkData();
DisableDefaultSettings();
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkConfiguration, true);
// If no networks are found, nothing should be reported.
GetStatus();
EXPECT_EQ(device_status_.SerializeAsString(), "");
}
TEST_F(DeviceStatusCollectorNetworkStateTest, IfUnaffiliatedUser) {
// Network state shouldn't be reported for unaffiliated users.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkStatus, true);
const AccountId account_id0(AccountId::FromUserEmail("user0@managed.com"));
user_manager_->AddUserWithAffiliationAndType(account_id0, false,
user_manager::USER_TYPE_REGULAR);
GetStatus();
EXPECT_EQ(0, device_status_.network_states_size());
}
TEST_F(DeviceStatusCollectorNetworkStateTest, IfAffiliatedUser) {
// Network state should be reported for affiliated users.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkStatus, true);
const AccountId account_id0(AccountId::FromUserEmail("user0@managed.com"));
user_manager_->AddUserWithAffiliationAndType(account_id0, true,
user_manager::USER_TYPE_REGULAR);
GetStatus();
VerifyReporting();
}
TEST_F(DeviceStatusCollectorNetworkStateTest, IfPublicSession) {
// Network state should be reported if in public session.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkStatus, true);
user_manager_->CreatePublicAccountUser(
AccountId::FromUserEmail(kPublicAccountId));
EXPECT_CALL(*user_manager_, IsLoggedInAsPublicAccount())
.WillRepeatedly(Return(true));
GetStatus();
VerifyReporting();
}
TEST_F(DeviceStatusCollectorNetworkStateTest, IfKioskMode) {
// Network state should be reported if in kiosk mode.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
ash::kReportDeviceNetworkStatus, true);
user_manager_->CreateKioskAppUser(AccountId::FromUserEmail(kKioskAccountId));
EXPECT_CALL(*user_manager_, IsLoggedInAsKioskApp())
.WillRepeatedly(Return(true));
GetStatus();
VerifyReporting();
}
} // namespace policy