chromium/chromeos/ash/components/phonehub/phone_hub_ui_readiness_recorder_unittest.cc

// 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 "chromeos/ash/components/phonehub/phone_hub_ui_readiness_recorder.h"

#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "chromeos/ash/components/phonehub/fake_feature_status_provider.h"
#include "chromeos/ash/components/phonehub/feature_status_provider.h"
#include "chromeos/ash/services/secure_channel/public/cpp/client/fake_connection_manager.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace ash::phonehub {
namespace {
constexpr auto kLatencyDelta = base::Milliseconds(500u);
}  // namespace

class PhoneHubUiReadinessRecorderTest : public testing::Test {
 protected:
  PhoneHubUiReadinessRecorderTest() = default;
  PhoneHubUiReadinessRecorderTest(const PhoneHubUiReadinessRecorderTest&) =
      delete;
  PhoneHubUiReadinessRecorderTest& operator=(
      const PhoneHubUiReadinessRecorderTest&) = delete;
  ~PhoneHubUiReadinessRecorderTest() override = default;

  void SetUp() override {
    feature_status_provider_ = std::make_unique<FakeFeatureStatusProvider>();
    connection_manager_ =
        std::make_unique<secure_channel::FakeConnectionManager>();
    recorder_ = std::make_unique<PhoneHubUiReadinessRecorder>(
        feature_status_provider_.get(), connection_manager_.get());
  }

  base::test::TaskEnvironment task_environment_{
      base::test::TaskEnvironment::TimeSource::MOCK_TIME};

  std::unique_ptr<FakeFeatureStatusProvider> feature_status_provider_;
  std::unique_ptr<secure_channel::FakeConnectionManager> connection_manager_;
  std::unique_ptr<PhoneHubUiReadinessRecorder> recorder_;
  base::HistogramTester histogram_tester_;
};

TEST_F(PhoneHubUiReadinessRecorderTest, RecordMessageLatency) {
  feature_status_provider_->SetStatus(FeatureStatus::kEnabledAndConnected);
  recorder_->RecordCrosStateMessageSent();
  task_environment_.FastForwardBy(kLatencyDelta);
  recorder_->RecordPhoneStatusSnapShotReceived();
  histogram_tester_.ExpectTimeBucketCount(
      "PhoneHub.InitialPhoneStatusSnapshot.Latency", kLatencyDelta,
      /*expected_count=*/1);
  histogram_tester_.ExpectBucketCount(
      "PhoneHub.InitialPhoneStatusSnapshot.Received", true, 1);
  EXPECT_TRUE(recorder_->message_sent_timestamp_.is_null());

  feature_status_provider_->SetStatus(FeatureStatus::kEnabledButDisconnected);
  recorder_->RecordCrosStateMessageSent();
  EXPECT_FALSE(recorder_->is_cros_state_message_sent_);

  recorder_->RecordPhoneStatusSnapShotReceived();
  EXPECT_FALSE(recorder_->is_phone_status_snapshot_processed_);
}

TEST_F(PhoneHubUiReadinessRecorderTest, RecordMessageSuccess) {
  feature_status_provider_->SetStatus(FeatureStatus::kEnabledAndConnected);
  recorder_->RecordCrosStateMessageSent();

  feature_status_provider_->SetStatus(FeatureStatus::kUnavailableBluetoothOff);
  histogram_tester_.ExpectBucketCount(
      "PhoneHub.InitialPhoneStatusSnapshot.Received", true, 0);
  histogram_tester_.ExpectBucketCount(
      "PhoneHub.InitialPhoneStatusSnapshot.Received", false, 1);
  EXPECT_FALSE(recorder_->is_cros_state_message_sent_);
  EXPECT_FALSE(recorder_->is_phone_status_snapshot_processed_);

  feature_status_provider_->SetStatus(FeatureStatus::kEnabledButDisconnected);
  histogram_tester_.ExpectBucketCount(
      "PhoneHub.InitialPhoneStatusSnapshot.Received", true, 0);
  histogram_tester_.ExpectBucketCount(
      "PhoneHub.InitialPhoneStatusSnapshot.Received", false, 1);

  feature_status_provider_->SetStatus(FeatureStatus::kEnabledAndConnected);
  recorder_->RecordCrosStateMessageSent();
  recorder_->RecordPhoneStatusSnapShotReceived();
  feature_status_provider_->SetStatus(FeatureStatus::kEnabledButDisconnected);
  histogram_tester_.ExpectBucketCount(
      "PhoneHub.InitialPhoneStatusSnapshot.Received", true, 1);
  histogram_tester_.ExpectBucketCount(
      "PhoneHub.InitialPhoneStatusSnapshot.Received", false, 1);
}

