// 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/macros.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::TimeDelta::FromMilliseconds(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() 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:
SyncSocket* socket_;
DelegateSimpleThread thread_;
bool with_timeout_;
WaitableEvent started_event_;
WaitableEvent done_event_;
DISALLOW_COPY_AND_ASSIGN(HangingReceiveThread);
};
// 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());
ASSERT_TRUE(socket_a->Close());
ASSERT_TRUE(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