chromium/ash/system/network/cellular_setup_notifier_unittest.cc

// Copyright 2021 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/cellular_setup_notifier.h"

#include "ash/constants/ash_pref_names.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/system/system_notification_controller.h"
#include "ash/test/ash_test_base.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/test/task_environment.h"
#include "chromeos/ash/components/dbus/hermes/hermes_clients.h"
#include "chromeos/ash/components/dbus/shill/shill_clients.h"
#include "chromeos/ash/components/network/network_cert_loader.h"
#include "chromeos/ash/components/network/network_handler.h"
#include "chromeos/ash/components/network/system_token_cert_db_storage.h"
#include "chromeos/ash/services/network_config/public/cpp/cros_network_config_test_helper.h"
#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
#include "components/prefs/pref_service.h"
#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/public/cpp/notification.h"

namespace ash {

namespace {

constexpr char kShillManagerClientStubCellularDevice[] =
    "/device/stub_cellular_device";
constexpr char kShillManagerClientStubCellularDeviceName[] =
    "stub_cellular_device";
constexpr char kCellularNetworkWithActivationState[] = R"(
{
  "GUID": "cellular_guid",
  "Type": "cellular",
  "Technology": "LTE",
  "State": "idle",
  "Cellular.ActivationState": "%s"
})";

// Delay after OOBE when the notification is expected to be shown.
constexpr base::TimeDelta kNotificationDelay = base::Minutes(15);

}  // namespace

