OLD | NEW |
(Empty) | |
| 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 // NOTE(vtl): Some of these tests are inherently flaky (e.g., if run on a |
| 6 // heavily-loaded system). Sorry. |kEpsilonMicros| may be increased to increase |
| 7 // tolerance and reduce observed flakiness. |
| 8 |
| 9 #include "mojo/system/message_pipe_dispatcher.h" |
| 10 |
| 11 #include "base/memory/ref_counted.h" |
| 12 #include "base/threading/platform_thread.h" // For |Sleep()|. |
| 13 #include "base/time/time.h" |
| 14 #include "mojo/system/message_pipe.h" |
| 15 #include "mojo/system/test_utils.h" |
| 16 #include "mojo/system/waiter.h" |
| 17 #include "mojo/system/waiter_test_utils.h" |
| 18 #include "testing/gtest/include/gtest/gtest.h" |
| 19 |
| 20 namespace mojo { |
| 21 namespace system { |
| 22 namespace { |
| 23 |
| 24 const int64_t kMicrosPerMs = 1000; |
| 25 const int64_t kEpsilonMicros = 15 * kMicrosPerMs; // 15 ms. |
| 26 |
| 27 TEST(MessagePipeDispatcherTest, Basic) { |
| 28 test::Stopwatch stopwatch; |
| 29 int32_t buffer[1]; |
| 30 const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer)); |
| 31 uint32_t buffer_size; |
| 32 int64_t elapsed_micros; |
| 33 |
| 34 // Run this test both with |d_0| as port 0, |d_1| as port 1 and vice versa. |
| 35 for (unsigned i = 0; i < 2; i++) { |
| 36 scoped_refptr<MessagePipeDispatcher> d_0(new MessagePipeDispatcher()); |
| 37 scoped_refptr<MessagePipeDispatcher> d_1(new MessagePipeDispatcher()); |
| 38 { |
| 39 scoped_refptr<MessagePipe> mp(new MessagePipe()); |
| 40 d_0->Init(mp, i); // 0, 1. |
| 41 d_1->Init(mp, i ^ 1); // 1, 0. |
| 42 } |
| 43 Waiter w; |
| 44 |
| 45 // Try adding a writable waiter when already writable. |
| 46 w.Init(); |
| 47 EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, |
| 48 d_0->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 0)); |
| 49 // Shouldn't need to remove the waiter (it was not added). |
| 50 |
| 51 // Add a readable waiter to |d_0|, then make it readable (by writing to |
| 52 // |d_1|), then wait. |
| 53 w.Init(); |
| 54 EXPECT_EQ(MOJO_RESULT_OK, |
| 55 d_0->AddWaiter(&w, MOJO_WAIT_FLAG_READABLE, 1)); |
| 56 buffer[0] = 123456789; |
| 57 EXPECT_EQ(MOJO_RESULT_OK, |
| 58 d_1->WriteMessage(buffer, kBufferSize, |
| 59 NULL, 0, |
| 60 MOJO_WRITE_MESSAGE_FLAG_NONE)); |
| 61 stopwatch.Start(); |
| 62 EXPECT_EQ(1, w.Wait(MOJO_DEADLINE_INDEFINITE)); |
| 63 elapsed_micros = stopwatch.Elapsed(); |
| 64 EXPECT_LT(elapsed_micros, kEpsilonMicros); |
| 65 d_0->RemoveWaiter(&w); |
| 66 |
| 67 // Try adding a readable waiter when already readable (from above). |
| 68 w.Init(); |
| 69 EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, |
| 70 d_0->AddWaiter(&w, MOJO_WAIT_FLAG_READABLE, 2)); |
| 71 // Shouldn't need to remove the waiter (it was not added). |
| 72 |
| 73 // Make |d_0| no longer readable (by reading from it). |
| 74 buffer[0] = 0; |
| 75 buffer_size = kBufferSize; |
| 76 EXPECT_EQ(MOJO_RESULT_OK, |
| 77 d_0->ReadMessage(buffer, &buffer_size, |
| 78 NULL, NULL, |
| 79 MOJO_READ_MESSAGE_FLAG_NONE)); |
| 80 EXPECT_EQ(kBufferSize, buffer_size); |
| 81 EXPECT_EQ(123456789, buffer[0]); |
| 82 |
| 83 // Wait for zero time for readability on |d_0| (will time out). |
| 84 w.Init(); |
| 85 EXPECT_EQ(MOJO_RESULT_OK, |
| 86 d_0->AddWaiter(&w, MOJO_WAIT_FLAG_READABLE, 3)); |
| 87 stopwatch.Start(); |
| 88 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, w.Wait(0)); |
| 89 elapsed_micros = stopwatch.Elapsed(); |
| 90 EXPECT_LT(elapsed_micros, kEpsilonMicros); |
| 91 d_0->RemoveWaiter(&w); |
| 92 |
| 93 // Wait for non-zero, finite time for readability on |d_0| (will time out). |
| 94 w.Init(); |
| 95 EXPECT_EQ(MOJO_RESULT_OK, |
| 96 d_0->AddWaiter(&w, MOJO_WAIT_FLAG_READABLE, 3)); |
| 97 stopwatch.Start(); |
| 98 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, w.Wait(2 * kEpsilonMicros)); |
| 99 elapsed_micros = stopwatch.Elapsed(); |
| 100 EXPECT_GT(elapsed_micros, (2-1) * kEpsilonMicros); |
| 101 EXPECT_LT(elapsed_micros, (2+1) * kEpsilonMicros); |
| 102 d_0->RemoveWaiter(&w); |
| 103 |
| 104 EXPECT_EQ(MOJO_RESULT_OK, d_0->Close()); |
| 105 EXPECT_EQ(MOJO_RESULT_OK, d_1->Close()); |
| 106 } |
| 107 } |
| 108 |
| 109 // Test what happens when one end is closed (single-threaded test). |
| 110 TEST(MessagePipeDispatcherTest, BasicClosed) { |
| 111 int32_t buffer[1]; |
| 112 const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer)); |
| 113 uint32_t buffer_size; |
| 114 |
| 115 // Run this test both with |d_0| as port 0, |d_1| as port 1 and vice versa. |
| 116 for (unsigned i = 0; i < 2; i++) { |
| 117 scoped_refptr<MessagePipeDispatcher> d_0(new MessagePipeDispatcher()); |
| 118 scoped_refptr<MessagePipeDispatcher> d_1(new MessagePipeDispatcher()); |
| 119 { |
| 120 scoped_refptr<MessagePipe> mp(new MessagePipe()); |
| 121 d_0->Init(mp, i); // 0, 1. |
| 122 d_1->Init(mp, i ^ 1); // 1, 0. |
| 123 } |
| 124 Waiter w; |
| 125 |
| 126 // Write (twice) to |d_1|. |
| 127 buffer[0] = 123456789; |
| 128 EXPECT_EQ(MOJO_RESULT_OK, |
| 129 d_1->WriteMessage(buffer, kBufferSize, |
| 130 NULL, 0, |
| 131 MOJO_WRITE_MESSAGE_FLAG_NONE)); |
| 132 buffer[0] = 234567890; |
| 133 EXPECT_EQ(MOJO_RESULT_OK, |
| 134 d_1->WriteMessage(buffer, kBufferSize, |
| 135 NULL, 0, |
| 136 MOJO_WRITE_MESSAGE_FLAG_NONE)); |
| 137 |
| 138 // Try waiting for readable on |d_0|; should fail (already satisfied). |
| 139 w.Init(); |
| 140 EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, |
| 141 d_0->AddWaiter(&w, MOJO_WAIT_FLAG_READABLE, 0)); |
| 142 |
| 143 // Close |d_1|. |
| 144 EXPECT_EQ(MOJO_RESULT_OK, d_1->Close()); |
| 145 |
| 146 // Try waiting for readable on |d_0|; should fail (already satisfied). |
| 147 w.Init(); |
| 148 EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, |
| 149 d_0->AddWaiter(&w, MOJO_WAIT_FLAG_READABLE, 1)); |
| 150 |
| 151 // Read from |d_0|. |
| 152 buffer[0] = 0; |
| 153 buffer_size = kBufferSize; |
| 154 EXPECT_EQ(MOJO_RESULT_OK, |
| 155 d_0->ReadMessage(buffer, &buffer_size, |
| 156 NULL, NULL, |
| 157 MOJO_READ_MESSAGE_FLAG_NONE)); |
| 158 EXPECT_EQ(kBufferSize, buffer_size); |
| 159 EXPECT_EQ(123456789, buffer[0]); |
| 160 |
| 161 // Try waiting for readable on |d_0|; should fail (already satisfied). |
| 162 w.Init(); |
| 163 EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, |
| 164 d_0->AddWaiter(&w, MOJO_WAIT_FLAG_READABLE, 2)); |
| 165 |
| 166 // Read again from |d_0|. |
| 167 buffer[0] = 0; |
| 168 buffer_size = kBufferSize; |
| 169 EXPECT_EQ(MOJO_RESULT_OK, |
| 170 d_0->ReadMessage(buffer, &buffer_size, |
| 171 NULL, NULL, |
| 172 MOJO_READ_MESSAGE_FLAG_NONE)); |
| 173 EXPECT_EQ(kBufferSize, buffer_size); |
| 174 EXPECT_EQ(234567890, buffer[0]); |
| 175 |
| 176 // Try waiting for readable on |d_0|; should fail (unsatisfiable). |
| 177 w.Init(); |
| 178 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, |
| 179 d_0->AddWaiter(&w, MOJO_WAIT_FLAG_READABLE, 3)); |
| 180 |
| 181 // Try waiting for writable on |d_0|; should fail (unsatisfiable). |
| 182 w.Init(); |
| 183 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, |
| 184 d_0->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 4)); |
| 185 |
| 186 // Try reading from |d_0|; should fail (nothing to read). |
| 187 buffer[0] = 0; |
| 188 buffer_size = kBufferSize; |
| 189 EXPECT_EQ(MOJO_RESULT_NOT_FOUND, |
| 190 d_0->ReadMessage(buffer, &buffer_size, |
| 191 NULL, NULL, |
| 192 MOJO_READ_MESSAGE_FLAG_NONE)); |
| 193 |
| 194 // Try writing to |d_0|; should fail (other end closed). |
| 195 buffer[0] = 345678901; |
| 196 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, |
| 197 d_0->WriteMessage(buffer, kBufferSize, |
| 198 NULL, 0, |
| 199 MOJO_WRITE_MESSAGE_FLAG_NONE)); |
| 200 |
| 201 EXPECT_EQ(MOJO_RESULT_OK, d_0->Close()); |
| 202 } |
| 203 } |
| 204 |
| 205 TEST(MessagePipeDispatcherTest, BasicThreaded) { |
| 206 test::Stopwatch stopwatch; |
| 207 int32_t buffer[1]; |
| 208 const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer)); |
| 209 uint32_t buffer_size; |
| 210 bool did_wait; |
| 211 MojoResult result; |
| 212 int64_t elapsed_micros; |
| 213 |
| 214 // Run this test both with |d_0| as port 0, |d_1| as port 1 and vice versa. |
| 215 for (unsigned i = 0; i < 2; i++) { |
| 216 scoped_refptr<MessagePipeDispatcher> d_0(new MessagePipeDispatcher()); |
| 217 scoped_refptr<MessagePipeDispatcher> d_1(new MessagePipeDispatcher()); |
| 218 { |
| 219 scoped_refptr<MessagePipe> mp(new MessagePipe()); |
| 220 d_0->Init(mp, i); // 0, 1. |
| 221 d_1->Init(mp, i ^ 1); // 1, 0. |
| 222 } |
| 223 |
| 224 // Wait for readable on |d_1|, which will become readable after some time. |
| 225 { |
| 226 test::WaiterThread thread(d_1, |
| 227 MOJO_WAIT_FLAG_READABLE, |
| 228 MOJO_DEADLINE_INDEFINITE, |
| 229 0, |
| 230 &did_wait, &result); |
| 231 stopwatch.Start(); |
| 232 thread.Start(); |
| 233 base::PlatformThread::Sleep( |
| 234 base::TimeDelta::FromMicroseconds(2 * kEpsilonMicros)); |
| 235 // Wake it up by writing to |d_0|. |
| 236 buffer[0] = 123456789; |
| 237 EXPECT_EQ(MOJO_RESULT_OK, |
| 238 d_0->WriteMessage(buffer, kBufferSize, |
| 239 NULL, 0, |
| 240 MOJO_WRITE_MESSAGE_FLAG_NONE)); |
| 241 } // Joins the thread. |
| 242 elapsed_micros = stopwatch.Elapsed(); |
| 243 EXPECT_TRUE(did_wait); |
| 244 EXPECT_EQ(0, result); |
| 245 EXPECT_GT(elapsed_micros, (2-1) * kEpsilonMicros); |
| 246 EXPECT_LT(elapsed_micros, (2+1) * kEpsilonMicros); |
| 247 |
| 248 // Now |d_1| is already readable. Try waiting for it again. |
| 249 { |
| 250 test::WaiterThread thread(d_1, |
| 251 MOJO_WAIT_FLAG_READABLE, |
| 252 MOJO_DEADLINE_INDEFINITE, |
| 253 1, |
| 254 &did_wait, &result); |
| 255 stopwatch.Start(); |
| 256 thread.Start(); |
| 257 } // Joins the thread. |
| 258 elapsed_micros = stopwatch.Elapsed(); |
| 259 EXPECT_FALSE(did_wait); |
| 260 EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, result); |
| 261 EXPECT_LT(elapsed_micros, kEpsilonMicros); |
| 262 |
| 263 // Consume what we wrote to |d_0|. |
| 264 buffer[0] = 0; |
| 265 buffer_size = kBufferSize; |
| 266 EXPECT_EQ(MOJO_RESULT_OK, |
| 267 d_1->ReadMessage(buffer, &buffer_size, |
| 268 NULL, NULL, |
| 269 MOJO_READ_MESSAGE_FLAG_NONE)); |
| 270 EXPECT_EQ(kBufferSize, buffer_size); |
| 271 EXPECT_EQ(123456789, buffer[0]); |
| 272 |
| 273 // Wait for readable on |d_1| and close |d_0| after some time, which should |
| 274 // cancel that wait. |
| 275 { |
| 276 test::WaiterThread thread(d_1, |
| 277 MOJO_WAIT_FLAG_READABLE, |
| 278 MOJO_DEADLINE_INDEFINITE, |
| 279 0, |
| 280 &did_wait, &result); |
| 281 stopwatch.Start(); |
| 282 thread.Start(); |
| 283 base::PlatformThread::Sleep( |
| 284 base::TimeDelta::FromMicroseconds(2 * kEpsilonMicros)); |
| 285 EXPECT_EQ(MOJO_RESULT_OK, d_0->Close()); |
| 286 } // Joins the thread. |
| 287 elapsed_micros = stopwatch.Elapsed(); |
| 288 EXPECT_TRUE(did_wait); |
| 289 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); |
| 290 EXPECT_GT(elapsed_micros, (2-1) * kEpsilonMicros); |
| 291 EXPECT_LT(elapsed_micros, (2+1) * kEpsilonMicros); |
| 292 |
| 293 EXPECT_EQ(MOJO_RESULT_OK, d_1->Close()); |
| 294 } |
| 295 |
| 296 for (unsigned i = 0; i < 2; i++) { |
| 297 scoped_refptr<MessagePipeDispatcher> d_0(new MessagePipeDispatcher()); |
| 298 scoped_refptr<MessagePipeDispatcher> d_1(new MessagePipeDispatcher()); |
| 299 { |
| 300 scoped_refptr<MessagePipe> mp(new MessagePipe()); |
| 301 d_0->Init(mp, i); // 0, 1. |
| 302 d_1->Init(mp, i ^ 1); // 1, 0. |
| 303 } |
| 304 |
| 305 // Wait for readable on |d_1| and close |d_1| after some time, which should |
| 306 // cancel that wait. |
| 307 { |
| 308 test::WaiterThread thread(d_1, |
| 309 MOJO_WAIT_FLAG_READABLE, |
| 310 MOJO_DEADLINE_INDEFINITE, |
| 311 0, |
| 312 &did_wait, &result); |
| 313 stopwatch.Start(); |
| 314 thread.Start(); |
| 315 base::PlatformThread::Sleep( |
| 316 base::TimeDelta::FromMicroseconds(2 * kEpsilonMicros)); |
| 317 EXPECT_EQ(MOJO_RESULT_OK, d_1->Close()); |
| 318 } // Joins the thread. |
| 319 elapsed_micros = stopwatch.Elapsed(); |
| 320 EXPECT_TRUE(did_wait); |
| 321 EXPECT_EQ(MOJO_RESULT_CANCELLED, result); |
| 322 EXPECT_GT(elapsed_micros, (2-1) * kEpsilonMicros); |
| 323 EXPECT_LT(elapsed_micros, (2+1) * kEpsilonMicros); |
| 324 |
| 325 EXPECT_EQ(MOJO_RESULT_OK, d_0->Close()); |
| 326 } |
| 327 } |
| 328 |
| 329 // TODO(vtl): Actually read/write on threads? |
| 330 // TODO(vtl): Stress test? |
| 331 |
| 332 } // namespace |
| 333 } // namespace system |
| 334 } // namespace mojo |
OLD | NEW |