xref: /aosp_15_r20/external/cronet/net/socket/websocket_endpoint_lock_manager_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2014 The Chromium Authors
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 "base/check.h"
8 #include "base/run_loop.h"
9 #include "base/time/time.h"
10 #include "net/base/ip_address.h"
11 #include "net/base/net_errors.h"
12 #include "net/log/net_log_with_source.h"
13 #include "net/socket/next_proto.h"
14 #include "net/socket/socket_test_util.h"
15 #include "net/test/gtest_util.h"
16 #include "net/test/test_with_task_environment.h"
17 #include "net/traffic_annotation/network_traffic_annotation.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 
21 using net::test::IsOk;
22 
23 namespace net {
24 
25 namespace {
26 
27 class FakeWaiter : public WebSocketEndpointLockManager::Waiter {
28  public:
29   FakeWaiter() = default;
30 
GotEndpointLock()31   void GotEndpointLock() override {
32     CHECK(!called_);
33     called_ = true;
34   }
35 
called() const36   bool called() const { return called_; }
37 
38  private:
39   bool called_ = false;
40 };
41 
42 class BlockingWaiter : public FakeWaiter {
43  public:
WaitForLock()44   void WaitForLock() {
45     while (!called()) {
46       run_loop_.Run();
47     }
48   }
49 
GotEndpointLock()50   void GotEndpointLock() override {
51     FakeWaiter::GotEndpointLock();
52     run_loop_.Quit();
53   }
54 
55  private:
56   base::RunLoop run_loop_;
57 };
58 
59 class WebSocketEndpointLockManagerTest : public TestWithTaskEnvironment {
60  protected:
WebSocketEndpointLockManagerTest()61   WebSocketEndpointLockManagerTest() {
62     websocket_endpoint_lock_manager_.SetUnlockDelayForTesting(
63         base::TimeDelta());
64   }
65 
~WebSocketEndpointLockManagerTest()66   ~WebSocketEndpointLockManagerTest() override {
67     // Permit any pending asynchronous unlock operations to complete.
68     RunUntilIdle();
69     // If this check fails then subsequent tests may fail.
70     CHECK(websocket_endpoint_lock_manager_.IsEmpty());
71   }
72 
DummyEndpoint()73   IPEndPoint DummyEndpoint() {
74     return IPEndPoint(IPAddress::IPv4Localhost(), 80);
75   }
76 
UnlockDummyEndpoint(int times)77   void UnlockDummyEndpoint(int times) {
78     for (int i = 0; i < times; ++i) {
79       websocket_endpoint_lock_manager_.UnlockEndpoint(DummyEndpoint());
80       RunUntilIdle();
81     }
82   }
83 
RunUntilIdle()84   static void RunUntilIdle() { base::RunLoop().RunUntilIdle(); }
85 
86   WebSocketEndpointLockManager websocket_endpoint_lock_manager_;
87 };
88 
TEST_F(WebSocketEndpointLockManagerTest,LockEndpointReturnsOkOnce)89 TEST_F(WebSocketEndpointLockManagerTest, LockEndpointReturnsOkOnce) {
90   FakeWaiter waiters[2];
91   EXPECT_THAT(websocket_endpoint_lock_manager_.LockEndpoint(DummyEndpoint(),
92                                                             &waiters[0]),
93               IsOk());
94   EXPECT_EQ(ERR_IO_PENDING, websocket_endpoint_lock_manager_.LockEndpoint(
95                                 DummyEndpoint(), &waiters[1]));
96 
97   UnlockDummyEndpoint(2);
98 }
99 
TEST_F(WebSocketEndpointLockManagerTest,GotEndpointLockNotCalledOnOk)100 TEST_F(WebSocketEndpointLockManagerTest, GotEndpointLockNotCalledOnOk) {
101   FakeWaiter waiter;
102   EXPECT_THAT(
103       websocket_endpoint_lock_manager_.LockEndpoint(DummyEndpoint(), &waiter),
104       IsOk());
105   RunUntilIdle();
106   EXPECT_FALSE(waiter.called());
107 
108   UnlockDummyEndpoint(1);
109 }
110 
TEST_F(WebSocketEndpointLockManagerTest,GotEndpointLockNotCalledImmediately)111 TEST_F(WebSocketEndpointLockManagerTest, GotEndpointLockNotCalledImmediately) {
112   FakeWaiter waiters[2];
113   EXPECT_THAT(websocket_endpoint_lock_manager_.LockEndpoint(DummyEndpoint(),
114                                                             &waiters[0]),
115               IsOk());
116   EXPECT_EQ(ERR_IO_PENDING, websocket_endpoint_lock_manager_.LockEndpoint(
117                                 DummyEndpoint(), &waiters[1]));
118   RunUntilIdle();
119   EXPECT_FALSE(waiters[1].called());
120 
121   UnlockDummyEndpoint(2);
122 }
123 
TEST_F(WebSocketEndpointLockManagerTest,GotEndpointLockCalledWhenUnlocked)124 TEST_F(WebSocketEndpointLockManagerTest, GotEndpointLockCalledWhenUnlocked) {
125   FakeWaiter waiters[2];
126   EXPECT_THAT(websocket_endpoint_lock_manager_.LockEndpoint(DummyEndpoint(),
127                                                             &waiters[0]),
128               IsOk());
129   EXPECT_EQ(ERR_IO_PENDING, websocket_endpoint_lock_manager_.LockEndpoint(
130                                 DummyEndpoint(), &waiters[1]));
131   websocket_endpoint_lock_manager_.UnlockEndpoint(DummyEndpoint());
132   RunUntilIdle();
133   EXPECT_TRUE(waiters[1].called());
134 
135   UnlockDummyEndpoint(1);
136 }
137 
TEST_F(WebSocketEndpointLockManagerTest,EndpointUnlockedIfWaiterAlreadyDeleted)138 TEST_F(WebSocketEndpointLockManagerTest,
139        EndpointUnlockedIfWaiterAlreadyDeleted) {
140   FakeWaiter first_lock_holder;
141   EXPECT_THAT(websocket_endpoint_lock_manager_.LockEndpoint(DummyEndpoint(),
142                                                             &first_lock_holder),
143               IsOk());
144 
145   {
146     FakeWaiter short_lived_waiter;
147     EXPECT_EQ(ERR_IO_PENDING, websocket_endpoint_lock_manager_.LockEndpoint(
148                                   DummyEndpoint(), &short_lived_waiter));
149   }
150 
151   websocket_endpoint_lock_manager_.UnlockEndpoint(DummyEndpoint());
152   RunUntilIdle();
153 
154   FakeWaiter second_lock_holder;
155   EXPECT_THAT(websocket_endpoint_lock_manager_.LockEndpoint(
156                   DummyEndpoint(), &second_lock_holder),
157               IsOk());
158 
159   UnlockDummyEndpoint(1);
160 }
161 
TEST_F(WebSocketEndpointLockManagerTest,LockReleaserWorks)162 TEST_F(WebSocketEndpointLockManagerTest, LockReleaserWorks) {
163   FakeWaiter waiters[2];
164   EXPECT_THAT(websocket_endpoint_lock_manager_.LockEndpoint(DummyEndpoint(),
165                                                             &waiters[0]),
166               IsOk());
167   EXPECT_EQ(ERR_IO_PENDING, websocket_endpoint_lock_manager_.LockEndpoint(
168                                 DummyEndpoint(), &waiters[1]));
169 
170   {
171     WebSocketEndpointLockManager::LockReleaser releaser(
172         &websocket_endpoint_lock_manager_, DummyEndpoint());
173   }
174   RunUntilIdle();
175   EXPECT_TRUE(waiters[1].called());
176 
177   UnlockDummyEndpoint(1);
178 }
179 
180 // UnlockEndpoint() should cause any LockReleasers for this endpoint to be
181 // unregistered.
TEST_F(WebSocketEndpointLockManagerTest,LockReleaserForgottenOnUnlock)182 TEST_F(WebSocketEndpointLockManagerTest, LockReleaserForgottenOnUnlock) {
183   FakeWaiter waiter;
184 
185   EXPECT_THAT(
186       websocket_endpoint_lock_manager_.LockEndpoint(DummyEndpoint(), &waiter),
187       IsOk());
188   WebSocketEndpointLockManager::LockReleaser releaser(
189       &websocket_endpoint_lock_manager_, DummyEndpoint());
190   websocket_endpoint_lock_manager_.UnlockEndpoint(DummyEndpoint());
191   RunUntilIdle();
192   EXPECT_TRUE(websocket_endpoint_lock_manager_.IsEmpty());
193 }
194 
195 // When ownership of the endpoint is passed to a new waiter, the new waiter can
196 // construct another LockReleaser.
TEST_F(WebSocketEndpointLockManagerTest,NextWaiterCanCreateLockReleaserAgain)197 TEST_F(WebSocketEndpointLockManagerTest, NextWaiterCanCreateLockReleaserAgain) {
198   FakeWaiter waiters[2];
199   EXPECT_THAT(websocket_endpoint_lock_manager_.LockEndpoint(DummyEndpoint(),
200                                                             &waiters[0]),
201               IsOk());
202   EXPECT_EQ(ERR_IO_PENDING, websocket_endpoint_lock_manager_.LockEndpoint(
203                                 DummyEndpoint(), &waiters[1]));
204 
205   WebSocketEndpointLockManager::LockReleaser releaser1(
206       &websocket_endpoint_lock_manager_, DummyEndpoint());
207   websocket_endpoint_lock_manager_.UnlockEndpoint(DummyEndpoint());
208   RunUntilIdle();
209   EXPECT_TRUE(waiters[1].called());
210   WebSocketEndpointLockManager::LockReleaser releaser2(
211       &websocket_endpoint_lock_manager_, DummyEndpoint());
212 
213   UnlockDummyEndpoint(1);
214 }
215 
216 // Destroying LockReleaser after UnlockEndpoint() does nothing.
TEST_F(WebSocketEndpointLockManagerTest,DestroyLockReleaserAfterUnlockEndpointDoesNothing)217 TEST_F(WebSocketEndpointLockManagerTest,
218        DestroyLockReleaserAfterUnlockEndpointDoesNothing) {
219   FakeWaiter waiters[3];
220 
221   EXPECT_THAT(websocket_endpoint_lock_manager_.LockEndpoint(DummyEndpoint(),
222                                                             &waiters[0]),
223               IsOk());
224   EXPECT_EQ(ERR_IO_PENDING, websocket_endpoint_lock_manager_.LockEndpoint(
225                                 DummyEndpoint(), &waiters[1]));
226   EXPECT_EQ(ERR_IO_PENDING, websocket_endpoint_lock_manager_.LockEndpoint(
227                                 DummyEndpoint(), &waiters[2]));
228   {
229     WebSocketEndpointLockManager::LockReleaser releaser(
230         &websocket_endpoint_lock_manager_, DummyEndpoint());
231     websocket_endpoint_lock_manager_.UnlockEndpoint(DummyEndpoint());
232   }
233   RunUntilIdle();
234   EXPECT_TRUE(waiters[1].called());
235   EXPECT_FALSE(waiters[2].called());
236 
237   UnlockDummyEndpoint(2);
238 }
239 
240 // UnlockEndpoint() should always be asynchronous.
TEST_F(WebSocketEndpointLockManagerTest,UnlockEndpointIsAsynchronous)241 TEST_F(WebSocketEndpointLockManagerTest, UnlockEndpointIsAsynchronous) {
242   FakeWaiter waiters[2];
243   EXPECT_THAT(websocket_endpoint_lock_manager_.LockEndpoint(DummyEndpoint(),
244                                                             &waiters[0]),
245               IsOk());
246   EXPECT_EQ(ERR_IO_PENDING, websocket_endpoint_lock_manager_.LockEndpoint(
247                                 DummyEndpoint(), &waiters[1]));
248 
249   websocket_endpoint_lock_manager_.UnlockEndpoint(DummyEndpoint());
250   EXPECT_FALSE(waiters[1].called());
251   RunUntilIdle();
252   EXPECT_TRUE(waiters[1].called());
253 
254   UnlockDummyEndpoint(1);
255 }
256 
257 // UnlockEndpoint() should normally have a delay.
TEST_F(WebSocketEndpointLockManagerTest,UnlockEndpointIsDelayed)258 TEST_F(WebSocketEndpointLockManagerTest, UnlockEndpointIsDelayed) {
259   using base::TimeTicks;
260 
261   // This 1ms delay is too short for very slow environments (usually those
262   // running memory checkers). In those environments, the code takes >1ms to run
263   // and no delay is needed. Rather than increase the delay and slow down the
264   // test everywhere, the test doesn't explicitly verify that a delay has been
265   // applied. Instead it just verifies that the whole thing took >=1ms. 1ms is
266   // easily enough for normal compiles even on Android, so the fact that there
267   // is a delay is still checked on every platform.
268   const base::TimeDelta unlock_delay = base::Milliseconds(1);
269   websocket_endpoint_lock_manager_.SetUnlockDelayForTesting(unlock_delay);
270   FakeWaiter fake_waiter;
271   BlockingWaiter blocking_waiter;
272   EXPECT_THAT(websocket_endpoint_lock_manager_.LockEndpoint(DummyEndpoint(),
273                                                             &fake_waiter),
274               IsOk());
275   EXPECT_EQ(ERR_IO_PENDING, websocket_endpoint_lock_manager_.LockEndpoint(
276                                 DummyEndpoint(), &blocking_waiter));
277 
278   TimeTicks before_unlock = TimeTicks::Now();
279   websocket_endpoint_lock_manager_.UnlockEndpoint(DummyEndpoint());
280   blocking_waiter.WaitForLock();
281   TimeTicks after_unlock = TimeTicks::Now();
282   EXPECT_GE(after_unlock - before_unlock, unlock_delay);
283   websocket_endpoint_lock_manager_.SetUnlockDelayForTesting(base::TimeDelta());
284   UnlockDummyEndpoint(1);
285 }
286 
287 }  // namespace
288 
289 }  // namespace net
290