// Copyright 2013 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 "base/sync_socket.h" #include "base/memory/raw_ptr.h" #include "base/synchronization/waitable_event.h" #include "base/threading/platform_thread.h" #include "base/threading/simple_thread.h" #include "base/time/time.h" #include "testing/gtest/include/gtest/gtest.h" namespace base { namespace { constexpr TimeDelta kReceiveTimeout = base::Milliseconds(750); class HangingReceiveThread : public DelegateSimpleThread::Delegate { public: explicit HangingReceiveThread(SyncSocket* socket, bool with_timeout) : socket_(socket), thread_(this, "HangingReceiveThread"), with_timeout_(with_timeout), started_event_(WaitableEvent::ResetPolicy::MANUAL, WaitableEvent::InitialState::NOT_SIGNALED), done_event_(WaitableEvent::ResetPolicy::MANUAL, WaitableEvent::InitialState::NOT_SIGNALED) { thread_.Start(); } HangingReceiveThread(const HangingReceiveThread&) = delete; HangingReceiveThread& operator=(const HangingReceiveThread&) = delete; ~HangingReceiveThread() override = default; void Run() override { int data = 0; ASSERT_EQ(socket_->Peek(), 0u); started_event_.Signal(); if (with_timeout_) { ASSERT_EQ(0u, socket_->ReceiveWithTimeout(&data, sizeof(data), kReceiveTimeout)); } else { ASSERT_EQ(0u, socket_->Receive(&data, sizeof(data))); } done_event_.Signal(); } void Stop() { thread_.Join(); } WaitableEvent* started_event() { return &started_event_; } WaitableEvent* done_event() { return &done_event_; } private: raw_ptr socket_; DelegateSimpleThread thread_; bool with_timeout_; WaitableEvent started_event_; WaitableEvent done_event_; }; // Tests sending data between two SyncSockets. Uses ASSERT() and thus will exit // early upon failure. Callers should use ASSERT_NO_FATAL_FAILURE() if testing // continues after return. void SendReceivePeek(SyncSocket* socket_a, SyncSocket* socket_b) { int received = 0; const int kSending = 123; static_assert(sizeof(kSending) == sizeof(received), "invalid data size"); ASSERT_EQ(0u, socket_a->Peek()); ASSERT_EQ(0u, socket_b->Peek()); // Verify |socket_a| can send to |socket_a| and |socket_a| can Receive from // |socket_a|. ASSERT_EQ(sizeof(kSending), socket_a->Send(&kSending, sizeof(kSending))); ASSERT_EQ(sizeof(kSending), socket_b->Peek()); ASSERT_EQ(sizeof(kSending), socket_b->Receive(&received, sizeof(kSending))); ASSERT_EQ(kSending, received); ASSERT_EQ(0u, socket_a->Peek()); ASSERT_EQ(0u, socket_b->Peek()); // Now verify the reverse. received = 0; ASSERT_EQ(sizeof(kSending), socket_b->Send(&kSending, sizeof(kSending))); ASSERT_EQ(sizeof(kSending), socket_a->Peek()); ASSERT_EQ(sizeof(kSending), socket_a->Receive(&received, sizeof(kSending))); ASSERT_EQ(kSending, received); ASSERT_EQ(0u, socket_a->Peek()); ASSERT_EQ(0u, socket_b->Peek()); socket_a->Close(); socket_b->Close(); } } // namespace class SyncSocketTest : public testing::Test { public: void SetUp() override { ASSERT_TRUE(SyncSocket::CreatePair(&socket_a_, &socket_b_)); } protected: SyncSocket socket_a_; SyncSocket socket_b_; }; TEST_F(SyncSocketTest, NormalSendReceivePeek) { SendReceivePeek(&socket_a_, &socket_b_); } TEST_F(SyncSocketTest, ClonedSendReceivePeek) { SyncSocket socket_c(socket_a_.Release()); SyncSocket socket_d(socket_b_.Release()); SendReceivePeek(&socket_c, &socket_d); } class CancelableSyncSocketTest : public testing::Test { public: void SetUp() override { ASSERT_TRUE(CancelableSyncSocket::CreatePair(&socket_a_, &socket_b_)); } protected: CancelableSyncSocket socket_a_; CancelableSyncSocket socket_b_; }; TEST_F(CancelableSyncSocketTest, NormalSendReceivePeek) { SendReceivePeek(&socket_a_, &socket_b_); } TEST_F(CancelableSyncSocketTest, ClonedSendReceivePeek) { CancelableSyncSocket socket_c(socket_a_.Release()); CancelableSyncSocket socket_d(socket_b_.Release()); SendReceivePeek(&socket_c, &socket_d); } TEST_F(CancelableSyncSocketTest, ShutdownCancelsReceive) { HangingReceiveThread thread(&socket_b_, /* with_timeout = */ false); // Wait for the thread to be started. Note that this doesn't guarantee that // Receive() is called before Shutdown(). thread.started_event()->Wait(); EXPECT_TRUE(socket_b_.Shutdown()); EXPECT_TRUE(thread.done_event()->TimedWait(kReceiveTimeout)); thread.Stop(); } TEST_F(CancelableSyncSocketTest, ShutdownCancelsReceiveWithTimeout) { HangingReceiveThread thread(&socket_b_, /* with_timeout = */ true); // Wait for the thread to be started. Note that this doesn't guarantee that // Receive() is called before Shutdown(). thread.started_event()->Wait(); EXPECT_TRUE(socket_b_.Shutdown()); EXPECT_TRUE(thread.done_event()->TimedWait(kReceiveTimeout)); thread.Stop(); } TEST_F(CancelableSyncSocketTest, ReceiveAfterShutdown) { socket_a_.Shutdown(); int data = 0; EXPECT_EQ(0u, socket_a_.Receive(&data, sizeof(data))); } TEST_F(CancelableSyncSocketTest, ReceiveWithTimeoutAfterShutdown) { socket_a_.Shutdown(); TimeTicks start = TimeTicks::Now(); int data = 0; EXPECT_EQ(0u, socket_a_.ReceiveWithTimeout(&data, sizeof(data), kReceiveTimeout)); // Ensure the receive didn't just timeout. EXPECT_LT(TimeTicks::Now() - start, kReceiveTimeout); } } // namespace base