Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(386)

Side by Side Diff: Source/modules/fetch/CompositeDataConsumerHandleTest.cpp

Issue 1162043007: Introduce CompositeDataConsumerHandle. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 MockReader : public WebDataConsumerHandle::Reader {
43 public:
44 static PassOwnPtr<StrictMock<MockReader>> create() { return adoptPtr(new Str ictMock<MockReader>); }
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 };
50
51 class MockHandle : public WebDataConsumerHandle {
52 public:
53 static PassOwnPtr<StrictMock<MockHandle>> create() { return adoptPtr(new Str ictMock<MockHandle>); }
54
55 MOCK_METHOD1(obtainReaderInternal, Reader*(Client*));
56 };
57
58 class ThreadingTestBase : public ThreadSafeRefCounted<ThreadingTestBase> {
59 public:
60 class Context : public ThreadSafeRefCounted<Context> {
61 public:
62 static PassRefPtr<Context> create() { return adoptRef(new Context); }
63 void recordAttach(const String& handle)
64 {
65 MutexLocker locker(m_loggingMutex);
66 m_result.append("A reader is attached to " + handle.isolatedCopy() + " on " + threadName() + ".\n");
67 }
68 void recordDetach(const String& handle)
69 {
70 MutexLocker locker(m_loggingMutex);
71 m_result.append("A reader is detached from " + handle.isolatedCopy() + " on " + threadName() + ".\n");
72 }
73
74 const String& result()
75 {
76 MutexLocker locker(m_loggingMutex);
77 return m_result;
78 }
79 WebThread* readingThread() { return m_readingThread.get(); }
80 WebThread* updatingThread() { return m_updatingThread.get(); }
81
82 private:
83 Context()
84 {
85 m_readingThread = adoptPtr(Platform::current()->createThread("readin g thread"));
86 m_updatingThread = adoptPtr(Platform::current()->createThread("updat ing thread"));
87 }
88 String threadName()
89 {
90 if (m_readingThread->isCurrentThread())
91 return "the reading thread";
92 if (m_updatingThread->isCurrentThread())
93 return "the updating thread";
94 return "an unknown thread";
95 }
96
97 OwnPtr<WebThread> m_readingThread;
98 OwnPtr<WebThread> m_updatingThread;
99 Mutex m_loggingMutex;
100 String m_result;
101 };
102
103 class ReaderImpl final : public WebDataConsumerHandle::Reader {
104 public:
105 ReaderImpl(const String& name, PassRefPtr<Context> context) : m_name(nam e.isolatedCopy()), m_context(context)
106 {
107 m_context->recordAttach(m_name);
108 }
109 ~ReaderImpl() override { m_context->recordDetach(m_name); }
110 Result read(void*, size_t, Flags, size_t*) override { return kShouldWait ; }
111 Result beginRead(const void**, Flags, size_t*) override { return kShould Wait; }
112 Result endRead(size_t) override { return kUnexpectedError; }
113
114 private:
115 const String m_name;
116 RefPtr<Context> m_context;
117 };
118 class DataConsumerHandle final : public WebDataConsumerHandle {
119 public:
120 DataConsumerHandle(const String& name, PassRefPtr<Context> context) : m_ name(name.isolatedCopy()), m_context(context) { }
121
122 private:
123 Reader* obtainReaderInternal(Client*) { return new ReaderImpl(m_name, m_ context); }
124 const String m_name;
125 RefPtr<Context> m_context;
126 };
127
128 void resetReader() { m_reader = nullptr; }
129 void signalDone() { m_waitableEvent->signal(); }
130 const String& result() { return m_context->result(); }
131 WebThread* readingThread() { return m_context->readingThread(); }
132 WebThread* updatingThread() { return m_context->updatingThread(); }
133
134 protected:
135 RefPtr<Context> m_context;
136 OwnPtr<CompositeDataConsumerHandle> m_handle;
137 OwnPtr<WebDataConsumerHandle::Reader> m_reader;
138 OwnPtr<WebWaitableEvent> m_waitableEvent;
139 NoopClient m_client;
140 };
141
142 class ThreadingRegistrationTest : public ThreadingTestBase {
143 public:
144 using Self = ThreadingRegistrationTest;
145 void run()
146 {
147 m_context = Context::create();
148 m_waitableEvent = adoptPtr(Platform::current()->createWaitableEvent());
149 m_handle = CompositeDataConsumerHandle::create(adoptPtr(new DataConsumer Handle("handle1", m_context)));
150
151 readingThread()->postTask(FROM_HERE, new Task(threadSafeBind(&Self::obta inReader, this)));
152
153 m_waitableEvent->wait();
154 }
155
156 private:
157 void obtainReader()
158 {
159 m_reader = m_handle->obtainReader(&m_client);
160 updatingThread()->postTask(FROM_HERE, new Task(threadSafeBind(&Self::upd ate, this)));
161 }
162 void update()
163 {
164 m_handle->update(adoptPtr(new DataConsumerHandle("handle2", m_context))) ;
165 readingThread()->postTask(FROM_HERE, new Task(threadSafeBind(&Self::rese tReader, this)));
166 readingThread()->postTask(FROM_HERE, new Task(threadSafeBind(&Self::sign alDone, this)));
167 }
168 };
169
170 class ThreadingRegistrationDeleteHandleTest : public ThreadingTestBase {
171 public:
172 using Self = ThreadingRegistrationDeleteHandleTest;
173 void run()
174 {
175 m_context = Context::create();
176 m_waitableEvent = adoptPtr(Platform::current()->createWaitableEvent());
177 m_handle = CompositeDataConsumerHandle::create(adoptPtr(new DataConsumer Handle("handle1", m_context)));
178
179 readingThread()->postTask(FROM_HERE, new Task(threadSafeBind(&Self::obta inReader, this)));
180
181 m_waitableEvent->wait();
182 }
183
184 private:
185 void obtainReader()
186 {
187 m_reader = m_handle->obtainReader(&m_client);
188 updatingThread()->postTask(FROM_HERE, new Task(threadSafeBind(&Self::upd ate, this)));
189 }
190 void update()
191 {
192 m_handle->update(adoptPtr(new DataConsumerHandle("handle2", m_context))) ;
193 m_handle = nullptr;
194 readingThread()->postTask(FROM_HERE, new Task(threadSafeBind(&Self::rese tReader, this)));
195 readingThread()->postTask(FROM_HERE, new Task(threadSafeBind(&Self::sign alDone, this)));
196 }
197 };
198
199 class ThreadingRegistrationDeleteReaderTest : public ThreadingTestBase {
200 public:
201 using Self = ThreadingRegistrationDeleteReaderTest;
202 void run()
203 {
204 m_context = Context::create();
205 m_waitableEvent = adoptPtr(Platform::current()->createWaitableEvent());
206 m_handle = CompositeDataConsumerHandle::create(adoptPtr(new DataConsumer Handle("handle1", m_context)));
207
208 readingThread()->postTask(FROM_HERE, new Task(threadSafeBind(&Self::obta inReader, this)));
209
210 m_waitableEvent->wait();
211 }
212
213 private:
214 void obtainReader()
215 {
216 m_reader = m_handle->obtainReader(&m_client);
217 updatingThread()->postTask(FROM_HERE, new Task(threadSafeBind(&Self::upd ate, this)));
218 }
219 void update()
220 {
221 readingThread()->postTask(FROM_HERE, new Task(threadSafeBind(&Self::rese tReader, this)));
222 m_handle->update(adoptPtr(new DataConsumerHandle("handle2", m_context))) ;
223 readingThread()->postTask(FROM_HERE, new Task(threadSafeBind(&Self::rese tReader, this)));
224 readingThread()->postTask(FROM_HERE, new Task(threadSafeBind(&Self::sign alDone, this)));
225 }
226 };
227
228 class ThreadingRegistrationUpdateTwiceAtOneTimeTest : public ThreadingTestBase {
229 public:
230 using Self = ThreadingRegistrationUpdateTwiceAtOneTimeTest;
231 void run()
232 {
233 m_context = Context::create();
234 m_waitableEvent = adoptPtr(Platform::current()->createWaitableEvent());
235 m_handle = CompositeDataConsumerHandle::create(adoptPtr(new DataConsumer Handle("handle1", m_context)));
236
237 readingThread()->postTask(FROM_HERE, new Task(threadSafeBind(&Self::obta inReader, this)));
238
239 m_waitableEvent->wait();
240 }
241
242 private:
243 void obtainReader()
244 {
245 m_reader = m_handle->obtainReader(&m_client);
246 updatingThread()->postTask(FROM_HERE, new Task(threadSafeBind(&Self::upd ate, this)));
247 }
248 void update()
249 {
250 m_handle->update(adoptPtr(new DataConsumerHandle("handle2", m_context))) ;
251 m_handle->update(adoptPtr(new DataConsumerHandle("handle3", m_context))) ;
252 readingThread()->postTask(FROM_HERE, new Task(threadSafeBind(&Self::rese tReader, this)));
253 readingThread()->postTask(FROM_HERE, new Task(threadSafeBind(&Self::sign alDone, this)));
254 }
255 };
256
257 class ThreadingDoneHandleNotificationTest : public ThreadingTestBase, public Web DataConsumerHandle::Client {
258 public:
259 using Self = ThreadingDoneHandleNotificationTest;
260 void run()
261 {
262 m_context = Context::create();
263 m_waitableEvent = adoptPtr(Platform::current()->createWaitableEvent());
264 m_handle = CompositeDataConsumerHandle::create(CompositeDataConsumerHand le::createDoneHandle());
265
266 readingThread()->postTask(FROM_HERE, new Task(threadSafeBind(&Self::obta inReader, this)));
267
268 m_waitableEvent->wait();
269 }
270
271 private:
272 void obtainReader()
273 {
274 m_reader = m_handle->obtainReader(this);
275 }
276 void didGetReadable() override
277 {
278 readingThread()->postTask(FROM_HERE, new Task(threadSafeBind(&Self::sign alDone, this)));
279 }
280 };
281
282 TEST(CompositeDataConsumerHandleTest, CreateWaitingHandle)
283 {
284 char buffer[20];
285 const void* p = nullptr;
286 size_t size = 0;
287 OwnPtr<WebDataConsumerHandle> handle = CompositeDataConsumerHandle::createWa itingHandle();
288 OwnPtr<WebDataConsumerHandle::Reader> reader = handle->obtainReader(nullptr) ;
289
290 EXPECT_EQ(kShouldWait, reader->read(buffer, sizeof(buffer), kNone, &size));
291 EXPECT_EQ(kShouldWait, reader->beginRead(&p, kNone, &size));
292 EXPECT_EQ(kUnexpectedError, reader->endRead(99));
293 }
294
295 TEST(CompositeDataConsumerHandleTest, CreateDoneHandle)
296 {
297 char buffer[20];
298 const void* p = nullptr;
299 size_t size = 0;
300 OwnPtr<WebDataConsumerHandle> handle = CompositeDataConsumerHandle::createDo neHandle();
301 OwnPtr<WebDataConsumerHandle::Reader> reader = handle->obtainReader(nullptr) ;
302
303 EXPECT_EQ(kDone, reader->read(buffer, sizeof(buffer), kNone, &size));
304 EXPECT_EQ(kDone, reader->beginRead(&p, kNone, &size));
305 EXPECT_EQ(kUnexpectedError, reader->endRead(99));
306 (void)kOk;
307 }
308
309 TEST(CompositeDataConsumerHandleTest, Read)
310 {
311 char buffer[20];
312 size_t size = 0;
313 NoopClient client;
314 Checkpoint checkpoint;
315
316 OwnPtr<MockHandle> handle1 = MockHandle::create();
317 OwnPtr<MockHandle> handle2 = MockHandle::create();
318 OwnPtr<MockReader> reader1 = MockReader::create();
319 OwnPtr<MockReader> reader2 = MockReader::create();
320
321 InSequence s;
322 EXPECT_CALL(checkpoint, Call(0));
323 EXPECT_CALL(*handle1, obtainReaderInternal(&client)).WillOnce(Return(reader1 .get()));
324 EXPECT_CALL(checkpoint, Call(1));
325 EXPECT_CALL(*reader1, read(buffer, sizeof(buffer), kNone, &size)).WillOnce(R eturn(kOk));
326 EXPECT_CALL(checkpoint, Call(2));
327 EXPECT_CALL(*handle2, obtainReaderInternal(&client)).WillOnce(Return(reader2 .get()));
328 EXPECT_CALL(checkpoint, Call(3));
329 EXPECT_CALL(*reader2, read(buffer, sizeof(buffer), kNone, &size)).WillOnce(R eturn(kOk));
330 EXPECT_CALL(checkpoint, Call(4));
331
332 // They are adopted by |obtainReader|.
333 (void)reader1.leakPtr();
334 (void)reader2.leakPtr();
335
336 OwnPtr<CompositeDataConsumerHandle> handle = CompositeDataConsumerHandle::cr eate(handle1.release());
337 checkpoint.Call(0);
338 OwnPtr<CompositeDataConsumerHandle::Reader> reader = handle->obtainReader(&c lient);
339 checkpoint.Call(1);
340 EXPECT_EQ(kOk, reader->read(buffer, sizeof(buffer), kNone, &size));
341 checkpoint.Call(2);
342 handle->update(handle2.release());
343 checkpoint.Call(3);
344 EXPECT_EQ(kOk, reader->read(buffer, sizeof(buffer), kNone, &size));
345 checkpoint.Call(4);
346 }
347
348 TEST(CompositeDataConsumerHandleTest, TwoPhaseRead)
349 {
350 const void* p = nullptr;
351 size_t size = 0;
352 Checkpoint checkpoint;
353
354 OwnPtr<MockHandle> handle1 = MockHandle::create();
355 OwnPtr<MockHandle> handle2 = MockHandle::create();
356 OwnPtr<MockReader> reader1 = MockReader::create();
357 OwnPtr<MockReader> reader2 = MockReader::create();
358
359 InSequence s;
360 EXPECT_CALL(checkpoint, Call(0));
361 EXPECT_CALL(*handle1, obtainReaderInternal(nullptr)).WillOnce(Return(reader1 .get()));
362 EXPECT_CALL(checkpoint, Call(1));
363 EXPECT_CALL(*reader1, beginRead(&p, kNone, &size)).WillOnce(Return(kOk));
364 EXPECT_CALL(checkpoint, Call(2));
365 EXPECT_CALL(*reader1, endRead(0)).WillOnce(Return(kOk));
366 EXPECT_CALL(checkpoint, Call(3));
367 EXPECT_CALL(*handle2, obtainReaderInternal(nullptr)).WillOnce(Return(reader2 .get()));
368 EXPECT_CALL(checkpoint, Call(4));
369 EXPECT_CALL(*reader2, beginRead(&p, kNone, &size)).WillOnce(Return(kOk));
370 EXPECT_CALL(checkpoint, Call(5));
371 EXPECT_CALL(*reader2, endRead(0)).WillOnce(Return(kOk));
372 EXPECT_CALL(checkpoint, Call(6));
373
374 // They are adopted by |obtainReader|.
375 (void)reader1.leakPtr();
376 (void)reader2.leakPtr();
377
378 OwnPtr<CompositeDataConsumerHandle> handle = CompositeDataConsumerHandle::cr eate(handle1.release());
379 checkpoint.Call(0);
380 OwnPtr<CompositeDataConsumerHandle::Reader> reader = handle->obtainReader(nu llptr);
381 checkpoint.Call(1);
382 EXPECT_EQ(kOk, reader->beginRead(&p, kNone, &size));
383 checkpoint.Call(2);
384 EXPECT_EQ(kOk, reader->endRead(0));
385 checkpoint.Call(3);
386 handle->update(handle2.release());
387 checkpoint.Call(4);
388 EXPECT_EQ(kOk, reader->beginRead(&p, kNone, &size));
389 checkpoint.Call(5);
390 EXPECT_EQ(kOk, reader->endRead(0));
391 checkpoint.Call(6);
392 }
393
394 TEST(CompositeDataConsumerHandleTest, HangingTwoPhaseRead)
395 {
396 const void* p = nullptr;
397 size_t size = 0;
398 Checkpoint checkpoint;
399
400 OwnPtr<MockHandle> handle1 = MockHandle::create();
401 OwnPtr<MockHandle> handle2 = MockHandle::create();
402 OwnPtr<MockReader> reader1 = MockReader::create();
403 OwnPtr<MockReader> reader2 = MockReader::create();
404
405 InSequence s;
406 EXPECT_CALL(checkpoint, Call(0));
407 EXPECT_CALL(*handle1, obtainReaderInternal(nullptr)).WillOnce(Return(reader1 .get()));
408 EXPECT_CALL(checkpoint, Call(1));
409 EXPECT_CALL(*reader1, beginRead(&p, kNone, &size)).WillOnce(Return(kOk));
410 EXPECT_CALL(checkpoint, Call(2));
411 EXPECT_CALL(checkpoint, Call(3));
412 EXPECT_CALL(*reader1, endRead(0)).WillOnce(Return(kOk));
413 EXPECT_CALL(*handle2, obtainReaderInternal(nullptr)).WillOnce(Return(reader2 .get()));
414 EXPECT_CALL(checkpoint, Call(4));
415 EXPECT_CALL(*reader2, beginRead(&p, kNone, &size)).WillOnce(Return(kOk));
416 EXPECT_CALL(checkpoint, Call(5));
417 EXPECT_CALL(*reader2, endRead(0)).WillOnce(Return(kOk));
418 EXPECT_CALL(checkpoint, Call(6));
419
420 // They are adopted by |obtainReader|.
421 (void)reader1.leakPtr();
422 (void)reader2.leakPtr();
423
424 OwnPtr<CompositeDataConsumerHandle> handle = CompositeDataConsumerHandle::cr eate(handle1.release());
425 checkpoint.Call(0);
426 OwnPtr<CompositeDataConsumerHandle::Reader> reader = handle->obtainReader(nu llptr);
427 checkpoint.Call(1);
428 EXPECT_EQ(kOk, reader->beginRead(&p, kNone, &size));
429 checkpoint.Call(2);
430 handle->update(handle2.release());
431 checkpoint.Call(3);
432 EXPECT_EQ(kOk, reader->endRead(0));
433 checkpoint.Call(4);
434 EXPECT_EQ(kOk, reader->beginRead(&p, kNone, &size));
435 checkpoint.Call(5);
436 EXPECT_EQ(kOk, reader->endRead(0));
437 checkpoint.Call(6);
438
439 }
440
441 TEST(CompositeDataConsumerHandleTest, RegisterClientOnDifferentThreads)
442 {
443 ThreadingRegistrationTest test;
444 test.run();
445
446 EXPECT_EQ(
447 "A reader is attached to handle1 on the reading thread.\n"
448 "A reader is detached from handle1 on the reading thread.\n"
449 "A reader is attached to handle2 on the reading thread.\n"
450 "A reader is detached from handle2 on the reading thread.\n",
451 test.result());
452 }
453
454 TEST(CompositeDataConsumerHandleTest, DeleteHandleWhileUpdating)
455 {
456 ThreadingRegistrationDeleteHandleTest test;
457 test.run();
458
459 EXPECT_EQ(
460 "A reader is attached to handle1 on the reading thread.\n"
461 "A reader is detached from handle1 on the reading thread.\n"
462 "A reader is attached to handle2 on the reading thread.\n"
463 "A reader is detached from handle2 on the reading thread.\n",
464 test.result());
465 }
466
467 TEST(CompositeDataConsumerHandleTest, DeleteReaderWhileUpdating)
468 {
469 ThreadingRegistrationDeleteReaderTest test;
470 test.run();
471
472 EXPECT_EQ(
473 "A reader is attached to handle1 on the reading thread.\n"
474 "A reader is detached from handle1 on the reading thread.\n",
475 test.result());
476 }
477
478 TEST(CompositeDataConsumerHandleTest, UpdateTwiceAtOnce)
479 {
480 ThreadingRegistrationUpdateTwiceAtOneTimeTest test;
481 test.run();
482
483 EXPECT_EQ(
484 "A reader is attached to handle1 on the reading thread.\n"
485 "A reader is detached from handle1 on the reading thread.\n"
486 "A reader is attached to handle3 on the reading thread.\n"
487 "A reader is detached from handle3 on the reading thread.\n",
488 test.result());
489 }
490
491 TEST(CompositeDataConsumerHandleTest, DoneHandleNotification)
492 {
493 ThreadingDoneHandleNotificationTest test;
494 // Test this function returns.
495 test.run();
496 }
497
498 } // namespace
499
500 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698