| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <sys/types.h> |
| #include <utility> |
| |
| #include "base/memory/raw_ptr.h" |
| #include "base/test/task_environment.h" |
| #include "base/time/time.h" |
| #include "chrome/browser/ash/login/users/chrome_user_manager.h" |
| #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h" |
| #include "chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager.h" |
| #include "chrome/browser/ash/policy/reporting/metrics_reporting/network/fake_network_diagnostics_util.h" |
| #include "chrome/browser/ash/policy/reporting/metrics_reporting/network/https_latency_event_detector.h" |
| #include "chrome/browser/ash/settings/scoped_testing_cros_settings.h" |
| #include "chrome/browser/ash/settings/stub_cros_settings_provider.h" |
| #include "chrome/browser/chromeos/reporting/metric_default_utils.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "chromeos/ash/components/dbus/debug_daemon/debug_daemon_client.h" |
| #include "chromeos/ash/components/mojo_service_manager/fake_mojo_service_manager.h" |
| #include "chromeos/ash/components/network/network_handler_test_helper.h" |
| #include "chromeos/ash/components/settings/cros_settings_names.h" |
| #include "chromeos/ash/services/cros_healthd/public/cpp/fake_cros_healthd.h" |
| #include "chromeos/ash/services/cros_healthd/public/mojom/cros_healthd.mojom.h" |
| #include "components/reporting/metrics/fakes/fake_metric_report_queue.h" |
| #include "components/reporting/proto/synced/metric_data.pb.h" |
| #include "components/reporting/proto/synced/record_constants.pb.h" |
| #include "components/reporting/util/test_support_callbacks.h" |
| #include "components/session_manager/core/session_manager.h" |
| #include "components/user_manager/scoped_user_manager.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using HttpsLatencyProblemMojom = |
| ::chromeos::network_diagnostics::mojom::HttpsLatencyProblem; |
| using RoutineVerdictMojom = |
| ::chromeos::network_diagnostics::mojom::RoutineVerdict; |
| |
| namespace reporting { |
| namespace { |
| |
| class HttpsLatencyTestReportQueue : public test::FakeMetricReportQueue { |
| public: |
| HttpsLatencyTestReportQueue() = default; |
| HttpsLatencyTestReportQueue(const HttpsLatencyTestReportQueue&) = delete; |
| HttpsLatencyTestReportQueue& operator=(const HttpsLatencyTestReportQueue&) = |
| delete; |
| |
| ~HttpsLatencyTestReportQueue() override = default; |
| |
| // Override to block out unwanted metrics being reported. |
| void Enqueue(MetricData metric_data, |
| ReportQueue::EnqueueCallback callback) override { |
| if (!metric_data.telemetry_data() |
| .networks_telemetry() |
| .has_https_latency_data()) { |
| return; |
| } |
| test::FakeMetricReportQueue::Enqueue(std::move(metric_data), |
| std::move(callback)); |
| } |
| }; |
| |
| class FakeMetricReportingManagerDelegate |
| : public MetricReportingManager::Delegate { |
| public: |
| FakeMetricReportingManagerDelegate( |
| FakeNetworkDiagnostics* fake_diagnostics, |
| std::unique_ptr<MetricReportQueue> metric_report_queue) |
| : fake_diagnostics_(fake_diagnostics) { |
| metric_report_queue_ = std::move(metric_report_queue); |
| } |
| |
| FakeMetricReportingManagerDelegate( |
| const FakeMetricReportingManagerDelegate& other) = delete; |
| FakeMetricReportingManagerDelegate& operator=( |
| const FakeMetricReportingManagerDelegate& other) = delete; |
| ~FakeMetricReportingManagerDelegate() override = default; |
| |
| std::unique_ptr<Sampler> GetHttpsLatencySampler() const override { |
| return std::make_unique<HttpsLatencySampler>( |
| std::make_unique<FakeHttpsLatencyDelegate>(fake_diagnostics_)); |
| } |
| |
| bool IsDeprovisioned() const override { return false; } |
| |
| bool IsAppServiceAvailableForProfile(Profile* profile) const override { |
| return false; |
| } |
| |
| std::unique_ptr<MetricReportQueue> CreateMetricReportQueue( |
| EventType event_type, |
| Destination destination, |
| Priority priority) override { |
| if (event_type != EventType::kDevice || |
| destination != Destination::EVENT_METRIC || |
| priority != Priority::SLOW_BATCH) { |
| return nullptr; |
| } |
| |
| return std::move(metric_report_queue_); |
| } |
| |
| private: |
| const raw_ptr<FakeNetworkDiagnostics, ExperimentalAsh> fake_diagnostics_; |
| |
| std::unique_ptr<MetricReportQueue> metric_report_queue_; |
| }; |
| |
| class HttpsLatencyEventsTest : public ::testing::Test { |
| public: |
| HttpsLatencyEventsTest() = default; |
| HttpsLatencyEventsTest(const HttpsLatencyEventsTest&) = delete; |
| HttpsLatencyEventsTest& operator=(const HttpsLatencyEventsTest&) = delete; |
| |
| ~HttpsLatencyEventsTest() override = default; |
| |
| void SetUp() override { |
| ::ash::LoginState::Initialize(); |
| ::ash::DebugDaemonClient::InitializeFake(); |
| ::ash::cros_healthd::FakeCrosHealthd::Initialize(); |
| } |
| |
| void InitProfile(bool affiliated) { |
| auto user_manager = std::make_unique<ash::FakeChromeUserManager>(); |
| user_manager_ = user_manager.get(); |
| user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>( |
| std::move(user_manager)); |
| auto account_id = AccountId::FromUserEmail("ini_fan@gmail.com"); |
| TestingProfile::Builder profile_builder; |
| profile_builder.SetProfileName(account_id.GetUserEmail()); |
| profile_ = profile_builder.Build(); |
| user_manager_->AddUserWithAffiliationAndTypeAndProfile( |
| account_id, affiliated, user_manager::USER_TYPE_REGULAR, |
| profile_.get()); |
| user_manager_->LoginUser(account_id, /*set_profile_created_flag=*/false); |
| } |
| |
| void ProcessProblem(FakeNetworkDiagnostics* diagnostics, |
| HttpsLatencyProblemMojom problem, |
| base::TimeDelta delay) { |
| diagnostics->SetResultProblem(problem); |
| task_environment_.FastForwardBy(delay); |
| diagnostics->ExecuteCallback(); |
| task_environment_.RunUntilIdle(); |
| } |
| |
| void ProcessNoProblem(FakeNetworkDiagnostics* diagnostics, |
| int latency, |
| base::TimeDelta delay) { |
| diagnostics->SetResultNoProblem(latency); |
| task_environment_.FastForwardBy(delay); |
| diagnostics->ExecuteCallback(); |
| task_environment_.RunUntilIdle(); |
| } |
| |
| void TearDown() override { |
| ::ash::cros_healthd::FakeCrosHealthd::Shutdown(); |
| ::ash::DebugDaemonClient::Shutdown(); |
| ::ash::LoginState::Shutdown(); |
| } |
| |
| void EnableDeviceNetworkStatusPolicy() { |
| scoped_testing_cros_settings_.device_settings()->SetBoolean( |
| ::ash::kReportDeviceNetworkStatus, true); |
| } |
| |
| void DisableDeviceNetworkStatusPolicy() { |
| scoped_testing_cros_settings_.device_settings()->SetBoolean( |
| ::ash::kReportDeviceNetworkStatus, false); |
| } |
| |
| content::BrowserTaskEnvironment task_environment_{ |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME}; |
| ::ash::mojo_service_manager::FakeMojoServiceManager fake_service_manager_; |
| |
| ash::ScopedStubInstallAttributes scoped_stub_install_attributes_; |
| ash::ScopedTestingCrosSettings scoped_testing_cros_settings_; |
| |
| std::unique_ptr<TestingProfile> profile_; |
| raw_ptr<ash::FakeChromeUserManager, ExperimentalAsh> user_manager_; |
| std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_; |
| |
| ::ash::NetworkHandlerTestHelper network_handler_test_helper_; |
| |
| std::unique_ptr<MetricReportQueue> metric_report_queue_; |
| raw_ptr<HttpsLatencyTestReportQueue, ExperimentalAsh> report_queue_; |
| }; |
| |
| TEST_F(HttpsLatencyEventsTest, RoutineVerdictProblem) { |
| InitProfile(/*affiliated=*/true); |
| EnableDeviceNetworkStatusPolicy(); |
| |
| FakeNetworkDiagnostics diagnostics; |
| int latency_ms = 50; |
| diagnostics.SetResultNoProblem(latency_ms); |
| |
| HttpsLatencyTestReportQueue* fake_event_queue = |
| new HttpsLatencyTestReportQueue(); |
| std::unique_ptr<MetricReportQueue> metric_report_queue_(fake_event_queue); |
| auto delegate = std::make_unique<FakeMetricReportingManagerDelegate>( |
| &diagnostics, std::move(metric_report_queue_)); |
| auto init_delay = delegate->GetInitDelay(); |
| std::unique_ptr<MetricReportingManager> metric_reporting_manager = |
| MetricReportingManager::CreateForTesting(std::move(delegate), nullptr); |
| |
| metric_reporting_manager->OnLogin(profile_.get()); |
| ProcessNoProblem(&diagnostics, latency_ms, init_delay); |
| EXPECT_TRUE(fake_event_queue->IsEmpty()); |
| |
| ProcessNoProblem(&diagnostics, latency_ms, |
| metrics::kDefaultNetworkTelemetryEventCheckingRate); |
| EXPECT_TRUE(fake_event_queue->IsEmpty()); |
| |
| // Send a problem after login. |
| ProcessProblem(&diagnostics, HttpsLatencyProblemMojom::kFailedHttpsRequests, |
| metrics::kDefaultNetworkTelemetryCollectionRate); |
| MetricData metric_result = fake_event_queue->GetMetricDataReported(); |
| |
| EXPECT_EQ(metric_result.event_data().type(), |
| MetricEventType::NETWORK_HTTPS_LATENCY_CHANGE); |
| ASSERT_TRUE(metric_result.telemetry_data() |
| .networks_telemetry() |
| .has_https_latency_data()); |
| EXPECT_EQ(metric_result.telemetry_data() |
| .networks_telemetry() |
| .https_latency_data() |
| .verdict(), |
| RoutineVerdict::PROBLEM); |
| EXPECT_EQ(metric_result.telemetry_data() |
| .networks_telemetry() |
| .https_latency_data() |
| .latency_ms(), |
| latency_ms); |
| EXPECT_EQ(metric_result.telemetry_data() |
| .networks_telemetry() |
| .https_latency_data() |
| .problem(), |
| HttpsLatencyProblem::FAILED_HTTPS_REQUESTS); |
| |
| // Make sure nothing is reported for a continuing problem. |
| ProcessProblem(&diagnostics, HttpsLatencyProblemMojom::kFailedHttpsRequests, |
| metrics::kDefaultNetworkTelemetryCollectionRate); |
| ASSERT_TRUE(fake_event_queue->IsEmpty()); |
| |
| // Report when a problem is resolved. |
| ProcessNoProblem(&diagnostics, latency_ms, |
| metrics::kDefaultNetworkTelemetryCollectionRate); |
| metric_result = fake_event_queue->GetMetricDataReported(); |
| EXPECT_EQ(metric_result.event_data().type(), |
| MetricEventType::NETWORK_HTTPS_LATENCY_CHANGE); |
| ASSERT_TRUE(metric_result.telemetry_data() |
| .networks_telemetry() |
| .has_https_latency_data()); |
| EXPECT_EQ(metric_result.telemetry_data() |
| .networks_telemetry() |
| .https_latency_data() |
| .verdict(), |
| RoutineVerdict::NO_PROBLEM); |
| EXPECT_EQ(metric_result.telemetry_data() |
| .networks_telemetry() |
| .https_latency_data() |
| .latency_ms(), |
| latency_ms); |
| EXPECT_FALSE(metric_result.telemetry_data() |
| .networks_telemetry() |
| .https_latency_data() |
| .has_problem()); |
| |
| // Ensure going from no problem reported to a problem is reported. |
| ProcessProblem(&diagnostics, HttpsLatencyProblemMojom::kFailedHttpsRequests, |
| metrics::kDefaultNetworkTelemetryCollectionRate); |
| |
| metric_result = fake_event_queue->GetMetricDataReported(); |
| EXPECT_EQ(metric_result.event_data().type(), |
| MetricEventType::NETWORK_HTTPS_LATENCY_CHANGE); |
| ASSERT_TRUE(metric_result.telemetry_data() |
| .networks_telemetry() |
| .has_https_latency_data()); |
| EXPECT_EQ(metric_result.telemetry_data() |
| .networks_telemetry() |
| .https_latency_data() |
| .verdict(), |
| RoutineVerdict::PROBLEM); |
| EXPECT_EQ(metric_result.telemetry_data() |
| .networks_telemetry() |
| .https_latency_data() |
| .latency_ms(), |
| 50); |
| EXPECT_EQ(metric_result.telemetry_data() |
| .networks_telemetry() |
| .https_latency_data() |
| .problem(), |
| HttpsLatencyProblem::FAILED_HTTPS_REQUESTS); |
| } |
| |
| TEST_F(HttpsLatencyEventsTest, ReportDeviceNetworkStatusDisabled) { |
| InitProfile(/*affiliated=*/true); |
| DisableDeviceNetworkStatusPolicy(); |
| |
| FakeNetworkDiagnostics diagnostics; |
| HttpsLatencyTestReportQueue* fake_event_queue = |
| new HttpsLatencyTestReportQueue(); |
| std::unique_ptr<MetricReportQueue> metric_report_queue_(fake_event_queue); |
| auto delegate = std::make_unique<FakeMetricReportingManagerDelegate>( |
| &diagnostics, std::move(metric_report_queue_)); |
| std::unique_ptr<MetricReportingManager> metric_reporting_manager = |
| MetricReportingManager::CreateForTesting(std::move(delegate), nullptr); |
| metric_reporting_manager->OnLogin(profile_.get()); |
| |
| ProcessProblem(&diagnostics, HttpsLatencyProblemMojom::kFailedHttpsRequests, |
| metrics::kDefaultNetworkTelemetryEventCheckingRate); |
| ASSERT_TRUE(fake_event_queue->IsEmpty()); |
| } |
| |
| TEST_F(HttpsLatencyEventsTest, ReportDeviceNetworkStatusUnaffiliatedUser) { |
| InitProfile(/*affiliated=*/false); |
| EnableDeviceNetworkStatusPolicy(); |
| |
| FakeNetworkDiagnostics diagnostics; |
| HttpsLatencyTestReportQueue* fake_event_queue = |
| new HttpsLatencyTestReportQueue(); |
| std::unique_ptr<MetricReportQueue> metric_report_queue_(fake_event_queue); |
| auto delegate = std::make_unique<FakeMetricReportingManagerDelegate>( |
| &diagnostics, std::move(metric_report_queue_)); |
| std::unique_ptr<MetricReportingManager> metric_reporting_manager = |
| MetricReportingManager::CreateForTesting(std::move(delegate), nullptr); |
| metric_reporting_manager->OnLogin(profile_.get()); |
| |
| ProcessProblem(&diagnostics, HttpsLatencyProblemMojom::kFailedHttpsRequests, |
| metrics::kDefaultNetworkTelemetryEventCheckingRate); |
| ASSERT_TRUE(fake_event_queue->IsEmpty()); |
| } |
| |
| TEST_F(HttpsLatencyEventsTest, EventCheckingRateSet) { |
| InitProfile(/*affiliated=*/true); |
| EnableDeviceNetworkStatusPolicy(); |
| auto default_rate = metrics::kDefaultNetworkTelemetryEventCheckingRate; |
| // Double the default checking rate |
| scoped_testing_cros_settings_.device_settings()->SetInteger( |
| ::ash::kReportDeviceNetworkTelemetryEventCheckingRateMs, |
| default_rate.InMilliseconds() * 2); |
| scoped_testing_cros_settings_.device_settings()->SetInteger( |
| ::ash::kReportDeviceNetworkTelemetryCollectionRateMs, |
| default_rate.InMilliseconds()); |
| int latency_ms = 50; |
| |
| FakeNetworkDiagnostics diagnostics; |
| HttpsLatencyTestReportQueue* fake_event_queue = |
| new HttpsLatencyTestReportQueue(); |
| std::unique_ptr<MetricReportQueue> metric_report_queue_(fake_event_queue); |
| auto delegate = std::make_unique<FakeMetricReportingManagerDelegate>( |
| &diagnostics, std::move(metric_report_queue_)); |
| auto init_delay = delegate->GetInitDelay(); |
| std::unique_ptr<MetricReportingManager> metric_reporting_manager = |
| MetricReportingManager::CreateForTesting(std::move(delegate), nullptr); |
| metric_reporting_manager->OnLogin(profile_.get()); |
| |
| ProcessNoProblem(&diagnostics, latency_ms, init_delay); |
| EXPECT_TRUE(fake_event_queue->IsEmpty()); |
| |
| // The set checking rate is double the default, expect nothing. |
| ProcessProblem(&diagnostics, HttpsLatencyProblemMojom::kFailedHttpsRequests, |
| metrics::kDefaultNetworkTelemetryEventCheckingRate); |
| EXPECT_TRUE(fake_event_queue->IsEmpty()); |
| |
| // Now that double the default rate has passed, expect something reported. |
| task_environment_.FastForwardBy( |
| metrics::kDefaultNetworkTelemetryEventCheckingRate); |
| diagnostics.ExecuteCallback(); |
| |
| MetricData metric_result = fake_event_queue->GetMetricDataReported(); |
| EXPECT_EQ(metric_result.event_data().type(), |
| MetricEventType::NETWORK_HTTPS_LATENCY_CHANGE); |
| ASSERT_TRUE(metric_result.telemetry_data() |
| .networks_telemetry() |
| .has_https_latency_data()); |
| EXPECT_EQ(metric_result.telemetry_data() |
| .networks_telemetry() |
| .https_latency_data() |
| .verdict(), |
| RoutineVerdict::PROBLEM); |
| EXPECT_EQ(metric_result.telemetry_data() |
| .networks_telemetry() |
| .https_latency_data() |
| .problem(), |
| HttpsLatencyProblem::FAILED_HTTPS_REQUESTS); |
| } |
| |
| } // namespace |
| } // namespace reporting |