chromium/chrome/services/sharing/nearby/platform/ble_v2_server_socket_unittest.cc

// Copyright 2024 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/services/sharing/nearby/platform/ble_v2_server_socket.h"

#include "base/task/thread_pool.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/services/sharing/nearby/platform/count_down_latch.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace nearby {
namespace chrome {

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

  void SetUp() override {
    ble_v2_socket_ = std::make_unique<BleV2Socket>();
    ble_v2_server_socket_ = std::make_unique<BleV2ServerSocket>();

    accept_socket_task_runner_ = base::ThreadPool::CreateSingleThreadTaskRunner(
        {base::MayBlock()}, base::SingleThreadTaskRunnerThreadMode::DEDICATED);

    close_socket_task_runner_ = base::ThreadPool::CreateSingleThreadTaskRunner(
        {base::MayBlock()}, base::SingleThreadTaskRunnerThreadMode::DEDICATED);
  }

  void ServerSocketAccept(base::RunLoop& run_loop, CountDownLatch& latch) {
    accept_socket_task_runner_->PostTask(
        FROM_HERE, base::BindLambdaForTesting([&] {
          base::ScopedAllowBaseSyncPrimitivesForTesting allow_wait;
          // Accept always returns a nullptr. Expect this to block.
          EXPECT_EQ(nullptr, ble_v2_server_socket_->Accept());

          // Decrement the latch after Accept exits.
          latch.CountDown();
          run_loop.Quit();
        }));
  }

  void PostDelayedServerSocketClose() {
    close_socket_task_runner_->PostDelayedTask(
        FROM_HERE, base::BindLambdaForTesting([&] {
          base::ScopedAllowBaseSyncPrimitivesForTesting allow_wait;
          EXPECT_TRUE(ble_v2_server_socket_->Close().Ok());
        }),
        base::Seconds(1));
  }

 protected:
  scoped_refptr<base::SingleThreadTaskRunner> accept_socket_task_runner_;
  scoped_refptr<base::SingleThreadTaskRunner> close_socket_task_runner_;
  std::unique_ptr<BleV2Socket> ble_v2_socket_;
  std::unique_ptr<BleV2ServerSocket> ble_v2_server_socket_;

 private:
  base::test::TaskEnvironment task_environment_;
};

TEST_F(BleV2ServerSocketTest, ServerSocket_AcceptAndClose) {
  // Calls Close() after 1s.
  PostDelayedServerSocketClose();

  // Server Socket's Accept is designed to wait forever until
  // Close is called, as the calling thread in Nearby Connections
  // calls accept in a while true loop that can cause crashes
  // and out-of-memory errors otherwise. This mimics what a true
  // implementation would do, which is block until a Bluetooth
  // connection is ready for socket creation.
  CountDownLatch accept_latch(1);
  base::RunLoop run_loop;
  ServerSocketAccept(run_loop, accept_latch);
  run_loop.Run();

  // Ensure Accept exits without error, after Close is called.
  EXPECT_TRUE(accept_latch.Await().Ok());
}

TEST_F(BleV2ServerSocketTest, ServerSocket_MultipleAcceptAndClose) {
  // Calling Close multiple times should cause no errors.
  PostDelayedServerSocketClose();
  PostDelayedServerSocketClose();
  PostDelayedServerSocketClose();

  // Calling Accept multiple times should cause no errors.
  CountDownLatch accept_latch(3);
  base::RunLoop run_loop_1;
  ServerSocketAccept(run_loop_1, accept_latch);
  run_loop_1.Run();

  base::RunLoop run_loop_2;
  ServerSocketAccept(run_loop_2, accept_latch);
  run_loop_2.Run();

  base::RunLoop run_loop_3;
  ServerSocketAccept(run_loop_3, accept_latch);
  run_loop_3.Run();

  // Ensure all Accept tasks exit without error, after Close is called.
  EXPECT_TRUE(accept_latch.Await().Ok());
}

TEST_F(BleV2ServerSocketTest, ServerSocket_AcceptDoesntBlockAfterClose) {
  // Calling Close before Accept causes no error,
  // and Accept will not block.
  EXPECT_TRUE(ble_v2_server_socket_->Close().Ok());
  EXPECT_EQ(nullptr, ble_v2_server_socket_->Accept());
}

TEST_F(BleV2ServerSocketTest, Socket_Close) {
  EXPECT_TRUE(ble_v2_socket_->Close().Ok());
}

TEST_F(BleV2ServerSocketTest, Socket_GetRemotePeripheral) {
  EXPECT_TRUE(ble_v2_socket_->GetRemotePeripheral());
}

TEST_F(BleV2ServerSocketTest, InputStream_Read) {
  InputStream* input_stream = &ble_v2_socket_->GetInputStream();
  EXPECT_FALSE(input_stream->Read(1u).ok());
  EXPECT_TRUE(input_stream->Read(1u).GetException().Raised(Exception::kIo));
}

TEST_F(BleV2ServerSocketTest, InputStream_ReadExactly) {
  InputStream* input_stream = &ble_v2_socket_->GetInputStream();
  EXPECT_FALSE(input_stream->ReadExactly(1u).ok());
  EXPECT_TRUE(
      input_stream->ReadExactly(1u).GetException().Raised(Exception::kIo));
}

TEST_F(BleV2ServerSocketTest, InputStream_Close) {
  InputStream* input_stream = &ble_v2_socket_->GetInputStream();
  EXPECT_TRUE(input_stream->Close().Ok());
}

TEST_F(BleV2ServerSocketTest, OutputStream_Write) {
  OutputStream* output_stream = &ble_v2_socket_->GetOutputStream();
  EXPECT_TRUE(output_stream->Write(ByteArray()).Raised(Exception::kIo));
}

TEST_F(BleV2ServerSocketTest, OutputStream_Flush) {
  OutputStream* output_stream = &ble_v2_socket_->GetOutputStream();
  EXPECT_TRUE(output_stream->Flush().Ok());
}

TEST_F(BleV2ServerSocketTest, OutputStream_Close) {
  OutputStream* output_stream = &ble_v2_socket_->GetOutputStream();
  EXPECT_TRUE(output_stream->Close().Ok());
}

}  // namespace chrome
}  // namespace nearby