chromium/ash/system/network/sms_observer_unittest.cc

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

#include "ash/system/network/sms_observer.h"

#include <memory>
#include <optional>

#include "ash/constants/ash_features.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "chromeos/ash/components/network/fake_network_metadata_store.h"
#include "chromeos/ash/components/network/metrics/cellular_network_metrics_logger.h"
#include "chromeos/ash/components/network/network_handler.h"
#include "chromeos/ash/components/network/network_handler_test_helper.h"
#include "chromeos/ash/components/network/network_sms_handler.h"
#include "chromeos/ash/components/network/text_message_suppression_state.h"
#include "components/onc/onc_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/notification_list.h"
#include "ui/message_center/public/cpp/notification.h"

using message_center::MessageCenter;

namespace ash {

namespace {

constexpr char kTestGuid[] = "TestGuid";

std::optional<const std::string> GetStringOptional(const char* text) {
  if (text) {
    return std::make_optional<const std::string>(text);
  }
  return std::nullopt;
}

}  // namespace

struct SmsObserverTestCase {
  std::string test_name;
  bool use_suppress_text_message_flag;
};

class SmsObserverTest : public AshTestBase {
 public:
  SmsObserverTest() = default;

  SmsObserverTest(const SmsObserverTest&) = delete;
  SmsObserverTest& operator=(const SmsObserverTest&) = delete;

  ~SmsObserverTest() override = default;

  SmsObserver* GetSmsObserver() { return Shell::Get()->sms_observer_.get(); }

  void SetUp() override {
    AshTestBase::SetUp();
      test_helper_ = std::make_unique<NetworkHandlerTestHelper>();
      NetworkHandler::Get()->text_message_provider()->SetNetworkMetadataStore(
          &network_metadata_store_);
  }

  void SimulateMessageReceived(
      const char* kDefaultMessage = "FakeSMSClient: \xF0\x9F\x98\x8A",
      const char* kDefaultNumber = "000-000-0000",
      const char* kDefaultTimestamp = "Fri Jun  8 13:26:04 EDT 2016") {
    TextMessageData message_data(GetStringOptional(kDefaultNumber),
                                 GetStringOptional(kDefaultMessage),
                                 GetStringOptional(kDefaultTimestamp));
    GetSmsObserver()->MessageReceived(kTestGuid, message_data);
  }

  NetworkMetadataStore* network_metadata_store() {
    return &network_metadata_store_;
  }

  ManagedNetworkConfigurationHandler* managed_network_configuration_handler() {
    return NetworkHandler::Get()->managed_network_configuration_handler();
  }

 private:
  base::test::ScopedFeatureList features_;
  std::unique_ptr<NetworkHandlerTestHelper> test_helper_;
  FakeNetworkMetadataStore network_metadata_store_;
};

// Verify if notification is received after receiving a sms message with
// number and content.
TEST_F(SmsObserverTest, SendTextMessage) {
  EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size());
  SimulateMessageReceived();
  const message_center::NotificationList::Notifications notifications =
      MessageCenter::Get()->GetVisibleNotifications();
  EXPECT_EQ(1u, notifications.size());

  EXPECT_EQ(u"000-000-0000", (*notifications.begin())->title());
  EXPECT_EQ(u"FakeSMSClient: 😊", (*notifications.begin())->message());
  MessageCenter::Get()->RemoveAllNotifications(false /* by_user */,
                                               MessageCenter::RemoveType::ALL);
  EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size());
}

// Verify if no notification is received if phone number is missing in sms
// message.
TEST_F(SmsObserverTest, TextMessageMissingNumber) {
  EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size());
  SimulateMessageReceived("FakeSMSClient: Test Message.", nullptr);
  EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size());
}

// Verify if no notification is received if text body is empty in sms message.
TEST_F(SmsObserverTest, TextMessageEmptyText) {
  EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size());
  SimulateMessageReceived("");
  EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size());
}

// Verify if no notification is received if the text is missing in sms message.
TEST_F(SmsObserverTest, TextMessageMissingText) {
  EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size());
  SimulateMessageReceived("");
  EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size());
}

// Verify if 2 notification received after receiving 2 sms messages from the
// same number.
TEST_F(SmsObserverTest, MultipleTextMessages) {
  EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size());
  SimulateMessageReceived("first message");
  SimulateMessageReceived("second message");
  const message_center::NotificationList::Notifications notifications =
      MessageCenter::Get()->GetVisibleNotifications();
  EXPECT_EQ(2u, notifications.size());

  for (message_center::Notification* iter : notifications) {
    if (iter->id().find("chrome://network/sms1") != std::string::npos) {
      EXPECT_EQ(u"000-000-0000", iter->title());
      EXPECT_EQ(u"first message", iter->message());
    } else if (iter->id().find("chrome://network/sms2") != std::string::npos) {
      EXPECT_EQ(u"000-000-0000", iter->title());
      EXPECT_EQ(u"second message", iter->message());
    } else {
      ASSERT_TRUE(false);
    }
  }
}

