1// Copyright 2014 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 "net/socket/websocket_endpoint_lock_manager.h"
6
7#include "net/base/net_errors.h"
8#include "net/socket/next_proto.h"
9#include "net/socket/socket_test_util.h"
10#include "net/socket/stream_socket.h"
11#include "testing/gtest/include/gtest/gtest.h"
12
13namespace net {
14
15namespace {
16
17// A StreamSocket implementation with no functionality at all.
18// TODO(ricea): If you need to use this in another file, please move it to
19// socket_test_util.h.
20class FakeStreamSocket : public StreamSocket {
21 public:
22  FakeStreamSocket() {}
23
24  // StreamSocket implementation
25  virtual int Connect(const CompletionCallback& callback) OVERRIDE {
26    return ERR_FAILED;
27  }
28
29  virtual void Disconnect() OVERRIDE { return; }
30
31  virtual bool IsConnected() const OVERRIDE { return false; }
32
33  virtual bool IsConnectedAndIdle() const OVERRIDE { return false; }
34
35  virtual int GetPeerAddress(IPEndPoint* address) const OVERRIDE {
36    return ERR_FAILED;
37  }
38
39  virtual int GetLocalAddress(IPEndPoint* address) const OVERRIDE {
40    return ERR_FAILED;
41  }
42
43  virtual const BoundNetLog& NetLog() const OVERRIDE { return bound_net_log_; }
44
45  virtual void SetSubresourceSpeculation() OVERRIDE { return; }
46  virtual void SetOmniboxSpeculation() OVERRIDE { return; }
47
48  virtual bool WasEverUsed() const OVERRIDE { return false; }
49
50  virtual bool UsingTCPFastOpen() const OVERRIDE { return false; }
51
52  virtual bool WasNpnNegotiated() const OVERRIDE { return false; }
53
54  virtual NextProto GetNegotiatedProtocol() const OVERRIDE {
55    return kProtoUnknown;
56  }
57
58  virtual bool GetSSLInfo(SSLInfo* ssl_info) OVERRIDE { return false; }
59
60  // Socket implementation
61  virtual int Read(IOBuffer* buf,
62                   int buf_len,
63                   const CompletionCallback& callback) OVERRIDE {
64    return ERR_FAILED;
65  }
66
67  virtual int Write(IOBuffer* buf,
68                    int buf_len,
69                    const CompletionCallback& callback) OVERRIDE {
70    return ERR_FAILED;
71  }
72
73  virtual int SetReceiveBufferSize(int32 size) OVERRIDE { return ERR_FAILED; }
74
75  virtual int SetSendBufferSize(int32 size) OVERRIDE { return ERR_FAILED; }
76
77 private:
78  BoundNetLog bound_net_log_;
79
80  DISALLOW_COPY_AND_ASSIGN(FakeStreamSocket);
81};
82
83class FakeWaiter : public WebSocketEndpointLockManager::Waiter {
84 public:
85  FakeWaiter() : called_(false) {}
86
87  virtual void GotEndpointLock() OVERRIDE {
88    CHECK(!called_);
89    called_ = true;
90  }
91
92  bool called() const { return called_; }
93
94 private:
95  bool called_;
96};
97
98class WebSocketEndpointLockManagerTest : public ::testing::Test {
99 protected:
100  WebSocketEndpointLockManagerTest()
101      : instance_(WebSocketEndpointLockManager::GetInstance()) {}
102  virtual ~WebSocketEndpointLockManagerTest() {
103    // If this check fails then subsequent tests may fail.
104    CHECK(instance_->IsEmpty());
105  }
106
107  WebSocketEndpointLockManager* instance() const { return instance_; }
108
109  IPEndPoint DummyEndpoint() {
110    IPAddressNumber ip_address_number;
111    CHECK(ParseIPLiteralToNumber("127.0.0.1", &ip_address_number));
112    return IPEndPoint(ip_address_number, 80);
113  }
114
115  void UnlockDummyEndpoint(int times) {
116    for (int i = 0; i < times; ++i) {
117      instance()->UnlockEndpoint(DummyEndpoint());
118    }
119  }
120
121  WebSocketEndpointLockManager* const instance_;
122};
123
124TEST_F(WebSocketEndpointLockManagerTest, GetInstanceWorks) {
125  // All the work is done by the test framework.
126}
127
128TEST_F(WebSocketEndpointLockManagerTest, LockEndpointReturnsOkOnce) {
129  FakeWaiter waiters[2];
130  EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &waiters[0]));
131  EXPECT_EQ(ERR_IO_PENDING,
132            instance()->LockEndpoint(DummyEndpoint(), &waiters[1]));
133
134  UnlockDummyEndpoint(2);
135}
136
137TEST_F(WebSocketEndpointLockManagerTest, GotEndpointLockNotCalledOnOk) {
138  FakeWaiter waiter;
139  EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &waiter));
140  EXPECT_FALSE(waiter.called());
141
142  UnlockDummyEndpoint(1);
143}
144
145TEST_F(WebSocketEndpointLockManagerTest, GotEndpointLockNotCalledImmediately) {
146  FakeWaiter waiters[2];
147  EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &waiters[0]));
148  EXPECT_EQ(ERR_IO_PENDING,
149            instance()->LockEndpoint(DummyEndpoint(), &waiters[1]));
150  EXPECT_FALSE(waiters[1].called());
151
152  UnlockDummyEndpoint(2);
153}
154
155TEST_F(WebSocketEndpointLockManagerTest, GotEndpointLockCalledWhenUnlocked) {
156  FakeWaiter waiters[2];
157  EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &waiters[0]));
158  EXPECT_EQ(ERR_IO_PENDING,
159            instance()->LockEndpoint(DummyEndpoint(), &waiters[1]));
160  instance()->UnlockEndpoint(DummyEndpoint());
161  EXPECT_TRUE(waiters[1].called());
162
163  UnlockDummyEndpoint(1);
164}
165
166TEST_F(WebSocketEndpointLockManagerTest,
167       EndpointUnlockedIfWaiterAlreadyDeleted) {
168  FakeWaiter first_lock_holder;
169  EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &first_lock_holder));
170
171  {
172    FakeWaiter short_lived_waiter;
173    EXPECT_EQ(ERR_IO_PENDING,
174              instance()->LockEndpoint(DummyEndpoint(), &short_lived_waiter));
175  }
176
177  instance()->UnlockEndpoint(DummyEndpoint());
178
179  FakeWaiter second_lock_holder;
180  EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &second_lock_holder));
181
182  UnlockDummyEndpoint(1);
183}
184
185TEST_F(WebSocketEndpointLockManagerTest, RememberSocketWorks) {
186  FakeWaiter waiters[2];
187  FakeStreamSocket dummy_socket;
188  EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &waiters[0]));
189  EXPECT_EQ(ERR_IO_PENDING,
190            instance()->LockEndpoint(DummyEndpoint(), &waiters[1]));
191
192  instance()->RememberSocket(&dummy_socket, DummyEndpoint());
193  instance()->UnlockSocket(&dummy_socket);
194  EXPECT_TRUE(waiters[1].called());
195
196  UnlockDummyEndpoint(1);
197}
198
199// UnlockEndpoint() should cause any sockets remembered for this endpoint
200// to be forgotten.
201TEST_F(WebSocketEndpointLockManagerTest, SocketAssociationForgottenOnUnlock) {
202  FakeWaiter waiter;
203  FakeStreamSocket dummy_socket;
204
205  EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &waiter));
206  instance()->RememberSocket(&dummy_socket, DummyEndpoint());
207  instance()->UnlockEndpoint(DummyEndpoint());
208  EXPECT_TRUE(instance()->IsEmpty());
209}
210
211// When ownership of the endpoint is passed to a new waiter, the new waiter can
212// call RememberSocket() again.
213TEST_F(WebSocketEndpointLockManagerTest, NextWaiterCanCallRememberSocketAgain) {
214  FakeWaiter waiters[2];
215  FakeStreamSocket dummy_sockets[2];
216  EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &waiters[0]));
217  EXPECT_EQ(ERR_IO_PENDING,
218            instance()->LockEndpoint(DummyEndpoint(), &waiters[1]));
219
220  instance()->RememberSocket(&dummy_sockets[0], DummyEndpoint());
221  instance()->UnlockEndpoint(DummyEndpoint());
222  EXPECT_TRUE(waiters[1].called());
223  instance()->RememberSocket(&dummy_sockets[1], DummyEndpoint());
224
225  UnlockDummyEndpoint(1);
226}
227
228}  // namespace
229
230}  // namespace net
231