1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/basictypes.h"
6#include "base/sync_socket.h"
7#include "base/threading/simple_thread.h"
8#include "base/time/time.h"
9#include "testing/gtest/include/gtest/gtest.h"
10
11namespace {
12
13const int kReceiveTimeoutInMilliseconds = 750;
14
15class HangingReceiveThread : public base::DelegateSimpleThread::Delegate {
16 public:
17  explicit HangingReceiveThread(base::SyncSocket* socket)
18      : socket_(socket),
19        thread_(this, "HangingReceiveThread") {
20    thread_.Start();
21  }
22
23  virtual ~HangingReceiveThread() {}
24
25  virtual void Run() OVERRIDE {
26    int data = 0;
27    ASSERT_EQ(socket_->Peek(), 0u);
28
29    // Use receive with timeout so we don't hang the test harness indefinitely.
30    ASSERT_EQ(0u, socket_->ReceiveWithTimeout(
31        &data, sizeof(data), base::TimeDelta::FromMilliseconds(
32            kReceiveTimeoutInMilliseconds)));
33  }
34
35  void Stop() {
36    thread_.Join();
37  }
38
39 private:
40  base::SyncSocket* socket_;
41  base::DelegateSimpleThread thread_;
42
43  DISALLOW_COPY_AND_ASSIGN(HangingReceiveThread);
44};
45
46// Tests sending data between two SyncSockets.  Uses ASSERT() and thus will exit
47// early upon failure.  Callers should use ASSERT_NO_FATAL_FAILURE() if testing
48// continues after return.
49void SendReceivePeek(base::SyncSocket* socket_a, base::SyncSocket* socket_b) {
50  int received = 0;
51  const int kSending = 123;
52  COMPILE_ASSERT(sizeof(kSending) == sizeof(received), Invalid_Data_Size);
53
54  ASSERT_EQ(0u, socket_a->Peek());
55  ASSERT_EQ(0u, socket_b->Peek());
56
57  // Verify |socket_a| can send to |socket_a| and |socket_a| can Receive from
58  // |socket_a|.
59  ASSERT_EQ(sizeof(kSending), socket_a->Send(&kSending, sizeof(kSending)));
60  ASSERT_EQ(sizeof(kSending), socket_b->Peek());
61  ASSERT_EQ(sizeof(kSending), socket_b->Receive(&received, sizeof(kSending)));
62  ASSERT_EQ(kSending, received);
63
64  ASSERT_EQ(0u, socket_a->Peek());
65  ASSERT_EQ(0u, socket_b->Peek());
66
67  // Now verify the reverse.
68  received = 0;
69  ASSERT_EQ(sizeof(kSending), socket_b->Send(&kSending, sizeof(kSending)));
70  ASSERT_EQ(sizeof(kSending), socket_a->Peek());
71  ASSERT_EQ(sizeof(kSending), socket_a->Receive(&received, sizeof(kSending)));
72  ASSERT_EQ(kSending, received);
73
74  ASSERT_EQ(0u, socket_a->Peek());
75  ASSERT_EQ(0u, socket_b->Peek());
76
77  ASSERT_TRUE(socket_a->Close());
78  ASSERT_TRUE(socket_b->Close());
79}
80
81template <class SocketType>
82void NormalSendReceivePeek() {
83  SocketType socket_a, socket_b;
84  ASSERT_TRUE(SocketType::CreatePair(&socket_a, &socket_b));
85  SendReceivePeek(&socket_a, &socket_b);
86}
87
88template <class SocketType>
89void ClonedSendReceivePeek() {
90  SocketType socket_a, socket_b;
91  ASSERT_TRUE(SocketType::CreatePair(&socket_a, &socket_b));
92
93  // Create new SyncSockets from the paired handles.
94  SocketType socket_c(socket_a.handle()), socket_d(socket_b.handle());
95  SendReceivePeek(&socket_c, &socket_d);
96}
97
98}  // namespace
99
100TEST(SyncSocket, NormalSendReceivePeek) {
101  NormalSendReceivePeek<base::SyncSocket>();
102}
103
104TEST(SyncSocket, ClonedSendReceivePeek) {
105  ClonedSendReceivePeek<base::SyncSocket>();
106}
107
108TEST(CancelableSyncSocket, NormalSendReceivePeek) {
109  NormalSendReceivePeek<base::CancelableSyncSocket>();
110}
111
112TEST(CancelableSyncSocket, ClonedSendReceivePeek) {
113  ClonedSendReceivePeek<base::CancelableSyncSocket>();
114}
115
116TEST(CancelableSyncSocket, CancelReceiveShutdown) {
117  base::CancelableSyncSocket socket_a, socket_b;
118  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&socket_a, &socket_b));
119
120  base::TimeTicks start = base::TimeTicks::Now();
121  HangingReceiveThread thread(&socket_b);
122  ASSERT_TRUE(socket_b.Shutdown());
123  thread.Stop();
124
125  // Ensure the receive didn't just timeout.
126  ASSERT_LT((base::TimeTicks::Now() - start).InMilliseconds(),
127            kReceiveTimeoutInMilliseconds);
128
129  ASSERT_TRUE(socket_a.Close());
130  ASSERT_TRUE(socket_b.Close());
131}
132