chromium/chrome/browser/ash/policy/reporting/metrics_reporting/network/network_events_observer_browsertest.cc

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <memory>
#include <string>
#include <utility>

#include "base/functional/bind.h"
#include "base/run_loop.h"
#include "base/values.h"
#include "chrome/browser/ash/login/test/cryptohome_mixin.h"
#include "chrome/browser/ash/policy/affiliation/affiliation_mixin.h"
#include "chrome/browser/ash/policy/affiliation/affiliation_test_helper.h"
#include "chrome/browser/ash/policy/core/device_policy_cros_browser_test.h"
#include "chrome/browser/ash/policy/reporting/metrics_reporting/network/network_events_observer.h"
#include "chrome/browser/ash/settings/scoped_testing_cros_settings.h"
#include "chrome/browser/ash/settings/stub_cros_settings_provider.h"
#include "chromeos/ash/components/dbus/shill/shill_service_client.h"
#include "chromeos/ash/components/network/network_handler_test_helper.h"
#include "chromeos/ash/components/settings/cros_settings_names.h"
#include "chromeos/dbus/missive/missive_client_test_observer.h"
#include "chromeos/services/network_health/public/mojom/network_health_types.mojom.h"
#include "components/reporting/proto/synced/metric_data.pb.h"
#include "components/reporting/proto/synced/record.pb.h"
#include "components/reporting/proto/synced/record_constants.pb.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/test_launcher.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"

using ::testing::Eq;

namespace reporting {
namespace {

constexpr int kSignalStrength = 50;
constexpr char kWifiGuid[] = "wifi-guid";
constexpr char kWifiDevicePath[] = "/device/wlan";
constexpr char kWifiServicePath[] = "/service/wlan";
constexpr char kWifiConfig[] =
    R"({"GUID": "%s", "Type": "wifi", "State": "online",
    "WiFi.SignalStrengthRssi": %d})";
constexpr int kGoodSignalStrengthRssi = -50;
constexpr int kLowSignalStrengthRssi = -75;

bool IsEventDrivenNetworkTelemetry(const ::reporting::Record& record) {
  if (record.destination() != Destination::TELEMETRY_METRIC) {
    return false;
  }

  MetricData record_data;
  EXPECT_TRUE(record_data.ParseFromString(record.data()));

  return record_data.has_telemetry_data() &&
         record_data.telemetry_data().is_event_driven();
}

Record GetNextRecord(::chromeos::MissiveClientTestObserver* observer,
                     Priority expectedPriority) {
  const std::tuple<Priority, Record>& enqueued_record =
      observer->GetNextEnqueuedRecord();
  Priority priority = std::get<0>(enqueued_record);
  Record record = std::get<1>(enqueued_record);
  EXPECT_THAT(priority, Eq(expectedPriority));
  return record;
}

class NetworkEventsBrowserTest : public ::policy::DevicePolicyCrosBrowserTest {
 protected:
  NetworkEventsBrowserTest() {
    crypto_home_mixin_.MarkUserAsExisting(affiliation_mixin_.account_id());
  }

  void SetUpCommandLine(base::CommandLine* command_line) override {
    ::policy::AffiliationTestHelper::AppendCommandLineSwitchesForLoginManager(
        command_line);
    ::policy::DevicePolicyCrosBrowserTest::SetUpCommandLine(command_line);
  }

  void SetUpOnMainThread() override {
    ::policy::DevicePolicyCrosBrowserTest::SetUpOnMainThread();
    if (content::IsPreTest()) {
      // Preliminary setup - set up affiliated user
      ::policy::AffiliationTestHelper::PreLoginUser(
          affiliation_mixin_.account_id());

      return;
    }
    network_handler_test_helper_ =
        std::make_unique<::ash::NetworkHandlerTestHelper>();
    network_handler_test_helper_->AddDefaultProfiles();
    network_handler_test_helper_->ResetDevicesAndServices();
    auto* const device_client = network_handler_test_helper_->device_test();
    device_client->AddDevice(kWifiDevicePath, shill::kTypeWifi, "wifi0");
    base::RunLoop().RunUntilIdle();
    auto* const service_client = network_handler_test_helper_->service_test();
    service_client->AddService(kWifiServicePath, kWifiGuid, "wifi-name",
                               shill::kTypeWifi, shill::kStateOnline, true);
    service_client->SetServiceProperty(kWifiServicePath, shill::kDeviceProperty,
                                       base::Value(kWifiDevicePath));
    std::string service_config_good_signal =
        base::StringPrintf(kWifiConfig, kWifiGuid, kGoodSignalStrengthRssi);
    network_handler_test_helper_->ConfigureService(service_config_good_signal);
    service_client->SetServiceProperty(
        kWifiServicePath, shill::kProfileProperty,
        base::Value(network_handler_test_helper_->ProfilePathUser()));

    ::policy::AffiliationTestHelper::LoginUser(affiliation_mixin_.account_id());
  }