class CellularSetupNotifierTest : public NoSessionAshTestBase {
 protected:
  CellularSetupNotifierTest()
      : NoSessionAshTestBase(
            base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
  CellularSetupNotifierTest(const CellularSetupNotifierTest&) = delete;
  CellularSetupNotifierTest& operator=(const CellularSetupNotifierTest&) =
      delete;
  ~CellularSetupNotifierTest() override = default;

  void SetUp() override {
    SystemTokenCertDbStorage::Initialize();
    NetworkCertLoader::Initialize();
    shill_clients::InitializeFakes();
    hermes_clients::InitializeFakes();
    NetworkHandler::Initialize();
    network_config_helper_ =
        std::make_unique<network_config::CrosNetworkConfigTestHelper>();

    AshTestBase::SetUp();
  }

  void TearDown() override {
    AshTestBase::TearDown();
    network_config_helper_.reset();
    NetworkHandler::Shutdown();
    hermes_clients::Shutdown();
    shill_clients::Shutdown();
    NetworkCertLoader::Shutdown();
    SystemTokenCertDbStorage::Shutdown();
  }

  void AddCellularDevice() {
    network_config_helper_->network_state_helper().AddDevice(
        kShillManagerClientStubCellularDevice, shill::kTypeCellular,
        kShillManagerClientStubCellularDeviceName);
    base::RunLoop().RunUntilIdle();
  }

  std::string ConfigureCellularService(bool activated) {
    const std::string path =
        network_config_helper_->network_state_helper().ConfigureService(
            base::StringPrintf(kCellularNetworkWithActivationState,
                               activated
                                   ? shill::kActivationStateActivated
                                   : shill::kActivationStateNotActivated));
    base::RunLoop().RunUntilIdle();
    return path;
  }

  void ActivateCellularService(const std::string& path) {
    network_config_helper_->network_state_helper().SetServiceProperty(
        path, shill::kActivationStateProperty,
        base::Value(shill::kActivationStateActivated));
    base::RunLoop().RunUntilIdle();
  }

  // Returns whether the cellular setup notification is shown.
  bool IsNotificationShown() {
    return message_center::MessageCenter::Get()->FindVisibleNotificationById(
        CellularSetupNotifier::kCellularSetupNotificationId);
  }

  void LogIn() {
    SimulateUserLogin("[email protected]");
    base::RunLoop().RunUntilIdle();
  }

  void LogOut() {
    // Remove the notification if it is shown.
    message_center::MessageCenter::Get()->RemoveNotification(
        CellularSetupNotifier::kCellularSetupNotificationId, false);
    ClearLogin();
    base::RunLoop().RunUntilIdle();
  }

  void FastForwardNotificationDelay() {
    task_environment()->FastForwardBy(kNotificationDelay);
    base::RunLoop().RunUntilIdle();
  }

  // Returns the pref that indicates whether the notification is able to be
  // shown; the value will be |false| if the notification has already been
  // shown, or if we should otherwise not show the notification.
  bool GetCanCellularSetupNotificationBeShown() {
    PrefService* prefs =
        Shell::Get()->session_controller()->GetLastActiveUserPrefService();
    if (!prefs) {
      return false;
    }
    return prefs->GetBoolean(prefs::kCanCellularSetupNotificationBeShown);
  }

  void SetCanCellularSetupNotificationBeShown(bool value) {
    PrefService* prefs =
        Shell::Get()->session_controller()->GetLastActiveUserPrefService();
    prefs->SetBoolean(prefs::kCanCellularSetupNotificationBeShown, value);
  }

 private:
  std::unique_ptr<network_config::CrosNetworkConfigTestHelper>
      network_config_helper_;
};

TEST_F(CellularSetupNotifierTest, DontShowNotificationUnfinishedOOBE) {
  FastForwardNotificationDelay();
  EXPECT_FALSE(IsNotificationShown());
}

TEST_F(CellularSetupNotifierTest, ShowNotificationZeroUnactivatedNetworks) {
  AddCellularDevice();

  LogIn();
  FastForwardNotificationDelay();

  EXPECT_TRUE(IsNotificationShown());
  EXPECT_FALSE(GetCanCellularSetupNotificationBeShown());
}

TEST_F(CellularSetupNotifierTest, ShowNotificationOneUnactivatedNetwork) {
  AddCellularDevice();
  ConfigureCellularService(/*activated=*/false);

  LogIn();
  FastForwardNotificationDelay();

  EXPECT_TRUE(IsNotificationShown());
  EXPECT_FALSE(GetCanCellularSetupNotificationBeShown());
}

TEST_F(CellularSetupNotifierTest, ShowNotificationTwoUnactivatedNetworks) {
  AddCellularDevice();
  ConfigureCellularService(/*activated=*/false);
  ConfigureCellularService(/*activated=*/false);

  LogIn();
  FastForwardNotificationDelay();

  EXPECT_TRUE(IsNotificationShown());
  EXPECT_FALSE(GetCanCellularSetupNotificationBeShown());
}

TEST_F(CellularSetupNotifierTest, DontShowNotificationActivatedNetwork) {
  AddCellularDevice();
  const std::string& cellular_path =
      ConfigureCellularService(/*activated=*/true);

  LogIn();
  FastForwardNotificationDelay();

  EXPECT_FALSE(IsNotificationShown());
  EXPECT_FALSE(GetCanCellularSetupNotificationBeShown());
}

TEST_F(CellularSetupNotifierTest, LogOutBeforeNotificationShowsThenLogInAgain) {
  AddCellularDevice();

  LogIn();
  task_environment()->FastForwardBy(kNotificationDelay - base::Minutes(1));
  base::RunLoop().RunUntilIdle();
  EXPECT_TRUE(GetCanCellularSetupNotificationBeShown());

  LogOut();
  FastForwardNotificationDelay();
  EXPECT_FALSE(GetCanCellularSetupNotificationBeShown());

  LogIn();
  FastForwardNotificationDelay();

  EXPECT_TRUE(IsNotificationShown());
  EXPECT_FALSE(GetCanCellularSetupNotificationBeShown());
}

TEST_F(CellularSetupNotifierTest, LogInAgainAfterShowingNotification) {
  AddCellularDevice();

  LogIn();
  FastForwardNotificationDelay();

  EXPECT_TRUE(IsNotificationShown());
  EXPECT_FALSE(GetCanCellularSetupNotificationBeShown());

  LogOut();
  LogIn();

  // Check that even without a delay we correctly identify that a notification
  // was already shown.
  EXPECT_FALSE(GetCanCellularSetupNotificationBeShown());
  FastForwardNotificationDelay();
  EXPECT_FALSE(IsNotificationShown());
}

TEST_F(CellularSetupNotifierTest, LogInAgainAfterCheckingNonCellularDevice) {
  // Perform the logic twice to check that even after logging out and back in
  // the notification is not shown if there is no cellular device.
  for (int i = 0; i < 2; ++i) {
    LogIn();
    FastForwardNotificationDelay();

    EXPECT_FALSE(IsNotificationShown());
    EXPECT_TRUE(GetCanCellularSetupNotificationBeShown());

    LogOut();
  }
}

TEST_F(CellularSetupNotifierTest,
       NotificationStillShownAfterLatentCellularDevice) {
  LogIn();
  FastForwardNotificationDelay();

  EXPECT_FALSE(IsNotificationShown());
  EXPECT_TRUE(GetCanCellularSetupNotificationBeShown());

  AddCellularDevice();
  FastForwardNotificationDelay();

  EXPECT_TRUE(IsNotificationShown());
  EXPECT_FALSE(GetCanCellularSetupNotificationBeShown());
}

TEST_F(CellularSetupNotifierTest,
       RemoveNotificationAfterAddingActivatedNetwork) {
  AddCellularDevice();

  LogIn();
  FastForwardNotificationDelay();

  EXPECT_TRUE(IsNotificationShown());
  EXPECT_FALSE(GetCanCellularSetupNotificationBeShown());

  const std::string& cellular_path =
      ConfigureCellularService(/*activated=*/true);

  EXPECT_FALSE(IsNotificationShown());
}

TEST_F(CellularSetupNotifierTest,
       RemoveNotificationAfterExistingNetworkBecomesActivated) {
  AddCellularDevice();

  LogIn();
  FastForwardNotificationDelay();

  EXPECT_TRUE(IsNotificationShown());
  EXPECT_FALSE(GetCanCellularSetupNotificationBeShown());

  const std::string& cellular_path =
      ConfigureCellularService(/*activated=*/false);

  // Notification is not removed after adding unactivated network.
  EXPECT_TRUE(IsNotificationShown());

  ActivateCellularService(cellular_path);
  EXPECT_FALSE(IsNotificationShown());
}

}  // namespace ash