class SmsObserverSuppressTextMessagesEnabled : public SmsObserverTest {
 public:
  void SetUp() override {
    SmsObserverTest::SetUp();
    histogram_tester_ = std::make_unique<base::HistogramTester>();
  }
  void ChangeUserSuppressionState(UserTextMessageSuppressionState state) {
    network_metadata_store()->SetUserTextMessageSuppressionState(kTestGuid,
                                                                 state);
  }

  void ChangePolicySuppressionState(PolicyTextMessageSuppressionState state) {
    std::string state_onc;
    switch (state) {
      case PolicyTextMessageSuppressionState::kUnset:
        state_onc = ::onc::cellular::kTextMessagesUnset;
        break;
      case PolicyTextMessageSuppressionState::kAllow:
        state_onc = ::onc::cellular::kTextMessagesAllow;
        break;
      case PolicyTextMessageSuppressionState::kSuppress:
        state_onc = ::onc::cellular::kTextMessagesSuppress;
        break;
    }

    base::Value::Dict global_config;
    global_config.Set(::onc::global_network_config::kAllowTextMessages,
                      state_onc);
    managed_network_configuration_handler()->SetPolicy(
        ::onc::ONC_SOURCE_DEVICE_POLICY, /*userhash=*/std::string(),
        base::Value::List(), global_config);
    base::RunLoop().RunUntilIdle();
  }

  void AssertHistogramCounts(size_t user_suppressed_count,
                             size_t policy_suppressed_count,
                             size_t not_suppressed_count) {
    histogram_tester_->ExpectBucketCount(
        CellularNetworkMetricsLogger::
            kAllowTextMessagesNotificationSuppressionState,
        CellularNetworkMetricsLogger::NotificationSuppressionState::
            kUserSuppressed,
        /*expected_count=*/user_suppressed_count);

    histogram_tester_->ExpectBucketCount(
        CellularNetworkMetricsLogger::
            kAllowTextMessagesNotificationSuppressionState,
        CellularNetworkMetricsLogger::NotificationSuppressionState::
            kPolicySuppressed,
        /*expected_count=*/policy_suppressed_count);

    histogram_tester_->ExpectBucketCount(
        CellularNetworkMetricsLogger::
            kAllowTextMessagesNotificationSuppressionState,
        CellularNetworkMetricsLogger::NotificationSuppressionState::
            kNotSuppressed,
        /*expected_count=*/not_suppressed_count);

    size_t total_count =
        user_suppressed_count + policy_suppressed_count + not_suppressed_count;
    histogram_tester_->ExpectTotalCount(
        CellularNetworkMetricsLogger::
            kAllowTextMessagesNotificationSuppressionState,
        /*expected_count=*/total_count);
  }

 private:
  std::unique_ptr<base::HistogramTester> histogram_tester_;
};

TEST_F(SmsObserverSuppressTextMessagesEnabled, SuccessGuardRailMetricsTest) {
  base::HistogramTester histogram_tester;

  AssertHistogramCounts(/*user_suppressed_count=*/0u,
                        /*policy_suppressed_count=*/0u,
                        /*not_suppressed_count=*/0u);
  ChangeUserSuppressionState(UserTextMessageSuppressionState::kAllow);
  ChangePolicySuppressionState(PolicyTextMessageSuppressionState::kUnset);
  SimulateMessageReceived();
  AssertHistogramCounts(/*user_suppressed_count=*/0u,
                        /*policy_suppressed_count=*/0u,
                        /*not_suppressed_count=*/1u);

  ChangeUserSuppressionState(UserTextMessageSuppressionState::kSuppress);
  ChangePolicySuppressionState(PolicyTextMessageSuppressionState::kUnset);
  SimulateMessageReceived();
  AssertHistogramCounts(/*user_suppressed_count=*/1u,
                        /*policy_suppressed_count=*/0u,
                        /*not_suppressed_count=*/1u);

  ChangeUserSuppressionState(UserTextMessageSuppressionState::kAllow);
  ChangePolicySuppressionState(PolicyTextMessageSuppressionState::kAllow);
  SimulateMessageReceived();
  AssertHistogramCounts(/*user_suppressed_count=*/1u,
                        /*policy_suppressed_count=*/0u,
                        /*not_suppressed_count=*/2u);

  ChangeUserSuppressionState(UserTextMessageSuppressionState::kSuppress);
  ChangePolicySuppressionState(PolicyTextMessageSuppressionState::kAllow);
  SimulateMessageReceived();
  AssertHistogramCounts(/*user_suppressed_count=*/1u,
                        /*policy_suppressed_count=*/0u,
                        /*not_suppressed_count=*/3u);

  ChangeUserSuppressionState(UserTextMessageSuppressionState::kSuppress);
  ChangePolicySuppressionState(PolicyTextMessageSuppressionState::kSuppress);
  SimulateMessageReceived();
  AssertHistogramCounts(/*user_suppressed_count=*/1u,
                        /*policy_suppressed_count=*/1u,
                        /*not_suppressed_count=*/3u);

  ChangeUserSuppressionState(UserTextMessageSuppressionState::kAllow);
  ChangePolicySuppressionState(PolicyTextMessageSuppressionState::kSuppress);
  SimulateMessageReceived();
  AssertHistogramCounts(/*user_suppressed_count=*/1u,
                        /*policy_suppressed_count=*/2u,
                        /*not_suppressed_count=*/3u);
}

}  // namespace ash