  void EnablePolicy() {
    scoped_testing_cros_settings_.device_settings()->SetBoolean(
        ash::kDeviceReportNetworkEvents, true);
  }

  void SetWifiSignalEventDrivenPolicy() {
    base::Value::List telemetry_list;
    telemetry_list.Append("network_telemetry");
    scoped_testing_cros_settings_.device_settings()->Set(
        ash::kReportDeviceSignalStrengthEventDrivenTelemetry,
        base::Value(std::move(telemetry_list)));
  }

  std::unique_ptr<::ash::NetworkHandlerTestHelper> network_handler_test_helper_;

  ::policy::DevicePolicyCrosTestHelper test_helper_;
  ::policy::AffiliationMixin affiliation_mixin_{&mixin_host_, &test_helper_};
  ash::CryptohomeMixin crypto_home_mixin_{&mixin_host_};
  ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
};

IN_PROC_BROWSER_TEST_F(NetworkEventsBrowserTest,
                       PRE_ConnectionStateAffiliatedUserAndPolicyEnabled) {
  // dummy case to register user.
}

IN_PROC_BROWSER_TEST_F(NetworkEventsBrowserTest,
                       ConnectionStateAffiliatedUserAndPolicyEnabled) {
  chromeos::MissiveClientTestObserver missive_event_observer(
      Destination::EVENT_METRIC);

  EnablePolicy();
  ash::ShillServiceClient::Get()->GetTestInterface()->SetServiceProperty(
      kWifiServicePath, shill::kStateProperty, base::Value(shill::kStateIdle));

  const Record& record =
      GetNextRecord(&missive_event_observer, Priority::SLOW_BATCH);
  ASSERT_TRUE(record.has_source_info());
  EXPECT_THAT(record.source_info().source(), Eq(SourceInfo::ASH));
  MetricData record_data;

  ASSERT_TRUE(record_data.ParseFromString(record.data()));
  // Testing event found successfully.
  EXPECT_THAT(record_data.event_data().type(),
              Eq(MetricEventType::NETWORK_STATE_CHANGE));
}

IN_PROC_BROWSER_TEST_F(NetworkEventsBrowserTest,
                       PRE_SignalStrengthAffiliatedUserAndPolicyEnabled) {
  // dummy case to register user.
}

IN_PROC_BROWSER_TEST_F(NetworkEventsBrowserTest,
                       SignalStrengthAffiliatedUserAndPolicyEnabled) {
  chromeos::MissiveClientTestObserver missive_event_observer(
      Destination::EVENT_METRIC);
  chromeos::MissiveClientTestObserver missive_telemetry_observer(
      base::BindRepeating(&IsEventDrivenNetworkTelemetry));

  const std::string service_config_low_signal =
      base::StringPrintf(kWifiConfig, kWifiGuid, kLowSignalStrengthRssi);
  network_handler_test_helper_->ConfigureService(service_config_low_signal);

  EnablePolicy();
  SetWifiSignalEventDrivenPolicy();
  ash::ShillServiceClient::Get()->GetTestInterface()->SetServiceProperty(
      kWifiServicePath, shill::kSignalStrengthProperty,
      base::Value(kSignalStrength));

  Record record = GetNextRecord(&missive_event_observer, Priority::SLOW_BATCH);
  ASSERT_TRUE(record.has_source_info());
  EXPECT_THAT(record.source_info().source(), Eq(SourceInfo::ASH));
  MetricData event_record_data;

  ASSERT_TRUE(event_record_data.ParseFromString(record.data()));
  EXPECT_THAT(event_record_data.event_data().type(),
              Eq(MetricEventType::WIFI_SIGNAL_STRENGTH_LOW));

  record = GetNextRecord(&missive_telemetry_observer, Priority::MANUAL_BATCH);
  ASSERT_TRUE(record.has_source_info());
  EXPECT_THAT(record.source_info().source(), Eq(SourceInfo::ASH));
  MetricData telemetry_record_data;

  ASSERT_TRUE(telemetry_record_data.ParseFromString(record.data()));
  ASSERT_TRUE(telemetry_record_data.telemetry_data().has_networks_telemetry());
  EXPECT_FALSE(telemetry_record_data.telemetry_data()
                   .networks_telemetry()
                   .network_telemetry()
                   .empty());
}

}  // namespace
}  // namespace reporting