text: // Copyright 2017 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "chrome/browser/ash/tether/tether_service.h"
  
  #include <memory>
  
  #include "ash/constants/ash_features.h"
  #include "base/bind.h"
  #include "base/command_line.h"
  #include "base/memory/ptr_util.h"
  #include "base/run_loop.h"
  #include "base/test/metrics/histogram_tester.h"
  #include "base/test/scoped_feature_list.h"
  #include "base/test/task_environment.h"
  #include "base/timer/mock_timer.h"
  #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
  #include "chrome/browser/prefs/browser_prefs.h"
  #include "chrome/browser/ui/ash/network/tether_notification_presenter.h"
  #include "chrome/common/pref_names.h"
  #include "chrome/test/base/testing_browser_process.h"
  #include "chrome/test/base/testing_profile.h"
  #include "chromeos/components/multidevice/remote_device_test_util.h"
  #include "chromeos/components/multidevice/software_feature.h"
  #include "chromeos/components/tether/fake_notification_presenter.h"
  #include "chromeos/components/tether/fake_tether_component.h"
  #include "chromeos/components/tether/fake_tether_host_fetcher.h"
  #include "chromeos/components/tether/tether_component_impl.h"
  #include "chromeos/components/tether/tether_host_fetcher_impl.h"
  #include "chromeos/dbus/power/fake_power_manager_client.h"
  #include "chromeos/dbus/power/power_manager_client.h"
  #include "chromeos/dbus/power_manager/suspend.pb.h"
  #include "chromeos/dbus/shill/shill_device_client.h"
  #include "chromeos/dbus/shill/shill_manager_client.h"
  #include "chromeos/dbus/shill/shill_service_client.h"
  #include "chromeos/network/network_connect.h"
  #include "chromeos/network/network_handler.h"
  #include "chromeos/network/network_handler_test_helper.h"
  #include "chromeos/network/network_state_handler.h"
  #include "chromeos/network/network_type_pattern.h"
  #include "chromeos/services/device_sync/cryptauth_device_manager.h"
  #include "chromeos/services/device_sync/cryptauth_enroller.h"
  #include "chromeos/services/device_sync/cryptauth_enrollment_manager.h"
  #include "chromeos/services/device_sync/fake_cryptauth_enrollment_manager.h"
  #include "chromeos/services/device_sync/fake_remote_device_provider.h"
  #include "chromeos/services/device_sync/public/cpp/device_sync_client_impl.h"
  #include "chromeos/services/device_sync/public/cpp/fake_device_sync_client.h"
  #include "chromeos/services/device_sync/remote_device_provider_impl.h"
  #include "chromeos/services/multidevice_setup/public/cpp/fake_multidevice_setup_client.h"
  #include "chromeos/services/multidevice_setup/public/cpp/multidevice_setup_client_impl.h"
  #include "chromeos/services/multidevice_setup/public/cpp/prefs.h"
  #include "chromeos/services/secure_channel/public/cpp/client/fake_secure_channel_client.h"
  #include "chromeos/services/secure_channel/public/cpp/client/secure_channel_client_impl.h"
  #include "components/prefs/testing_pref_service.h"
  #include "components/sync_preferences/testing_pref_service_syncable.h"
  #include "components/user_manager/scoped_user_manager.h"
  #include "content/public/test/browser_task_environment.h"
  #include "device/bluetooth/bluetooth_adapter_factory.h"
  #include "device/bluetooth/test/mock_bluetooth_adapter.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"
  
  namespace ash {
  namespace tether {
  
  namespace {
  
  using ::testing::Invoke;
  using ::testing::NiceMock;
  
  const char kTestUserPrivateKey[] = "kTestUserPrivateKey";
  const size_t kNumTestDevices = 5;
  
  chromeos::multidevice::RemoteDeviceRefList CreateTestDevices() {
    chromeos::multidevice::RemoteDeviceRefList list;
    for (size_t i = 0; i < kNumTestDevices; ++i) {
      list.push_back(
          chromeos::multidevice::RemoteDeviceRefBuilder()
              .SetSupportsMobileHotspot(true)
              .SetSoftwareFeatureState(
                  chromeos::multidevice::SoftwareFeature::kBetterTogetherHost,
                  chromeos::multidevice::SoftwareFeatureState::kSupported)
              .Build());
    }
    return list;
  }
  
  class TestTetherService : public TetherService {
   public:
    TestTetherService(
        Profile* profile,
        chromeos::PowerManagerClient* power_manager_client,
        chromeos::device_sync::DeviceSyncClient* device_sync_client,
        chromeos::secure_channel::SecureChannelClient* secure_channel_client,
        chromeos::multidevice_setup::MultiDeviceSetupClient*
            multidevice_setup_client,
        chromeos::NetworkStateHandler* network_state_handler,
        session_manager::SessionManager* session_manager)
        : TetherService(profile,
                        power_manager_client,
                        device_sync_client,
                        secure_channel_client,
                        multidevice_setup_client,
                        network_state_handler,
                        session_manager) {}
    ~TestTetherService() override {}
  
    int updated_technology_state_count() {
      return updated_technology_state_count_;
    }
  
   protected:
    void UpdateTetherTechnologyState() override {
      updated_technology_state_count_++;
      TetherService::UpdateTetherTechnologyState();
    }
  
   private:
    int updated_technology_state_count_ = 0;
  };
  
  class FakeTetherComponentWithDestructorCallback
      : public chromeos::tether::FakeTetherComponent {
   public:
    FakeTetherComponentWithDestructorCallback(
        base::OnceClosure destructor_callback)
        : FakeTetherComponent(/*has_asynchronous_shutdown=*/false),
          destructor_callback_(std::move(destructor_callback)) {}
  
    ~FakeTetherComponentWithDestructorCallback() override {
      std::move(destructor_callback_).Run();
    }
  
   private:
    base::OnceClosure destructor_callback_;
  };
  
  class TestTetherComponentFactory final
      : public chromeos::tether::TetherComponentImpl::Factory {
   public:
    TestTetherComponentFactory() {}
  
    // Returns nullptr if no TetherComponent has been created or if the last one
    // that was created has already been deleted.
    FakeTetherComponentWithDestructorCallback* active_tether_component() {
      return active_tether_component_;
    }
  
    // chromeos::tether::TetherComponentImpl::Factory:
    std::unique_ptr<chromeos::tether::TetherComponent> CreateInstance(
        chromeos::device_sync::DeviceSyncClient* device_sync_client,
        chromeos::secure_channel::SecureChannelClient* secure_channel_client,
        chromeos::tether::TetherHostFetcher* tether_host_fetcher,
        chromeos::tether::NotificationPresenter* notification_presenter,
        chromeos::tether::GmsCoreNotificationsStateTrackerImpl*
            gms_core_notifications_state_tracker,
        PrefService* pref_service,
        chromeos::NetworkStateHandler* network_state_handler,
        chromeos::ManagedNetworkConfigurationHandler*
            managed_network_configuration_handler,
        chromeos::NetworkConnect* network_connect,
        chromeos::NetworkConnectionHandler* network_connection_handler,
        scoped_refptr<device::BluetoothAdapter> adapter,
        session_manager::SessionManager* session_manager) override {
      active_tether_component_ =
          new FakeTetherComponentWithDestructorCallback(base::BindOnce(
              &TestTetherComponentFactory::OnActiveTetherComponentDeleted,
              base::Unretained(this)));
      was_tether_component_active_ = true;
      return base::WrapUnique(active_tether_component_);
    }
  
    bool was_tether_component_active() { return was_tether_component_active_; }
  
    const chromeos::tether::TetherComponent::ShutdownReason&
    last_shutdown_reason() {
      return last_shutdown_reason_;
    }
  
   private:
    void OnActiveTetherComponentDeleted() {
      last_shutdown_reason_ = *active_tether_component_->last_shutdown_reason();
      active_tether_component_ = nullptr;
    }
  
    FakeTetherComponentWithDestructorCallback* active_tether_component_ = nullptr;
    bool was_tether_component_active_ = false;
    chromeos::tether::TetherComponent::ShutdownReason last_shutdown_reason_;
  };
  
  class FakeRemoteDeviceProviderFactory
      : public chromeos::device_sync::RemoteDeviceProviderImpl::Factory {
   public:
    FakeRemoteDeviceProviderFactory() = default;
    ~FakeRemoteDeviceProviderFactory() override = default;
  
    // chromeos::device_sync::RemoteDeviceProviderImpl::Factory:
    std::unique_ptr<chromeos::device_sync::RemoteDeviceProvider> CreateInstance(
        chromeos::device_sync::CryptAuthDeviceManager* device_manager,
        chromeos::device_sync::CryptAuthV2DeviceManager* v2_device_manager,
        const std::string& user_email,
        const std::string& user_private_key) override {
      return std::make_unique<chromeos::device_sync::FakeRemoteDeviceProvider>();
    }
  };
  
  class FakeTetherHostFetcherFactory
      : public chromeos::tether::TetherHostFetcherImpl::Factory {
   public:
    FakeTetherHostFetcherFactory(
        const chromeos::multidevice::RemoteDeviceRefList& initial_devices)
        : initial_devices_(initial_devices) {}
    virtual ~FakeTetherHostFetcherFactory() = default;
  
    chromeos::tether::FakeTetherHostFetcher* last_created() {
      return last_created_;
    }
  
    void SetNoInitialDevices() { initial_devices_.clear(); }
  
    // chromeos::tether::TetherHostFetcherImpl::Factory :
    std::unique_ptr<chromeos::tether::TetherHostFetcher> CreateInstance(
        chromeos::device_sync::DeviceSyncClient* device_sync_client,
        chromeos::multidevice_setup::MultiDeviceSetupClient*
            multidevice_setup_client) override {
      last_created_ =
          new chromeos::tether::FakeTetherHostFetcher(initial_devices_);
      return base::WrapUnique(last_created_);
    }
  
   private:
    chromeos::multidevice::RemoteDeviceRefList initial_devices_;
    chromeos::tether::FakeTetherHostFetcher* last_created_ = nullptr;
  };
  
  class FakeDeviceSyncClientImplFactory
      : public chromeos::device_sync::DeviceSyncClientImpl::Factory {
   public:
    FakeDeviceSyncClientImplFactory() = default;
  
    ~FakeDeviceSyncClientImplFactory() override = default;
  
    // chromeos::device_sync::DeviceSyncClientImpl::Factory:
    std::unique_ptr<chromeos::device_sync::DeviceSyncClient> CreateInstance()
        override {
      auto fake_device_sync_client =
          std::make_unique<chromeos::device_sync::FakeDeviceSyncClient>();
      fake_device_sync_client->NotifyReady();
      return fake_device_sync_client;
    }
  };
  
  class FakeSecureChannelClientImplFactory
      : public chromeos::secure_channel::SecureChannelClientImpl::Factory {
   public:
    FakeSecureChannelClientImplFactory() = default;
  
    ~FakeSecureChannelClientImplFactory() override = default;
  
    // chromeos::secure_channel::SecureChannelClientImpl::Factory:
    std::unique_ptr<chromeos::secure_channel::SecureChannelClient> CreateInstance(
        mojo::PendingRemote<chromeos::secure_channel::mojom::SecureChannel>
            channel,
        scoped_refptr<base::TaskRunner> task_runner) override {
      return std::make_unique<
          chromeos::secure_channel::FakeSecureChannelClient>();
    }
  };
  
  class FakeMultiDeviceSetupClientImplFactory
      : public chromeos::multidevice_setup::MultiDeviceSetupClientImpl::Factory {
   public:
    FakeMultiDeviceSetupClientImplFactory() = default;
  
    ~FakeMultiDeviceSetupClientImplFactory() override = default;
  
    // chromeos::multidevice_setup::MultiDeviceSetupClientImpl::Factory:
    std::unique_ptr<chromeos::multidevice_setup::MultiDeviceSetupClient>
    CreateInstance(
        mojo::PendingRemote<chromeos::multidevice_setup::mojom::MultiDeviceSetup>)
        override {
      auto fake_multidevice_setup_client = std::make_unique<
          chromeos::multidevice_setup::FakeMultiDeviceSetupClient>();
      fake_multidevice_setup_client_ = fake_multidevice_setup_client.get();
      return fake_multidevice_setup_client;
    }
  
    chromeos::multidevice_setup::FakeMultiDeviceSetupClient*
    fake_multidevice_setup_client() {
      return fake_multidevice_setup_client_;
    }
  
   private:
    chromeos::multidevice_setup::FakeMultiDeviceSetupClient*
        fake_multidevice_setup_client_;
  };
  
  }  // namespace
  
  class TetherServiceTest : public testing::Test {
   public:
    TetherServiceTest(const TetherServiceTest&) = delete;
    TetherServiceTest& operator=(const TetherServiceTest&) = delete;
  
   protected:
    TetherServiceTest() : test_devices_(CreateTestDevices()) {}
    ~TetherServiceTest() override {}
  
    void SetUp() override {
      fake_notification_presenter_ = nullptr;
      mock_timer_ = nullptr;
  
      chromeos::NetworkConnect::Initialize(nullptr);
  
      TestingProfile::Builder builder;
      profile_ = builder.Build();
  
      fake_chrome_user_manager_ = new FakeChromeUserManager();
      scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
          base::WrapUnique(fake_chrome_user_manager_));
  
      chromeos::PowerManagerClient::InitializeFake();
  
      fake_device_sync_client_ =
          std::make_unique<chromeos::device_sync::FakeDeviceSyncClient>();
      fake_device_sync_client_->NotifyReady();
  
      fake_device_sync_client_impl_factory_ =
          std::make_unique<FakeDeviceSyncClientImplFactory>();
      chromeos::device_sync::DeviceSyncClientImpl::Factory::SetFactoryForTesting(
          fake_device_sync_client_impl_factory_.get());
  
      fake_secure_channel_client_ =
          std::make_unique<chromeos::secure_channel::FakeSecureChannelClient>();
      fake_secure_channel_client_impl_factory_ =
          std::make_unique<FakeSecureChannelClientImplFactory>();
      chromeos::secure_channel::SecureChannelClientImpl::Factory::
          SetFactoryForTesting(fake_secure_channel_client_impl_factory_.get());
  
      fake_multidevice_setup_client_ = std::make_unique<
          chromeos::multidevice_setup::FakeMultiDeviceSetupClient>();
      fake_multidevice_setup_client_impl_factory_ =
          std::make_unique<FakeMultiDeviceSetupClientImplFactory>();
      chromeos::multidevice_setup::MultiDeviceSetupClientImpl::Factory::
          SetFactoryForTesting(fake_multidevice_setup_client_impl_factory_.get());
      initial_feature_state_ =
          chromeos::multidevice_setup::mojom::FeatureState::kEnabledByUser;
  
      fake_enrollment_manager_ = std::make_unique<
          chromeos::device_sync::FakeCryptAuthEnrollmentManager>();
      fake_enrollment_manager_->set_user_private_key(kTestUserPrivateKey);
  
      mock_adapter_ =
          base::MakeRefCounted<NiceMock<device::MockBluetoothAdapter>>();
      SetIsBluetoothPowered(true);
      is_adapter_present_ = true;
      ON_CALL(*mock_adapter_, IsPresent())
          .WillByDefault(Invoke(this, &TetherServiceTest::IsBluetoothPresent));
      ON_CALL(*mock_adapter_, IsPowered())
          .WillByDefault(Invoke(this, &TetherServiceTest::IsBluetoothPowered));
      device::BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter_);
  
      test_tether_component_factory_ =
          base::WrapUnique(new TestTetherComponentFactory());
      chromeos::tether::TetherComponentImpl::Factory::SetFactoryForTesting(
          test_tether_component_factory_.get());
      shutdown_reason_verified_ = false;
  
      fake_remote_device_provider_factory_ =
          base::WrapUnique(new FakeRemoteDeviceProviderFactory());
      chromeos::device_sync::RemoteDeviceProviderImpl::Factory::
          SetFactoryForTesting(fake_remote_device_provider_factory_.get());
  
      fake_tether_host_fetcher_factory_ =
          base::WrapUnique(new FakeTetherHostFetcherFactory(test_devices_));
      chromeos::tether::TetherHostFetcherImpl::Factory::SetFactoryForTesting(
          fake_tether_host_fetcher_factory_.get());
  
      TestingBrowserProcess::GetGlobal()->SetLocalState(&local_pref_service_);
      RegisterLocalState(local_pref_service_.registry());
    }
  
    void TearDown() override {
      TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr);
  
      chromeos::device_sync::DeviceSyncClientImpl::Factory::SetFactoryForTesting(
          nullptr);
      chromeos::secure_channel::SecureChannelClientImpl::Factory::
          SetFactoryForTesting(nullptr);
      chromeos::multidevice_setup::MultiDeviceSetupClientImpl::Factory::
          SetFactoryForTesting(nullptr);
  
      ShutdownTetherService();
  
      if (tether_service_) {
        // As of crbug.com/798605, SHUT_DOWN should not be logged since it does
        // not contribute meaningful data.
        histogram_tester_.ExpectBucketCount(
            "InstantTethering.FeatureState",
            TetherService::TetherFeatureState::SHUT_DOWN, 0 /* count */);
        tether_service_.reset();
      }
  
      EXPECT_EQ(test_tether_component_factory_->was_tether_component_active(),
                shutdown_reason_verified_);
  
      chromeos::PowerManagerClient::Shutdown();
      chromeos::NetworkConnect::Shutdown();
    }
  
    void SetPrimaryUserLoggedIn() {
      const AccountId account_id(
          AccountId::FromUserEmail(profile_->GetProfileUserName()));
      const user_manager::User* user =
          fake_chrome_user_manager_->AddPublicAccountUser(account_id);
      fake_chrome_user_manager_->UserLoggedIn(account_id, user->username_hash(),
                                              false /* browser_restart */,
                                              false /* is_child */);
    }
  
    void CreateTetherService() {
      fake_multidevice_setup_client_->SetFeatureState(
          chromeos::multidevice_setup::mojom::Feature::kInstantTethering,
          initial_feature_state_);
  
      tether_service_ = base::WrapUnique(new TestTetherService(
          profile_.get(), chromeos::FakePowerManagerClient::Get(),
          fake_device_sync_client_.get(), fake_secure_channel_client_.get(),
          fake_multidevice_setup_client_.get(), network_state_handler(),
          nullptr /* session_manager */));
  
      fake_notification_presenter_ =
          new chromeos::tether::FakeNotificationPresenter();
      mock_timer_ = new base::MockOneShotTimer();
      tether_service_->SetTestDoubles(
          base::WrapUnique(fake_notification_presenter_),
          base::WrapUnique(mock_timer_));
  
      SetPrimaryUserLoggedIn();
  
      // Ensure that TetherService does not prematurely update its
      // TechnologyState before it fetches the BluetoothAdapter.
      EXPECT_EQ(
          chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
          network_state_handler()->GetTechnologyState(
              chromeos::NetworkTypePattern::Tether()));
      VerifyTetherActiveStatus(false /* expected_active */);
  
      if (!fake_device_sync_client_->is_ready()) {
        return;
      }
  
      // Allow the posted task to fetch the BluetoothAdapter to finish.
      base::RunLoop().RunUntilIdle();
    }
  
    void ShutdownTetherService() {
      if (tether_service_)
        tether_service_->Shutdown();
    }
  
    void SetTetherTechnologyStateEnabled(bool enabled) {
      network_state_handler()->SetTetherTechnologyState(
          enabled
              ? chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED
              : chromeos::NetworkStateHandler::TechnologyState::
                    TECHNOLOGY_AVAILABLE);
    }
  
    void SetCellularTechnologyStateEnabled(bool enabled) {
      network_state_handler()->SetTechnologyEnabled(
          chromeos::NetworkTypePattern::Cellular(), enabled,
          chromeos::network_handler::ErrorCallback());
      base::RunLoop().RunUntilIdle();
    }
  
    void SetIsBluetoothPowered(bool powered) {
      is_adapter_powered_ = powered;
      for (auto& observer : mock_adapter_->GetObservers())
        observer.AdapterPoweredChanged(mock_adapter_.get(), powered);
    }
  
    void set_is_adapter_present(bool present) { is_adapter_present_ = present; }
  
    bool IsBluetoothPresent() { return is_adapter_present_; }
    bool IsBluetoothPowered() { return is_adapter_powered_; }
  
    void RemoveWifiFromSystem() {
      manager_test()->RemoveTechnology(shill::kTypeWifi);
      base::RunLoop().RunUntilIdle();
    }
  
    void DisconnectDefaultShillNetworks() {
      const chromeos::NetworkState* default_state;
      while ((default_state = network_state_handler()->DefaultNetwork())) {
        network_handler_test_helper_.service_test()->SetServiceProperty(
            default_state->path(), shill::kStateProperty,
            base::Value(shill::kStateIdle));
        base::RunLoop().RunUntilIdle();
      }
    }
  
    void VerifyTetherFeatureStateRecorded(
        TetherService::TetherFeatureState expected_technology_state_and_reason,
        int expected_count) {
      histogram_tester_.ExpectBucketCount("InstantTethering.FeatureState",
                                          expected_technology_state_and_reason,
                                          expected_count);
    }
  
    void VerifyTetherActiveStatus(bool expected_active) {
      EXPECT_EQ(
          expected_active,
          test_tether_component_factory_->active_tether_component() != nullptr);
    }
  
    void VerifyLastShutdownReason(
        const chromeos::tether::TetherComponent::ShutdownReason&
            expected_shutdown_reason) {
      EXPECT_EQ(expected_shutdown_reason,
                test_tether_component_factory_->last_shutdown_reason());
      shutdown_reason_verified_ = true;
    }
  
    chromeos::ShillManagerClient::TestInterface* manager_test() {
      return network_handler_test_helper_.manager_test();
    }
  
    chromeos::NetworkStateHandler* network_state_handler() {
      return chromeos::NetworkHandler::Get()->network_state_handler();
    }
  
    const chromeos::multidevice::RemoteDeviceRefList test_devices_;
    const content::BrowserTaskEnvironment task_environment_;
  
    chromeos::NetworkHandlerTestHelper network_handler_test_helper_;
    std::unique_ptr<TestingProfile> profile_;
    FakeChromeUserManager* fake_chrome_user_manager_;
    std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
    std::unique_ptr<sync_preferences::TestingPrefServiceSyncable>
        test_pref_service_;
    std::unique_ptr<TestTetherComponentFactory> test_tether_component_factory_;
    std::unique_ptr<FakeRemoteDeviceProviderFactory>
        fake_remote_device_provider_factory_;
    std::unique_ptr<FakeTetherHostFetcherFactory>
        fake_tether_host_fetcher_factory_;
    chromeos::tether::FakeNotificationPresenter* fake_notification_presenter_;
    base::MockOneShotTimer* mock_timer_;
    std::unique_ptr<chromeos::device_sync::FakeDeviceSyncClient>
        fake_device_sync_client_;
    std::unique_ptr<FakeDeviceSyncClientImplFactory>
        fake_device_sync_client_impl_factory_;
    std::unique_ptr<chromeos::secure_channel::FakeSecureChannelClient>
        fake_secure_channel_client_;
    std::unique_ptr<FakeSecureChannelClientImplFactory>
        fake_secure_channel_client_impl_factory_;
    std::unique_ptr<chromeos::multidevice_setup::FakeMultiDeviceSetupClient>
        fake_multidevice_setup_client_;
    std::unique_ptr<FakeMultiDeviceSetupClientImplFactory>
        fake_multidevice_setup_client_impl_factory_;
    std::unique_ptr<chromeos::device_sync::FakeCryptAuthEnrollmentManager>
        fake_enrollment_manager_;
  
    chromeos::multidevice_setup::mojom::FeatureState initial_feature_state_;
  
    scoped_refptr<device::MockBluetoothAdapter> mock_adapter_;
    bool is_adapter_present_;
    bool is_adapter_powered_;
    bool shutdown_reason_verified_;
  
    // PrefService which contains the browser process' local storage.
    TestingPrefServiceSimple local_pref_service_;
  
    std::unique_ptr<TestTetherService> tether_service_;
  
    base::HistogramTester histogram_tester_;
  };
  
  TEST_F(TetherServiceTest, TestShutdown) {
    CreateTetherService();
    VerifyTetherActiveStatus(true /* expected_active */);
  
    ShutdownTetherService();
  
    // The TechnologyState should not have changed due to Shutdown() being called.
    // If it had changed, any settings UI that was previously open would have
    // shown visual jank.
    EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
              network_state_handler()->GetTechnologyState(
                  chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(false /* expected_active */);
    VerifyLastShutdownReason(
        chromeos::tether::TetherComponent::ShutdownReason::USER_LOGGED_OUT);
  }
  
  // TODO(https://crbug.com/893878): Fix disabled test.
  TEST_F(TetherServiceTest, DISABLED_TestAsyncTetherShutdown) {
    CreateTetherService();
  
    // Tether should be ENABLED, and there should be no AsyncShutdownTask.
    EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
              network_state_handler()->GetTechnologyState(
                  chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(true /* expected_active */);
  
    // Use an asynchronous shutdown.
    test_tether_component_factory_->active_tether_component()
        ->set_has_asynchronous_shutdown(true);
  
    // Disable the Tether preference. This should trigger the asynchrnous
    // shutdown.
    SetTetherTechnologyStateEnabled(false);
  
    // Tether should be active, but shutting down.
    VerifyTetherActiveStatus(true /* expected_active */);
    EXPECT_EQ(
        chromeos::tether::TetherComponent::Status::SHUTTING_DOWN,
        test_tether_component_factory_->active_tether_component()->status());
  
    // Tether should be AVAILABLE.
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
  
    // Complete the shutdown process; TetherService should delete its
    // TetherComponent instance.
    test_tether_component_factory_->active_tether_component()
        ->FinishAsynchronousShutdown();
    VerifyTetherActiveStatus(false /* expected_active */);
    VerifyLastShutdownReason(
        chromeos::tether::TetherComponent::ShutdownReason::PREF_DISABLED);
  }
  
  TEST_F(TetherServiceTest, TestSuspend) {
    CreateTetherService();
    VerifyTetherActiveStatus(true /* expected_active */);
  
    chromeos::FakePowerManagerClient::Get()->SendSuspendImminent(
        power_manager::SuspendImminent_Reason_OTHER);
  
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(false /* expected_active */);
  
    chromeos::FakePowerManagerClient::Get()->SendSuspendDone();
  
    EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
              network_state_handler()->GetTechnologyState(
                  chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(true /* expected_active */);
  
    chromeos::FakePowerManagerClient::Get()->SendSuspendImminent(
        power_manager::SuspendImminent_Reason_OTHER);
  
    VerifyTetherFeatureStateRecorded(TetherService::TetherFeatureState::SUSPENDED,
                                     2 /* expected_count */);
    VerifyLastShutdownReason(
        chromeos::tether::TetherComponent::ShutdownReason::USER_CLOSED_LID);
  }
  
  TEST_F(TetherServiceTest, TestDeviceSyncClientNotReady) {
    fake_device_sync_client_ =
        std::make_unique<chromeos::device_sync::FakeDeviceSyncClient>();
  
    CreateTetherService();
  
    fake_device_sync_client_->NotifyReady();
    base::RunLoop().RunUntilIdle();
  
    EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
              network_state_handler()->GetTechnologyState(
                  chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(true /* expected_active */);
  
    ShutdownTetherService();
    VerifyLastShutdownReason(
        chromeos::tether::TetherComponent::ShutdownReason::USER_LOGGED_OUT);
  }
  
  TEST_F(TetherServiceTest,
         TestMultiDeviceSetupClientInitiallyHasNoVerifiedHost) {
    fake_tether_host_fetcher_factory_->SetNoInitialDevices();
    initial_feature_state_ = chromeos::multidevice_setup::mojom::FeatureState::
        kUnavailableNoVerifiedHost;
  
    CreateTetherService();
  
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(false /* expected_active */);
  
    fake_tether_host_fetcher_factory_->last_created()->set_tether_hosts(
        test_devices_);
    fake_multidevice_setup_client_->SetFeatureState(
        chromeos::multidevice_setup::mojom::Feature::kInstantTethering,
        chromeos::multidevice_setup::mojom::FeatureState::kEnabledByUser);
  
    EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
              network_state_handler()->GetTechnologyState(
                  chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(true /* expected_active */);
  
    ShutdownTetherService();
    VerifyLastShutdownReason(
        chromeos::tether::TetherComponent::ShutdownReason::USER_LOGGED_OUT);
  }
  
  TEST_F(TetherServiceTest, TestMultiDeviceSetupClientLosesVerifiedHost) {
    CreateTetherService();
  
    EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
              network_state_handler()->GetTechnologyState(
                  chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(true /* expected_active */);
  
    fake_tether_host_fetcher_factory_->last_created()->set_tether_hosts({});
    fake_multidevice_setup_client_->SetFeatureState(
        chromeos::multidevice_setup::mojom::Feature::kInstantTethering,
        chromeos::multidevice_setup::mojom::FeatureState::
            kUnavailableNoVerifiedHost);
  
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(false /* expected_active */);
  
    mock_timer_->Fire();
    ShutdownTetherService();
    VerifyTetherFeatureStateRecorded(
        TetherService::TetherFeatureState::NO_AVAILABLE_HOSTS,
        1 /* expected_count */);
    VerifyLastShutdownReason(chromeos::tether::TetherComponent::ShutdownReason::
                                 MULTIDEVICE_HOST_UNVERIFIED);
  }
  
  TEST_F(TetherServiceTest, TestBetterTogetherSuiteInitiallyDisabled) {
    initial_feature_state_ = chromeos::multidevice_setup::mojom::FeatureState::
        kUnavailableSuiteDisabled;
  
    CreateTetherService();
  
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(false /* expected_active */);
  
    fake_multidevice_setup_client_->SetFeatureState(
        chromeos::multidevice_setup::mojom::Feature::kInstantTethering,
        chromeos::multidevice_setup::mojom::FeatureState::kEnabledByUser);
  
    EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
              network_state_handler()->GetTechnologyState(
                  chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(true /* expected_active */);
  
    ShutdownTetherService();
    VerifyLastShutdownReason(
        chromeos::tether::TetherComponent::ShutdownReason::USER_LOGGED_OUT);
  }
  
  TEST_F(TetherServiceTest, TestBetterTogetherSuiteBecomesDisabled) {
    CreateTetherService();
  
    EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
              network_state_handler()->GetTechnologyState(
                  chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(true /* expected_active */);
  
    fake_multidevice_setup_client_->SetFeatureState(
        chromeos::multidevice_setup::mojom::Feature::kInstantTethering,
        chromeos::multidevice_setup::mojom::FeatureState::
            kUnavailableSuiteDisabled);
  
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(false /* expected_active */);
  
    ShutdownTetherService();
    VerifyTetherFeatureStateRecorded(
        TetherService::TetherFeatureState::BETTER_TOGETHER_SUITE_DISABLED,
        1 /* expected_count */);
    VerifyLastShutdownReason(chromeos::tether::TetherComponent::ShutdownReason::
                                 BETTER_TOGETHER_SUITE_DISABLED);
  }
  
  TEST_F(TetherServiceTest, TestGet_NotPrimaryUser_FeatureFlagDisabled) {
    EXPECT_FALSE(TetherService::Get(profile_.get()));
  }
  
  TEST_F(TetherServiceTest, TestGet_PrimaryUser_FeatureFlagDisabled) {
    SetPrimaryUserLoggedIn();
    EXPECT_FALSE(TetherService::Get(profile_.get()));
  }
  
  TEST_F(TetherServiceTest, TestGet_NotPrimaryUser_FeatureFlagEnabled) {
    base::test::ScopedFeatureList feature_list;
    feature_list.InitAndEnableFeature(chromeos::features::kInstantTethering);
  
    EXPECT_FALSE(TetherService::Get(profile_.get()));
  }
  
  // TODO(https://crbug.com/893878): Fix disabled test.
  TEST_F(TetherServiceTest, DISABLED_TestGet_PrimaryUser_FeatureFlagEnabled) {
    SetPrimaryUserLoggedIn();
  
    base::test::ScopedFeatureList feature_list;
    feature_list.InitWithFeatures(
        {chromeos::features::kInstantTethering} /* enabled_features */,
        {} /* disabled_features */);
  
    TetherService* tether_service = TetherService::Get(profile_.get());
    ASSERT_TRUE(tether_service);
  
    base::RunLoop().RunUntilIdle();
    tether_service->Shutdown();
  
    VerifyLastShutdownReason(
        chromeos::tether::TetherComponent::ShutdownReason::USER_LOGGED_OUT);
  }
  
  // TODO(https://crbug.com/893878): Fix disabled test.
  TEST_F(
      TetherServiceTest,
      DISABLED_TestGet_PrimaryUser_FeatureFlagEnabled_MultiDeviceApiFlagEnabled) {
    SetPrimaryUserLoggedIn();
  
    base::test::ScopedFeatureList feature_list;
    feature_list.InitWithFeatures(
        {chromeos::features::kInstantTethering} /* enabled_features */,
        {} /* disabled_features */);
  
    TetherService* tether_service = TetherService::Get(profile_.get());
    ASSERT_TRUE(tether_service);
  
    base::RunLoop().RunUntilIdle();
    tether_service->Shutdown();
  
    VerifyLastShutdownReason(
        chromeos::tether::TetherComponent::ShutdownReason::USER_LOGGED_OUT);
  }
  
  // TODO(https://crbug.com/893878): Fix disabled test.
  TEST_F(
      TetherServiceTest,
      DISABLED_TestGet_PrimaryUser_FeatureFlagEnabled_MultiDeviceApiAndMultiDeviceSetupFlagsEnabled) {
    SetPrimaryUserLoggedIn();
  
    base::test::ScopedFeatureList feature_list;
    feature_list.InitWithFeatures(
        {chromeos::features::kInstantTethering} /* enabled_features */,
        {} /* disabled_features */);
  
    TetherService* tether_service = TetherService::Get(profile_.get());
    ASSERT_TRUE(tether_service);
  
    fake_multidevice_setup_client_impl_factory_->fake_multidevice_setup_client()
        ->SetFeatureState(
            chromeos::multidevice_setup::mojom::Feature::kInstantTethering,
            chromeos::multidevice_setup::mojom::FeatureState::kEnabledByUser);
  
    base::RunLoop().RunUntilIdle();
    tether_service->Shutdown();
  
    VerifyLastShutdownReason(
        chromeos::tether::TetherComponent::ShutdownReason::USER_LOGGED_OUT);
  }
  
  TEST_F(TetherServiceTest, TestNoTetherHosts) {
    fake_tether_host_fetcher_factory_->SetNoInitialDevices();
    CreateTetherService();
  
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(false /* expected_active */);
  
    // Simulate this being the final state of Tether by passing time.
    mock_timer_->Fire();
  
    VerifyTetherFeatureStateRecorded(
        TetherService::TetherFeatureState::NO_AVAILABLE_HOSTS,
        1 /* expected_count */);
  }
  
  // TODO(https://crbug.com/893878): Fix disabled test.
  TEST_F(TetherServiceTest, DISABLED_TestProhibitedByPolicy) {
    profile_->GetPrefs()->SetBoolean(
        chromeos::multidevice_setup::kInstantTetheringAllowedPrefName, false);
  
    CreateTetherService();
  
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_PROHIBITED,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(false /* expected_active */);
  
    VerifyTetherFeatureStateRecorded(
        TetherService::TetherFeatureState::PROHIBITED, 1 /* expected_count */);
  }
  
  TEST_F(TetherServiceTest, TestBluetoothNotPresent) {
    set_is_adapter_present(false);
  
    CreateTetherService();
  
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(false /* expected_active */);
  
    // Simulate this being the final state of Tether by passing time.
    mock_timer_->Fire();
  
    VerifyTetherFeatureStateRecorded(
        TetherService::TetherFeatureState::BLE_NOT_PRESENT,
        1 /* expected_count */);
  }
  
  TEST_F(TetherServiceTest, TestMetricsFalsePositives) {
    set_is_adapter_present(false);
    fake_tether_host_fetcher_factory_->SetNoInitialDevices();
    CreateTetherService();
  
    set_is_adapter_present(true);
    SetIsBluetoothPowered(true);
  
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(false /* expected_active */);
  
    fake_tether_host_fetcher_factory_->last_created()->set_tether_hosts(
        test_devices_);
    fake_tether_host_fetcher_factory_->last_created()->NotifyTetherHostsUpdated();
  
    EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
              network_state_handler()->GetTechnologyState(
                  chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(true /* expected_active */);
  
    // No metric should have been recorded for BLE_NOT_PRESENT and
    // NO_AVAILABLE_HOSTS, but ENABLED should have been recorded.
    VerifyTetherFeatureStateRecorded(
        TetherService::TetherFeatureState::BLE_NOT_PRESENT,
        0 /* expected_count */);
    VerifyTetherFeatureStateRecorded(
        TetherService::TetherFeatureState::NO_AVAILABLE_HOSTS,
        0 /* expected_count */);
    VerifyTetherFeatureStateRecorded(TetherService::TetherFeatureState::ENABLED,
                                     1 /* expected_count */);
  
    // Ensure that the pending state recording has been canceled.
    ASSERT_FALSE(mock_timer_->IsRunning());
  
    ShutdownTetherService();
    VerifyLastShutdownReason(
        chromeos::tether::TetherComponent::ShutdownReason::USER_LOGGED_OUT);
  }
  
  TEST_F(TetherServiceTest, TestWifiNotPresent) {
    RemoveWifiFromSystem();
  
    CreateTetherService();
  
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
  
    VerifyTetherFeatureStateRecorded(
        TetherService::TetherFeatureState::WIFI_NOT_PRESENT,
        1 /* expected_count */);
  }
  
  TEST_F(TetherServiceTest, TestIsBluetoothPowered) {
    SetIsBluetoothPowered(false);
  
    CreateTetherService();
  
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(false /* expected_active */);
  
    SetIsBluetoothPowered(true);
  
    EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
              network_state_handler()->GetTechnologyState(
                  chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(true /* expected_active */);
  
    SetIsBluetoothPowered(false);
  
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(false /* expected_active */);
  
    VerifyTetherFeatureStateRecorded(
        TetherService::TetherFeatureState::BLUETOOTH_DISABLED,
        2 /* expected_count */);
    VerifyLastShutdownReason(
        chromeos::tether::TetherComponent::ShutdownReason::BLUETOOTH_DISABLED);
  }
  
  // TODO(https://crbug.com/893878): Fix disabled test.
  TEST_F(TetherServiceTest, DISABLED_TestCellularIsUnavailable) {
    manager_test()->RemoveTechnology(shill::kTypeCellular);
    ASSERT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Cellular()));
  
    CreateTetherService();
  
    SetTetherTechnologyStateEnabled(false);
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(false /* expected_active */);
    VerifyLastShutdownReason(
        chromeos::tether::TetherComponent::ShutdownReason::PREF_DISABLED);
  
    SetTetherTechnologyStateEnabled(true);
    EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
              network_state_handler()->GetTechnologyState(
                  chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(true /* expected_active */);
  
    VerifyTetherFeatureStateRecorded(TetherService::TetherFeatureState::ENABLED,
                                     2 /* expected_count */);
  }
  
  // TODO(https://crbug.com/893878): Fix disabled test.
  TEST_F(TetherServiceTest, DISABLED_TestCellularIsAvailable) {
    // TODO (lesliewatkins): Investigate why cellular needs to be removed and
    // re-added for NetworkStateHandler to return the correct TechnologyState.
    manager_test()->RemoveTechnology(shill::kTypeCellular);
    manager_test()->AddTechnology(shill::kTypeCellular, false);
  
    CreateTetherService();
  
    // Cellular disabled
    SetCellularTechnologyStateEnabled(false);
    ASSERT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Cellular()));
    VerifyTetherActiveStatus(false /* expected_active */);
  
    SetTetherTechnologyStateEnabled(false);
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(false /* expected_active */);
  
    SetTetherTechnologyStateEnabled(true);
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(false /* expected_active */);
  
    // Cellular enabled
    SetCellularTechnologyStateEnabled(true);
    ASSERT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
              network_state_handler()->GetTechnologyState(
                  chromeos::NetworkTypePattern::Cellular()));
    VerifyTetherActiveStatus(true /* expected_active */);
  
    SetTetherTechnologyStateEnabled(false);
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(false /* expected_active */);
  
    SetTetherTechnologyStateEnabled(true);
    EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
              network_state_handler()->GetTechnologyState(
                  chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(true /* expected_active */);
  
    SetCellularTechnologyStateEnabled(false);
  
    VerifyTetherFeatureStateRecorded(
        TetherService::TetherFeatureState::CELLULAR_DISABLED,
        2 /* expected_count */);
    VerifyLastShutdownReason(
        chromeos::tether::TetherComponent::ShutdownReason::CELLULAR_DISABLED);
  }
  
  // TODO(https://crbug.com/893878): Fix disabled test.
  TEST_F(TetherServiceTest, DISABLED_TestDisabled) {
    profile_->GetPrefs()->SetBoolean(
        chromeos::multidevice_setup::kInstantTetheringEnabledPrefName, false);
  
    CreateTetherService();
  
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
    EXPECT_FALSE(profile_->GetPrefs()->GetBoolean(
        chromeos::multidevice_setup::kInstantTetheringEnabledPrefName));
    VerifyTetherActiveStatus(false /* expected_active */);
  
    VerifyTetherFeatureStateRecorded(
        TetherService::TetherFeatureState::USER_PREFERENCE_DISABLED,
        1 /* expected_count */);
  }
  
  // TODO(https://crbug.com/893878): Fix disabled test.
  TEST_F(TetherServiceTest, DISABLED_TestEnabled) {
    CreateTetherService();
  
    EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
              network_state_handler()->GetTechnologyState(
                  chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(true /* expected_active */);
  
    SetTetherTechnologyStateEnabled(false);
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
    EXPECT_FALSE(profile_->GetPrefs()->GetBoolean(
        chromeos::multidevice_setup::kInstantTetheringEnabledPrefName));
    VerifyTetherActiveStatus(false /* expected_active */);
    histogram_tester_.ExpectBucketCount(
        "InstantTethering.UserPreference.OnToggle", false,
        1u /* expected_count */);
  
    SetTetherTechnologyStateEnabled(true);
    EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
              network_state_handler()->GetTechnologyState(
                  chromeos::NetworkTypePattern::Tether()));
    EXPECT_TRUE(profile_->GetPrefs()->GetBoolean(
        chromeos::multidevice_setup::kInstantTetheringEnabledPrefName));
    VerifyTetherActiveStatus(true /* expected_active */);
    histogram_tester_.ExpectBucketCount(
        "InstantTethering.UserPreference.OnToggle", true,
        1u /* expected_count */);
  
    VerifyTetherFeatureStateRecorded(TetherService::TetherFeatureState::ENABLED,
                                     2 /* expected_count */);
    VerifyLastShutdownReason(
        chromeos::tether::TetherComponent::ShutdownReason::PREF_DISABLED);
  }
  
  TEST_F(TetherServiceTest, TestUserPrefChangesViaFeatureStateChange) {
    // Start with the feature disabled.
    initial_feature_state_ =
        chromeos::multidevice_setup::mojom::FeatureState::kDisabledByUser;
    profile_->GetPrefs()->SetBoolean(
        chromeos::multidevice_setup::kInstantTetheringEnabledPrefName, false);
    CreateTetherService();
  
    // Enable the feature.
    profile_->GetPrefs()->SetBoolean(
        chromeos::multidevice_setup::kInstantTetheringEnabledPrefName, true);
    fake_multidevice_setup_client_->SetFeatureState(
        chromeos::multidevice_setup::mojom::Feature::kInstantTethering,
        chromeos::multidevice_setup::mojom::FeatureState::kEnabledByUser);
    EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
              network_state_handler()->GetTechnologyState(
                  chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(true /* expected_active */);
    VerifyTetherFeatureStateRecorded(TetherService::TetherFeatureState::ENABLED,
                                     1 /* expected_count */);
    histogram_tester_.ExpectBucketCount(
        "InstantTethering.UserPreference.OnToggle", true,
        1u /* expected_count */);
  
    // Disable the feature.
    profile_->GetPrefs()->SetBoolean(
        chromeos::multidevice_setup::kInstantTetheringEnabledPrefName, false);
    fake_multidevice_setup_client_->SetFeatureState(
        chromeos::multidevice_setup::mojom::Feature::kInstantTethering,
        chromeos::multidevice_setup::mojom::FeatureState::kDisabledByUser);
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(false /* expected_active */);
    VerifyTetherFeatureStateRecorded(
        TetherService::TetherFeatureState::USER_PREFERENCE_DISABLED,
        2 /* expected_count */);
    histogram_tester_.ExpectBucketCount(
        "InstantTethering.UserPreference.OnToggle", false,
        1u /* expected_count */);
  
    // Enable the feature.
    profile_->GetPrefs()->SetBoolean(
        chromeos::multidevice_setup::kInstantTetheringEnabledPrefName, true);
    fake_multidevice_setup_client_->SetFeatureState(
        chromeos::multidevice_setup::mojom::Feature::kInstantTethering,
        chromeos::multidevice_setup::mojom::FeatureState::kEnabledByUser);
    EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
              network_state_handler()->GetTechnologyState(
                  chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(true /* expected_active */);
    VerifyTetherFeatureStateRecorded(TetherService::TetherFeatureState::ENABLED,
                                     2 /* expected_count */);
    histogram_tester_.ExpectBucketCount(
        "InstantTethering.UserPreference.OnToggle", true,
        2u /* expected_count */);
  
    VerifyLastShutdownReason(
        chromeos::tether::TetherComponent::ShutdownReason::PREF_DISABLED);
  }
  
  TEST_F(TetherServiceTest, TestUserPrefChangesViaTechnologyStateChange) {
    CreateTetherService();
  
    EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
              network_state_handler()->GetTechnologyState(
                  chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(true /* expected_active */);
  
    SetTetherTechnologyStateEnabled(false);
    fake_multidevice_setup_client_->InvokePendingSetFeatureEnabledStateCallback(
        chromeos::multidevice_setup::mojom::Feature::kInstantTethering,
        false /* expected_enabled */, absl::nullopt /* expected_auth_token */,
        true /* success */);
    profile_->GetPrefs()->SetBoolean(
        chromeos::multidevice_setup::kInstantTetheringEnabledPrefName, false);
    fake_multidevice_setup_client_->SetFeatureState(
        chromeos::multidevice_setup::mojom::Feature::kInstantTethering,
        chromeos::multidevice_setup::mojom::FeatureState::kDisabledByUser);
    EXPECT_EQ(
        chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
        network_state_handler()->GetTechnologyState(
            chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(false /* expected_active */);
    histogram_tester_.ExpectBucketCount(
        "InstantTethering.UserPreference.OnToggle", false,
        1u /* expected_count */);
  
    SetTetherTechnologyStateEnabled(true);
    fake_multidevice_setup_client_->InvokePendingSetFeatureEnabledStateCallback(
        chromeos::multidevice_setup::mojom::Feature::kInstantTethering,
        true /* expected_enabled */, absl::nullopt /* expected_auth_token */,
        false /* success */);
    profile_->GetPrefs()->SetBoolean(
        chromeos::multidevice_setup::kInstantTetheringEnabledPrefName, true);
    fake_multidevice_setup_client_->SetFeatureState(
        chromeos::multidevice_setup::mojom::Feature::kInstantTethering,
        chromeos::multidevice_setup::mojom::FeatureState::kEnabledByUser);
    EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
              network_state_handler()->GetTechnologyState(
                  chromeos::NetworkTypePattern::Tether()));
    VerifyTetherActiveStatus(true /* expected_active */);
    histogram_tester_.ExpectBucketCount(
        "InstantTethering.UserPreference.OnToggle", true,
        1u /* expected_count */);
  
    VerifyTetherFeatureStateRecorded(TetherService::TetherFeatureState::ENABLED,
                                     2 /* expected_count */);
    VerifyLastShutdownReason(
        chromeos::tether::TetherComponent::ShutdownReason::PREF_DISABLED);
  }
  
  // TODO(https://crbug.com/893878): Fix disabled test.
  // Test against a past defect that made TetherService and NetworkStateHandler
  // repeatly update technology state after the other did so. TetherService should
  // only update technology state if NetworkStateHandler has provided a different
  // state than the user preference.
  TEST_F(TetherServiceTest, DISABLED_TestEnabledMultipleChanges) {
    CreateTetherService();
  
    // CreateTetherService calls RunUntilIdle() so UpdateTetherTechnologyState()
    // may be called multiple times in the initialization process.
    int updated_technology_state_count =
        tether_service_->updated_technology_state_count();
  
    SetTetherTechnologyStateEnabled(false);
    SetTetherTechnologyStateEnabled(false);
    SetTetherTechnologyStateEnabled(false);
  
    updated_technology_state_count++;
    EXPECT_EQ(updated_technology_state_count,
              tether_service_->updated_technology_state_count());
  
    SetTetherTechnologyStateEnabled(true);
    SetTetherTechnologyStateEnabled(true);
    SetTetherTechnologyStateEnabled(true);
  
    updated_technology_state_count++;
    EXPECT_EQ(updated_technology_state_count,
              tether_service_->updated_technology_state_count());
  
    VerifyLastShutdownReason(
        chromeos::tether::TetherComponent::ShutdownReason::PREF_DISABLED);
  }
  
  }  // namespace tether
  }  // namespace ash
  