| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2015 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 "config.h" |
| 6 #include "modules/fetch/CompositeDataConsumerHandle.h" |
| 7 |
| 8 #include "platform/Task.h" |
| 9 #include "platform/ThreadSafeFunctional.h" |
| 10 #include "platform/heap/Handle.h" |
| 11 #include "public/platform/Platform.h" |
| 12 #include "public/platform/WebThread.h" |
| 13 #include "public/platform/WebTraceLocation.h" |
| 14 #include "public/platform/WebWaitableEvent.h" |
| 15 #include "wtf/Locker.h" |
| 16 |
| 17 #include <gmock/gmock.h> |
| 18 #include <gtest/gtest.h> |
| 19 |
| 20 namespace blink { |
| 21 |
| 22 namespace { |
| 23 |
| 24 using Result = WebDataConsumerHandle::Result; |
| 25 using Flags = WebDataConsumerHandle::Flags; |
| 26 using ::testing::InSequence; |
| 27 using ::testing::Return; |
| 28 using ::testing::StrictMock; |
| 29 using Checkpoint = StrictMock<::testing::MockFunction<void(int)>>; |
| 30 |
| 31 const Result kShouldWait = WebDataConsumerHandle::ShouldWait; |
| 32 const Result kDone = WebDataConsumerHandle::Done; |
| 33 const Result kOk = WebDataConsumerHandle::Ok; |
| 34 const Result kUnexpectedError = WebDataConsumerHandle::UnexpectedError; |
| 35 const Flags kNone = WebDataConsumerHandle::FlagNone; |
| 36 |
| 37 class NoopClient final : public WebDataConsumerHandle::Client { |
| 38 public: |
| 39 void didGetReadable() override { } |
| 40 }; |
| 41 |
| 42 class MockHandle : public WebDataConsumerHandle { |
| 43 public: |
| 44 static PassOwnPtr<StrictMock<MockHandle>> create() { return adoptPtr(new Str
ictMock<MockHandle>); } |
| 45 |
| 46 MOCK_METHOD4(read, Result(void*, size_t, Flags, size_t*)); |
| 47 MOCK_METHOD3(beginRead, Result(const void**, Flags, size_t*)); |
| 48 MOCK_METHOD1(endRead, Result(size_t)); |
| 49 MOCK_METHOD1(registerClient, void(Client*)); |
| 50 MOCK_METHOD0(unregisterClient, void()); |
| 51 }; |
| 52 |
| 53 class ThreadingTestBase { |
| 54 public: |
| 55 class DataConsumerHandle final : public WebDataConsumerHandle { |
| 56 public: |
| 57 DataConsumerHandle(const String& name, ThreadingTestBase* test) : m_name
(name.isolatedCopy()), m_test(test) { } |
| 58 Result read(void*, size_t, Flags, size_t*) override { return ShouldWait;
} |
| 59 Result beginRead(const void**, Flags, size_t*) override { return ShouldW
ait; } |
| 60 Result endRead(size_t) override { return ShouldWait; } |
| 61 void registerClient(Client*) override |
| 62 { |
| 63 m_test->record(m_name, "registerClient"); |
| 64 } |
| 65 void unregisterClient() override |
| 66 { |
| 67 m_test->record(m_name, "unregisterClient"); |
| 68 } |
| 69 private: |
| 70 const String m_name; |
| 71 ThreadingTestBase* m_test; |
| 72 }; |
| 73 |
| 74 void record(const String& instanceName, const String& functionName) |
| 75 { |
| 76 String threadName; |
| 77 if (m_readingThread->isCurrentThread()) { |
| 78 threadName = "the reading thread"; |
| 79 } else if (m_updatingThread->isCurrentThread()) { |
| 80 threadName = "the updating thread"; |
| 81 } else { |
| 82 threadName = "an unknown thread"; |
| 83 } |
| 84 MutexLocker locker(m_loggingMutex); |
| 85 m_result.append(instanceName.isolatedCopy() + "->" + functionName.isolat
edCopy() + " is called on " + threadName + ".\n"); |
| 86 } |
| 87 const String& result() |
| 88 { |
| 89 MutexLocker locker(m_loggingMutex); |
| 90 return m_result; |
| 91 } |
| 92 |
| 93 static void signalDone(ThreadingTestBase* test) |
| 94 { |
| 95 test->m_waitableEvent->signal(); |
| 96 } |
| 97 |
| 98 protected: |
| 99 OwnPtr<WebThread> m_readingThread; |
| 100 OwnPtr<WebThread> m_updatingThread; |
| 101 OwnPtr<CompositeDataConsumerHandle> m_handle; |
| 102 NoopClient m_client; |
| 103 OwnPtr<WebWaitableEvent> m_waitableEvent; |
| 104 Mutex m_loggingMutex; |
| 105 String m_result; |
| 106 }; |
| 107 |
| 108 class ThreadingRegistrationTest : public ThreadingTestBase { |
| 109 public: |
| 110 void run() |
| 111 { |
| 112 m_readingThread = adoptPtr(Platform::current()->createThread("reading th
read")); |
| 113 m_updatingThread = adoptPtr(Platform::current()->createThread("updating
thread")); |
| 114 m_waitableEvent = adoptPtr(Platform::current()->createWaitableEvent()); |
| 115 m_handle = CompositeDataConsumerHandle::create(adoptPtr(new DataConsumer
Handle("handle1", this))); |
| 116 |
| 117 m_readingThread->postTask(FROM_HERE, new Task(threadSafeBind(®isterCl
ient, AllowCrossThreadAccess(this)))); |
| 118 |
| 119 m_waitableEvent->wait(); |
| 120 } |
| 121 |
| 122 private: |
| 123 static void registerClient(ThreadingRegistrationTest* test) |
| 124 { |
| 125 test->m_handle->registerClient(&test->m_client); |
| 126 test->m_updatingThread->postTask(FROM_HERE, new Task(threadSafeBind(&upd
ate, AllowCrossThreadAccess(test)))); |
| 127 } |
| 128 static void update(ThreadingRegistrationTest* test) |
| 129 { |
| 130 test->m_handle->update(adoptPtr(new DataConsumerHandle("handle2", test))
); |
| 131 test->m_readingThread->postTask(FROM_HERE, new Task(threadSafeBind(&sign
alDone, AllowCrossThreadAccess(test)))); |
| 132 } |
| 133 }; |
| 134 |
| 135 class ThreadingRegistrationDeleteTest : public ThreadingTestBase { |
| 136 public: |
| 137 void run() |
| 138 { |
| 139 m_readingThread = adoptPtr(Platform::current()->createThread("reading th
read")); |
| 140 m_updatingThread = adoptPtr(Platform::current()->createThread("updating
thread")); |
| 141 m_waitableEvent = adoptPtr(Platform::current()->createWaitableEvent()); |
| 142 m_handle = CompositeDataConsumerHandle::create(adoptPtr(new DataConsumer
Handle("handle1", this))); |
| 143 |
| 144 m_readingThread->postTask(FROM_HERE, new Task(threadSafeBind(®isterCl
ient, AllowCrossThreadAccess(this)))); |
| 145 |
| 146 m_waitableEvent->wait(); |
| 147 } |
| 148 |
| 149 private: |
| 150 static void registerClient(ThreadingRegistrationDeleteTest* test) |
| 151 { |
| 152 test->m_handle->registerClient(&test->m_client); |
| 153 test->m_updatingThread->postTask(FROM_HERE, new Task(threadSafeBind(&upd
ate, AllowCrossThreadAccess(test)))); |
| 154 } |
| 155 static void update(ThreadingRegistrationDeleteTest* test) |
| 156 { |
| 157 test->m_handle->update(adoptPtr(new DataConsumerHandle("handle2", test))
); |
| 158 test->m_handle.clear(); |
| 159 test->m_readingThread->postTask(FROM_HERE, new Task(threadSafeBind(&sign
alDone, AllowCrossThreadAccess(test)))); |
| 160 } |
| 161 }; |
| 162 |
| 163 TEST(CompositeDataConsumerHandleTest, CreateWaitingHandle) |
| 164 { |
| 165 char buffer[20]; |
| 166 const void* p = nullptr; |
| 167 size_t size = 0; |
| 168 OwnPtr<WebDataConsumerHandle> handle = CompositeDataConsumerHandle::createWa
itingHandle(); |
| 169 |
| 170 EXPECT_EQ(kShouldWait, handle->read(buffer, sizeof(buffer), kNone, &size)); |
| 171 EXPECT_EQ(kShouldWait, handle->beginRead(&p, kNone, &size)); |
| 172 EXPECT_EQ(kUnexpectedError, handle->endRead(99)); |
| 173 } |
| 174 |
| 175 TEST(CompositeDataConsumerHandleTest, CreateDoneHandle) |
| 176 { |
| 177 char buffer[20]; |
| 178 const void* p = nullptr; |
| 179 size_t size = 0; |
| 180 OwnPtr<WebDataConsumerHandle> handle = CompositeDataConsumerHandle::createDo
neHandle(); |
| 181 |
| 182 EXPECT_EQ(kDone, handle->read(buffer, sizeof(buffer), kNone, &size)); |
| 183 EXPECT_EQ(kDone, handle->beginRead(&p, kNone, &size)); |
| 184 EXPECT_EQ(kUnexpectedError, handle->endRead(99)); |
| 185 } |
| 186 |
| 187 TEST(CompositeDataConsumerHandleTest, Read) |
| 188 { |
| 189 char buffer[20]; |
| 190 size_t size = 0; |
| 191 Checkpoint checkpoint; |
| 192 |
| 193 OwnPtr<MockHandle> handle1 = MockHandle::create(); |
| 194 OwnPtr<MockHandle> handle2 = MockHandle::create(); |
| 195 |
| 196 InSequence s; |
| 197 EXPECT_CALL(checkpoint, Call(0)); |
| 198 EXPECT_CALL(*handle1, read(buffer, sizeof(buffer), kNone, &size)).WillOnce(R
eturn(kOk)); |
| 199 EXPECT_CALL(checkpoint, Call(1)); |
| 200 EXPECT_CALL(checkpoint, Call(2)); |
| 201 EXPECT_CALL(*handle2, read(buffer, sizeof(buffer), kNone, &size)).WillOnce(R
eturn(kOk)); |
| 202 EXPECT_CALL(checkpoint, Call(3)); |
| 203 |
| 204 OwnPtr<CompositeDataConsumerHandle> handle = CompositeDataConsumerHandle::cr
eate(handle1.release()); |
| 205 checkpoint.Call(0); |
| 206 EXPECT_EQ(kOk, handle->read(buffer, sizeof(buffer), kNone, &size)); |
| 207 checkpoint.Call(1); |
| 208 handle->update(handle2.release()); |
| 209 checkpoint.Call(2); |
| 210 EXPECT_EQ(kOk, handle->read(buffer, sizeof(buffer), kNone, &size)); |
| 211 checkpoint.Call(3); |
| 212 } |
| 213 |
| 214 TEST(CompositeDataConsumerHandleTest, TwoPhaseRead) |
| 215 { |
| 216 const void* p = nullptr; |
| 217 size_t size = 0; |
| 218 Checkpoint checkpoint; |
| 219 |
| 220 OwnPtr<MockHandle> handle1 = MockHandle::create(); |
| 221 OwnPtr<MockHandle> handle2 = MockHandle::create(); |
| 222 |
| 223 InSequence s; |
| 224 EXPECT_CALL(checkpoint, Call(0)); |
| 225 EXPECT_CALL(*handle1, beginRead(&p, kNone, &size)).WillOnce(Return(kOk)); |
| 226 EXPECT_CALL(checkpoint, Call(1)); |
| 227 EXPECT_CALL(*handle1, endRead(0)).WillOnce(Return(kOk)); |
| 228 EXPECT_CALL(checkpoint, Call(2)); |
| 229 EXPECT_CALL(checkpoint, Call(3)); |
| 230 EXPECT_CALL(*handle2, beginRead(&p, kNone, &size)).WillOnce(Return(kOk)); |
| 231 EXPECT_CALL(checkpoint, Call(4)); |
| 232 EXPECT_CALL(*handle2, endRead(0)).WillOnce(Return(kOk)); |
| 233 EXPECT_CALL(checkpoint, Call(5)); |
| 234 |
| 235 OwnPtr<CompositeDataConsumerHandle> handle = CompositeDataConsumerHandle::cr
eate(handle1.release()); |
| 236 checkpoint.Call(0); |
| 237 EXPECT_EQ(kOk, handle->beginRead(&p, kNone, &size)); |
| 238 checkpoint.Call(1); |
| 239 EXPECT_EQ(kOk, handle->endRead(0)); |
| 240 checkpoint.Call(2); |
| 241 handle->update(handle2.release()); |
| 242 checkpoint.Call(3); |
| 243 EXPECT_EQ(kOk, handle->beginRead(&p, kNone, &size)); |
| 244 checkpoint.Call(4); |
| 245 EXPECT_EQ(kOk, handle->endRead(0)); |
| 246 checkpoint.Call(5); |
| 247 } |
| 248 |
| 249 TEST(CompositeDataConsumerHandleTest, ClientRegistration) |
| 250 { |
| 251 Checkpoint checkpoint; |
| 252 |
| 253 OwnPtr<MockHandle> handle1 = MockHandle::create(); |
| 254 OwnPtr<MockHandle> handle2 = MockHandle::create(); |
| 255 OwnPtr<MockHandle> handle3 = MockHandle::create(); |
| 256 NoopClient client; |
| 257 |
| 258 InSequence s; |
| 259 EXPECT_CALL(checkpoint, Call(0)); |
| 260 EXPECT_CALL(*handle1, registerClient(&client)); |
| 261 EXPECT_CALL(checkpoint, Call(1)); |
| 262 EXPECT_CALL(*handle1, unregisterClient()); |
| 263 EXPECT_CALL(checkpoint, Call(2)); |
| 264 EXPECT_CALL(*handle1, registerClient(&client)); |
| 265 EXPECT_CALL(checkpoint, Call(3)); |
| 266 EXPECT_CALL(*handle1, unregisterClient()); |
| 267 EXPECT_CALL(*handle2, registerClient(&client)); |
| 268 EXPECT_CALL(checkpoint, Call(4)); |
| 269 EXPECT_CALL(*handle2, unregisterClient()); |
| 270 EXPECT_CALL(checkpoint, Call(5)); |
| 271 EXPECT_CALL(checkpoint, Call(6)); |
| 272 |
| 273 OwnPtr<CompositeDataConsumerHandle> handle = CompositeDataConsumerHandle::cr
eate(handle1.release()); |
| 274 checkpoint.Call(0); |
| 275 handle->registerClient(&client); |
| 276 checkpoint.Call(1); |
| 277 handle->unregisterClient(); |
| 278 checkpoint.Call(2); |
| 279 handle->registerClient(&client); |
| 280 checkpoint.Call(3); |
| 281 handle->update(handle2.release()); |
| 282 checkpoint.Call(4); |
| 283 handle->unregisterClient(); |
| 284 checkpoint.Call(5); |
| 285 handle->update(handle3.release()); |
| 286 checkpoint.Call(6); |
| 287 } |
| 288 |
| 289 TEST(CompositeDataConsumerHandleTest, RegisterClientOnDifferentThreads) |
| 290 { |
| 291 ThreadingRegistrationTest test; |
| 292 test.run(); |
| 293 |
| 294 EXPECT_EQ( |
| 295 "handle1->registerClient is called on the reading thread.\n" |
| 296 "handle1->unregisterClient is called on the reading thread.\n" |
| 297 "handle2->registerClient is called on the reading thread.\n", |
| 298 test.result()); |
| 299 } |
| 300 |
| 301 TEST(CompositeDataConsumerHandleTest, DeleteHandleWhileUpdating) |
| 302 { |
| 303 ThreadingRegistrationDeleteTest test; |
| 304 test.run(); |
| 305 |
| 306 EXPECT_EQ( |
| 307 "handle1->registerClient is called on the reading thread.\n", |
| 308 test.result()); |
| 309 } |
| 310 |
| 311 } // namespace |
| 312 |
| 313 } // namespace blink |
| OLD | NEW |