chromium/chrome/browser/ash/device_name/device_name_applier_impl_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 "chrome/browser/ash/device_name/device_name_applier_impl.h"

#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "chromeos/ash/components/network/network_state_test_helper.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace ash {

namespace {
using ::testing::_;
}  // namespace

class DeviceNameApplierImplTest : public testing::Test {
 public:
  DeviceNameApplierImplTest() {
    applier_ = base::WrapUnique(
        new DeviceNameApplierImpl(helper_.network_state_handler()));
  }

  ~DeviceNameApplierImplTest() override = default;

  // testing::Test
  void SetUp() override {
    device::BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter_);

    ON_CALL(*mock_adapter_, SetName(_, _, _))
        .WillByDefault(testing::Invoke(
            [this](const std::string& name, base::OnceClosure success_callback,
                   base::OnceClosure error_callback) {
              device_name_ = name;
              set_name_success_callback_ = std::move(success_callback);
              set_name_error_callback_ = std::move(error_callback);
            }));

    ON_CALL(*mock_adapter_, GetName()).WillByDefault(testing::Invoke([this]() {
      return device_name_;
    }));
  }

  base::TimeDelta GetCurrentBackoffDelay() {
    return applier_->retry_backoff_.GetTimeUntilRelease();
  }

  int GetBackoffFailureCount() {
    return applier_->retry_backoff_.failure_count();
  }

  void VerifyNameInBluetoothAdapterAndNetworkStateHandler(
      const std::string& expected_device_name) {
    EXPECT_EQ(expected_device_name,
              helper_.network_state_handler()->hostname());
    EXPECT_EQ(expected_device_name, mock_adapter_->GetName());
  }

 protected:
  std::unique_ptr<DeviceNameApplierImpl> applier_;
  base::test::TaskEnvironment task_environment_{
      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
  scoped_refptr<::testing::NiceMock<device::MockBluetoothAdapter>>
      mock_adapter_ = base::MakeRefCounted<
          ::testing::NiceMock<device::MockBluetoothAdapter>>();
  base::OnceClosure set_name_success_callback_;
  base::OnceClosure set_name_error_callback_;

 private:
  NetworkStateTestHelper helper_{/*use_default_devices_and_services=*/true};
  std::string device_name_;
};

TEST_F(DeviceNameApplierImplTest, SuccessfullySetNameOnFirstAttempt) {
  applier_->SetDeviceName("TestName");
  base::RunLoop().RunUntilIdle();

  // Call success callback and confirm that that backoff received no error.
  std::move(set_name_success_callback_).Run();
  EXPECT_EQ(0, GetBackoffFailureCount());
  VerifyNameInBluetoothAdapterAndNetworkStateHandler("TestName");
}

TEST_F(DeviceNameApplierImplTest, SuccessfullySetNameAfterMultipleAttempts) {
  applier_->SetDeviceName("TestName");
  base::RunLoop().RunUntilIdle();

  // Call error callback and confirm that backoff received the error.
  std::move(set_name_error_callback_).Run();
  EXPECT_EQ(1, GetBackoffFailureCount());

  // Fast forward in time to next backoff retry and confirm another call is made
  // to SetName, and call error callback again.
  EXPECT_CALL(*mock_adapter_, SetName("TestName", _, _)).Times(1);
  task_environment_.FastForwardBy(GetCurrentBackoffDelay());
  std::move(set_name_error_callback_).Run();
  EXPECT_EQ(2, GetBackoffFailureCount());

  // Fast forward in time to next backoff retry and confirm another call is made
  // to SetName, and call success callback. Failure count should decrement by 1.
  EXPECT_CALL(*mock_adapter_, SetName("TestName", _, _)).Times(1);
  task_environment_.FastForwardBy(GetCurrentBackoffDelay());
  std::move(set_name_success_callback_).Run();
  EXPECT_EQ(1, GetBackoffFailureCount());
  VerifyNameInBluetoothAdapterAndNetworkStateHandler("TestName");

  // No more retry calls are made once success callback is called.
  EXPECT_CALL(*mock_adapter_, SetName("TestName", _, _)).Times(0);
  task_environment_.FastForwardBy(base::Hours(1));
}

TEST_F(DeviceNameApplierImplTest, SetNameDelayNotReached) {
  applier_->SetDeviceName("TestName");
  base::RunLoop().RunUntilIdle();

  // Call error callback and confirm that backoff received the error.
  std::move(set_name_error_callback_).Run();
  EXPECT_EQ(1, GetBackoffFailureCount());

  // SetName should not be called before next backoff retry time.
  EXPECT_CALL(*mock_adapter_, SetName("TestName", _, _)).Times(0);
  task_environment_.FastForwardBy(GetCurrentBackoffDelay() -
                                  base::Milliseconds(1));
}

TEST_F(DeviceNameApplierImplTest, MultipleCallsToSetDeviceName) {
  // Make first call to set device name and call error callback.
  applier_->SetDeviceName("TestName1");
  base::RunLoop().RunUntilIdle();
  std::move(set_name_error_callback_).Run();
  EXPECT_EQ(1, GetBackoffFailureCount());

  // Second call to SetDeviceName should clear pending attempts from previous
  // call.
  applier_->SetDeviceName("TestName2");
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(0, GetBackoffFailureCount());

  // Call success callback and make sure the name set is the one from the most
  // recent call.
  std::move(set_name_success_callback_).Run();
  EXPECT_EQ(0, GetBackoffFailureCount());
  VerifyNameInBluetoothAdapterAndNetworkStateHandler("TestName2");
}

}  // namespace ash