TEST_F(PhoneHubUiReadinessRecorderTest, RecordUiReadyLatency) {
  connection_manager_->SetStatus(
      secure_channel::ConnectionManager::Status::kConnected);
  EXPECT_EQ(recorder_->connection_flow_state_,
            ConnectionFlowState::kSecureChannelConnected);

  recorder_
      ->RecordCrosStateMessageSent();  // simulate sending cros state message
  EXPECT_EQ(recorder_->connection_flow_state_,
            ConnectionFlowState::kCrosStateMessageSent);

  recorder_->RecordPhoneStatusSnapShotReceived();  // simulate receiving cros
                                                   // state message
  EXPECT_EQ(recorder_->connection_flow_state_,
            ConnectionFlowState::kPhoneSnapShotReceivedButNoPhoneModelSet);

  task_environment_.FastForwardBy(kLatencyDelta);

  recorder_->RecordPhoneHubUiConnected();  // simulate Phone Hub ui state is
                                           // updated to connected.
  EXPECT_EQ(recorder_->connection_flow_state_,
            ConnectionFlowState::kUiConnected);
  histogram_tester_.ExpectTimeBucketCount("PhoneHub.UiReady.Latency",
                                          kLatencyDelta,
                                          /*expected_count=*/1);
  histogram_tester_.ExpectBucketCount("PhoneHub.UiReady.Result",
                                      ConnectionFlowState::kUiConnected, 1);
}

TEST_F(PhoneHubUiReadinessRecorderTest,
       RecordUiReainessFailedAfterSecureChannelConnected) {
  connection_manager_->SetStatus(
      secure_channel::ConnectionManager::Status::kConnected);
  EXPECT_EQ(recorder_->connection_flow_state_,
            ConnectionFlowState::kSecureChannelConnected);
  connection_manager_->SetStatus(
      secure_channel::ConnectionManager::Status::kConnecting);
  histogram_tester_.ExpectBucketCount(
      "PhoneHub.UiReady.Result", ConnectionFlowState::kSecureChannelConnected,
      1);
}

TEST_F(PhoneHubUiReadinessRecorderTest,
       RecordUiReainessFailedAfterCrosStateMessageSent) {
  connection_manager_->SetStatus(
      secure_channel::ConnectionManager::Status::kConnected);
  recorder_
      ->RecordCrosStateMessageSent();  // simulate sending cros state message
  connection_manager_->SetStatus(
      secure_channel::ConnectionManager::Status::kDisconnected);
  histogram_tester_.ExpectBucketCount(
      "PhoneHub.UiReady.Result", ConnectionFlowState::kCrosStateMessageSent, 1);
}

TEST_F(PhoneHubUiReadinessRecorderTest,
       RecordUiReainessFailedAfterPhoneSnapShotReceived) {
  connection_manager_->SetStatus(
      secure_channel::ConnectionManager::Status::kConnected);
  recorder_
      ->RecordCrosStateMessageSent();  // simulate sending cros state message
  recorder_->RecordPhoneStatusSnapShotReceived();  // simulate receiving cros
                                                   // state message
  connection_manager_->SetStatus(
      secure_channel::ConnectionManager::Status::kDisconnected);
  histogram_tester_.ExpectBucketCount(
      "PhoneHub.UiReady.Result",
      ConnectionFlowState::kPhoneSnapShotReceivedButNoPhoneModelSet, 1);
}

TEST_F(PhoneHubUiReadinessRecorderTest,
       RecordUiReainessDisconnectAfterSuccessfulConnection) {
  connection_manager_->SetStatus(
      secure_channel::ConnectionManager::Status::kConnected);
  recorder_
      ->RecordCrosStateMessageSent();  // simulate sending cros state message
  recorder_->RecordPhoneStatusSnapShotReceived();  // simulate receiving cros
                                                   // state message
  recorder_->RecordPhoneHubUiConnected();  // simulate Phone Hub ui state is
                                           // updated to connected.
  EXPECT_EQ(recorder_->connection_flow_state_,
            ConnectionFlowState::kUiConnected);
  histogram_tester_.ExpectBucketCount("PhoneHub.UiReady.Result",
                                      ConnectionFlowState::kUiConnected, 1);
  connection_manager_->SetStatus(
      secure_channel::ConnectionManager::Status::kDisconnected);
  histogram_tester_.ExpectBucketCount(
      "PhoneHub.UiReady.Result", ConnectionFlowState::kUiConnected,
      1);  // If disconnection happens after UI is fully ready, we should not
           // record any data to histogram.
}

}  // namespace ash::phonehub