1 // Copyright 2018 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 "third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h"
6
7 #include "base/run_loop.h"
8 #include "base/single_thread_task_runner.h"
9 #include "base/test/metrics/histogram_tester.h"
10 #include "base/test/simple_test_tick_clock.h"
11 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "third_party/blink/public/platform/platform.h"
14 #include "third_party/blink/renderer/platform/graphics/animation_worklet_mutator.h"
15 #include "third_party/blink/renderer/platform/graphics/compositor_mutator_client.h"
16 #include "third_party/blink/renderer/platform/heap/handle.h"
17 #include "third_party/blink/renderer/platform/heap/persistent.h"
18 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
19 #include "third_party/blink/renderer/platform/scheduler/public/thread.h"
20 #include "third_party/blink/renderer/platform/scheduler/public/thread_type.h"
21 #include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
22 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
23
24 #include <memory>
25
26 using ::testing::_;
27 using ::testing::AtLeast;
28 using ::testing::Mock;
29 using ::testing::Return;
30 using ::testing::Sequence;
31 using ::testing::StrictMock;
32 using ::testing::Truly;
33
34 // This test uses actual threads since mutator logic requires it. This means we
35 // have dependency on Blink platform to create threads.
36
37 namespace blink {
38 namespace {
39
CreateThread(const char * name)40 std::unique_ptr<Thread> CreateThread(const char* name) {
41 return Platform::Current()->CreateThread(
42 ThreadCreationParams(ThreadType::kTestThread).SetThreadNameForTest(name));
43 }
44
45 class MockAnimationWorkletMutator
46 : public GarbageCollected<MockAnimationWorkletMutator>,
47 public AnimationWorkletMutator {
48 USING_GARBAGE_COLLECTED_MIXIN(MockAnimationWorkletMutator);
49
50 public:
MockAnimationWorkletMutator(scoped_refptr<base::SingleThreadTaskRunner> expected_runner)51 MockAnimationWorkletMutator(
52 scoped_refptr<base::SingleThreadTaskRunner> expected_runner)
53 : expected_runner_(expected_runner) {}
54
~MockAnimationWorkletMutator()55 ~MockAnimationWorkletMutator() override {}
56
Mutate(std::unique_ptr<AnimationWorkletInput> input)57 std::unique_ptr<AnimationWorkletOutput> Mutate(
58 std::unique_ptr<AnimationWorkletInput> input) override {
59 return std::unique_ptr<AnimationWorkletOutput>(MutateRef(*input));
60 }
61
62 // Blocks the worklet thread by posting a task that will complete only when
63 // signaled. This blocking ensures that tests of async mutations do not
64 // encounter race conditions when validating queuing strategies.
BlockWorkletThread()65 void BlockWorkletThread() {
66 PostCrossThreadTask(
67 *expected_runner_, FROM_HERE,
68 CrossThreadBindOnce(
69 [](base::WaitableEvent* start_processing_event) {
70 start_processing_event->Wait();
71 },
72 WTF::CrossThreadUnretained(&start_processing_event_)));
73 }
74
UnblockWorkletThread()75 void UnblockWorkletThread() { start_processing_event_.Signal(); }
76
77 MOCK_CONST_METHOD0(GetWorkletId, int());
78 MOCK_METHOD1(MutateRef,
79 AnimationWorkletOutput*(const AnimationWorkletInput&));
80
81 scoped_refptr<base::SingleThreadTaskRunner> expected_runner_;
82 base::WaitableEvent start_processing_event_;
83 };
84
85 class MockCompositorMutatorClient : public CompositorMutatorClient {
86 public:
MockCompositorMutatorClient(std::unique_ptr<AnimationWorkletMutatorDispatcherImpl> mutator)87 MockCompositorMutatorClient(
88 std::unique_ptr<AnimationWorkletMutatorDispatcherImpl> mutator)
89 : CompositorMutatorClient(std::move(mutator)) {}
~MockCompositorMutatorClient()90 ~MockCompositorMutatorClient() override {}
91 // gmock cannot mock methods with move-only args so we forward it to ourself.
SetMutationUpdate(std::unique_ptr<cc::MutatorOutputState> output_state)92 void SetMutationUpdate(
93 std::unique_ptr<cc::MutatorOutputState> output_state) override {
94 SetMutationUpdateRef(output_state.get());
95 }
96
97 MOCK_METHOD1(SetMutationUpdateRef,
98 void(cc::MutatorOutputState* output_state));
99 };
100
101 class AnimationWorkletMutatorDispatcherImplTest : public ::testing::Test {
102 public:
SetUp()103 void SetUp() override {
104 auto mutator = std::make_unique<AnimationWorkletMutatorDispatcherImpl>(
105 /*main_thread_task_runner=*/true);
106 mutator_ = mutator.get();
107 client_ =
108 std::make_unique<::testing::StrictMock<MockCompositorMutatorClient>>(
109 std::move(mutator));
110 }
111
TearDown()112 void TearDown() override { mutator_ = nullptr; }
113
114 std::unique_ptr<::testing::StrictMock<MockCompositorMutatorClient>> client_;
115 AnimationWorkletMutatorDispatcherImpl* mutator_;
116 };
117
CreateTestMutatorInput()118 std::unique_ptr<AnimationWorkletDispatcherInput> CreateTestMutatorInput() {
119 AnimationWorkletInput::AddAndUpdateState state1{
120 {11, 1}, "test1", 5000, nullptr, nullptr};
121
122 AnimationWorkletInput::AddAndUpdateState state2{
123 {22, 2}, "test2", 5000, nullptr, nullptr};
124
125 auto input = std::make_unique<AnimationWorkletDispatcherInput>();
126 input->Add(std::move(state1));
127 input->Add(std::move(state2));
128
129 return input;
130 }
131
OnlyIncludesAnimation1(const AnimationWorkletInput & in)132 bool OnlyIncludesAnimation1(const AnimationWorkletInput& in) {
133 return in.added_and_updated_animations.size() == 1 &&
134 in.added_and_updated_animations[0].worklet_animation_id.animation_id ==
135 1;
136 }
137
TEST_F(AnimationWorkletMutatorDispatcherImplTest,RegisteredAnimatorShouldOnlyReceiveInputForItself)138 TEST_F(AnimationWorkletMutatorDispatcherImplTest,
139 RegisteredAnimatorShouldOnlyReceiveInputForItself) {
140 std::unique_ptr<Thread> first_thread = CreateThread("FirstThread");
141 MockAnimationWorkletMutator* first_mutator =
142 MakeGarbageCollected<MockAnimationWorkletMutator>(
143 first_thread->GetTaskRunner());
144
145 mutator_->RegisterAnimationWorkletMutator(
146 WrapCrossThreadPersistent(first_mutator), first_thread->GetTaskRunner());
147
148 EXPECT_CALL(*first_mutator, GetWorkletId())
149 .Times(AtLeast(1))
150 .WillRepeatedly(Return(11));
151 EXPECT_CALL(*first_mutator, MutateRef(Truly(OnlyIncludesAnimation1)))
152 .Times(1)
153 .WillOnce(Return(new AnimationWorkletOutput()));
154 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(1);
155 mutator_->MutateSynchronously(CreateTestMutatorInput());
156 }
157
TEST_F(AnimationWorkletMutatorDispatcherImplTest,RegisteredAnimatorShouldNotBeMutatedWhenNoInput)158 TEST_F(AnimationWorkletMutatorDispatcherImplTest,
159 RegisteredAnimatorShouldNotBeMutatedWhenNoInput) {
160 std::unique_ptr<Thread> first_thread = CreateThread("FirstThread");
161 MockAnimationWorkletMutator* first_mutator =
162 MakeGarbageCollected<MockAnimationWorkletMutator>(
163 first_thread->GetTaskRunner());
164
165 mutator_->RegisterAnimationWorkletMutator(
166 WrapCrossThreadPersistent(first_mutator), first_thread->GetTaskRunner());
167
168 EXPECT_CALL(*first_mutator, GetWorkletId())
169 .Times(AtLeast(1))
170 .WillRepeatedly(Return(11));
171 EXPECT_CALL(*first_mutator, MutateRef(_)).Times(0);
172 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(0);
173
174 AnimationWorkletInput::AddAndUpdateState state{
175 {22, 2}, "test2", 5000, nullptr, nullptr};
176
177 auto input = std::make_unique<AnimationWorkletDispatcherInput>();
178 input->Add(std::move(state));
179
180 mutator_->MutateSynchronously(std::move(input));
181 }
182
TEST_F(AnimationWorkletMutatorDispatcherImplTest,MutationUpdateIsNotInvokedWithNoRegisteredAnimators)183 TEST_F(AnimationWorkletMutatorDispatcherImplTest,
184 MutationUpdateIsNotInvokedWithNoRegisteredAnimators) {
185 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(0);
186 std::unique_ptr<AnimationWorkletDispatcherInput> input =
187 std::make_unique<AnimationWorkletDispatcherInput>();
188 mutator_->MutateSynchronously(std::move(input));
189 }
190
TEST_F(AnimationWorkletMutatorDispatcherImplTest,MutationUpdateIsNotInvokedWithNullOutput)191 TEST_F(AnimationWorkletMutatorDispatcherImplTest,
192 MutationUpdateIsNotInvokedWithNullOutput) {
193 // Create a thread to run mutator tasks.
194 std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread");
195 MockAnimationWorkletMutator* first_mutator =
196 MakeGarbageCollected<MockAnimationWorkletMutator>(
197 first_thread->GetTaskRunner());
198
199 mutator_->RegisterAnimationWorkletMutator(
200 WrapCrossThreadPersistent(first_mutator), first_thread->GetTaskRunner());
201
202 EXPECT_CALL(*first_mutator, GetWorkletId())
203 .Times(AtLeast(1))
204 .WillRepeatedly(Return(11));
205 EXPECT_CALL(*first_mutator, MutateRef(_)).Times(1).WillOnce(Return(nullptr));
206 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(0);
207 mutator_->MutateSynchronously(CreateTestMutatorInput());
208 }
209
TEST_F(AnimationWorkletMutatorDispatcherImplTest,MutationUpdateIsInvokedCorrectlyWithSingleRegisteredAnimator)210 TEST_F(AnimationWorkletMutatorDispatcherImplTest,
211 MutationUpdateIsInvokedCorrectlyWithSingleRegisteredAnimator) {
212 // Create a thread to run mutator tasks.
213 std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread");
214 MockAnimationWorkletMutator* first_mutator =
215 MakeGarbageCollected<MockAnimationWorkletMutator>(
216 first_thread->GetTaskRunner());
217
218 mutator_->RegisterAnimationWorkletMutator(
219 WrapCrossThreadPersistent(first_mutator), first_thread->GetTaskRunner());
220
221 EXPECT_CALL(*first_mutator, GetWorkletId())
222 .Times(AtLeast(1))
223 .WillRepeatedly(Return(11));
224 EXPECT_CALL(*first_mutator, MutateRef(_))
225 .Times(1)
226 .WillOnce(Return(new AnimationWorkletOutput()));
227 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(1);
228 mutator_->MutateSynchronously(CreateTestMutatorInput());
229
230 // The above call blocks on mutator threads running their tasks so we can
231 // safely verify here.
232 Mock::VerifyAndClearExpectations(client_.get());
233
234 // Ensure mutator is not invoked after unregistration.
235 EXPECT_CALL(*first_mutator, MutateRef(_)).Times(0);
236 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(0);
237 mutator_->UnregisterAnimationWorkletMutator(
238 WrapCrossThreadPersistent(first_mutator));
239
240 mutator_->MutateSynchronously(CreateTestMutatorInput());
241 Mock::VerifyAndClearExpectations(client_.get());
242 }
243
TEST_F(AnimationWorkletMutatorDispatcherImplTest,MutationUpdateInvokedCorrectlyWithTwoRegisteredAnimatorsOnSameThread)244 TEST_F(AnimationWorkletMutatorDispatcherImplTest,
245 MutationUpdateInvokedCorrectlyWithTwoRegisteredAnimatorsOnSameThread) {
246 std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread");
247 MockAnimationWorkletMutator* first_mutator =
248 MakeGarbageCollected<MockAnimationWorkletMutator>(
249 first_thread->GetTaskRunner());
250 MockAnimationWorkletMutator* second_mutator =
251 MakeGarbageCollected<MockAnimationWorkletMutator>(
252 first_thread->GetTaskRunner());
253
254 mutator_->RegisterAnimationWorkletMutator(
255 WrapCrossThreadPersistent(first_mutator), first_thread->GetTaskRunner());
256 mutator_->RegisterAnimationWorkletMutator(
257 WrapCrossThreadPersistent(second_mutator), first_thread->GetTaskRunner());
258
259 EXPECT_CALL(*first_mutator, GetWorkletId())
260 .Times(AtLeast(1))
261 .WillRepeatedly(Return(11));
262 EXPECT_CALL(*first_mutator, MutateRef(_))
263 .Times(1)
264 .WillOnce(Return(new AnimationWorkletOutput()));
265 EXPECT_CALL(*second_mutator, GetWorkletId())
266 .Times(AtLeast(1))
267 .WillRepeatedly(Return(22));
268 EXPECT_CALL(*second_mutator, MutateRef(_))
269 .Times(1)
270 .WillOnce(Return(new AnimationWorkletOutput()));
271 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(2);
272 mutator_->MutateSynchronously(CreateTestMutatorInput());
273 }
274
TEST_F(AnimationWorkletMutatorDispatcherImplTest,MutationUpdateInvokedCorrectlyWithTwoRegisteredAnimatorsOnDifferentThreads)275 TEST_F(
276 AnimationWorkletMutatorDispatcherImplTest,
277 MutationUpdateInvokedCorrectlyWithTwoRegisteredAnimatorsOnDifferentThreads) {
278 std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread");
279 MockAnimationWorkletMutator* first_mutator =
280 MakeGarbageCollected<MockAnimationWorkletMutator>(
281 first_thread->GetTaskRunner());
282
283 std::unique_ptr<Thread> second_thread = CreateThread("SecondAnimationThread");
284 MockAnimationWorkletMutator* second_mutator =
285 MakeGarbageCollected<MockAnimationWorkletMutator>(
286 second_thread->GetTaskRunner());
287
288 mutator_->RegisterAnimationWorkletMutator(
289 WrapCrossThreadPersistent(first_mutator), first_thread->GetTaskRunner());
290 mutator_->RegisterAnimationWorkletMutator(
291 WrapCrossThreadPersistent(second_mutator),
292 second_thread->GetTaskRunner());
293
294 EXPECT_CALL(*first_mutator, GetWorkletId())
295 .Times(AtLeast(1))
296 .WillRepeatedly(Return(11));
297 EXPECT_CALL(*first_mutator, MutateRef(_))
298 .Times(1)
299 .WillOnce(Return(new AnimationWorkletOutput()));
300 EXPECT_CALL(*second_mutator, GetWorkletId())
301 .Times(AtLeast(1))
302 .WillRepeatedly(Return(22));
303 EXPECT_CALL(*second_mutator, MutateRef(_))
304 .Times(1)
305 .WillOnce(Return(new AnimationWorkletOutput()));
306 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(2);
307 mutator_->MutateSynchronously(CreateTestMutatorInput());
308
309 // The above call blocks on mutator threads running their tasks so we can
310 // safely verify here.
311 Mock::VerifyAndClearExpectations(client_.get());
312
313 // Ensure first_mutator is not invoked after unregistration.
314 mutator_->UnregisterAnimationWorkletMutator(
315 WrapCrossThreadPersistent(first_mutator));
316
317 EXPECT_CALL(*first_mutator, GetWorkletId()).Times(0);
318 EXPECT_CALL(*first_mutator, MutateRef(_)).Times(0);
319 EXPECT_CALL(*second_mutator, GetWorkletId())
320 .Times(AtLeast(1))
321 .WillRepeatedly(Return(22));
322 EXPECT_CALL(*second_mutator, MutateRef(_))
323 .Times(1)
324 .WillOnce(Return(new AnimationWorkletOutput()));
325 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(1);
326 mutator_->MutateSynchronously(CreateTestMutatorInput());
327
328 Mock::VerifyAndClearExpectations(client_.get());
329 }
330
TEST_F(AnimationWorkletMutatorDispatcherImplTest,DispatcherShouldNotHangWhenMutatorGoesAway)331 TEST_F(AnimationWorkletMutatorDispatcherImplTest,
332 DispatcherShouldNotHangWhenMutatorGoesAway) {
333 // Create a thread to run mutator tasks.
334 std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread");
335 MockAnimationWorkletMutator* first_mutator =
336 MakeGarbageCollected<MockAnimationWorkletMutator>(
337 first_thread->GetTaskRunner());
338
339 mutator_->RegisterAnimationWorkletMutator(
340 WrapCrossThreadPersistent(first_mutator), first_thread->GetTaskRunner());
341
342 EXPECT_CALL(*first_mutator, GetWorkletId()).WillRepeatedly(Return(11));
343 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(0);
344
345 // Shutdown the thread so its task runner no longer executes tasks.
346 first_thread.reset();
347
348 mutator_->MutateSynchronously(CreateTestMutatorInput());
349
350 Mock::VerifyAndClearExpectations(client_.get());
351 }
352
353 // -----------------------------------------------------------------------
354 // Asynchronous version of tests.
355
356 using MutatorDispatcherRef =
357 scoped_refptr<AnimationWorkletMutatorDispatcherImpl>;
358
359 class AnimationWorkletMutatorDispatcherImplAsyncTest
360 : public AnimationWorkletMutatorDispatcherImplTest {
361 public:
362 AnimationWorkletMutatorDispatcher::AsyncMutationCompleteCallback
CreateIntermediateResultCallback(MutateStatus expected_result)363 CreateIntermediateResultCallback(MutateStatus expected_result) {
364 return CrossThreadBindOnce(
365 &AnimationWorkletMutatorDispatcherImplAsyncTest ::
366 VerifyExpectedMutationResult,
367 CrossThreadUnretained(this), expected_result);
368 }
369
370 AnimationWorkletMutatorDispatcher::AsyncMutationCompleteCallback
CreateNotReachedCallback()371 CreateNotReachedCallback() {
372 return CrossThreadBindOnce([](MutateStatus unused) {
373 NOTREACHED() << "Mutate complete callback should not have been triggered";
374 });
375 }
376
377 AnimationWorkletMutatorDispatcher::AsyncMutationCompleteCallback
CreateTestCompleteCallback(MutateStatus expected_result=MutateStatus::kCompletedWithUpdate)378 CreateTestCompleteCallback(
379 MutateStatus expected_result = MutateStatus::kCompletedWithUpdate) {
380 return CrossThreadBindOnce(
381 &AnimationWorkletMutatorDispatcherImplAsyncTest ::
382 VerifyCompletedMutationResultAndFinish,
383 CrossThreadUnretained(this), expected_result);
384 }
385
386 // Executes run loop until quit closure is called.
WaitForTestCompletion()387 void WaitForTestCompletion() { run_loop_.Run(); }
388
VerifyExpectedMutationResult(MutateStatus expectation,MutateStatus result)389 void VerifyExpectedMutationResult(MutateStatus expectation,
390 MutateStatus result) {
391 EXPECT_EQ(expectation, result);
392 IntermediateResultCallbackRef();
393 }
394
VerifyCompletedMutationResultAndFinish(MutateStatus expectation,MutateStatus result)395 void VerifyCompletedMutationResultAndFinish(MutateStatus expectation,
396 MutateStatus result) {
397 EXPECT_EQ(expectation, result);
398 run_loop_.Quit();
399 }
400
401 // Verifying that intermediate result callbacks are invoked the correct number
402 // of times.
403 MOCK_METHOD0(IntermediateResultCallbackRef, void());
404
405 static const MutateQueuingStrategy kNormalPriority =
406 MutateQueuingStrategy::kQueueAndReplaceNormalPriority;
407
408 static const MutateQueuingStrategy kHighPriority =
409 MutateQueuingStrategy::kQueueHighPriority;
410
411 private:
412 base::RunLoop run_loop_;
413 };
414
TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,RegisteredAnimatorShouldOnlyReceiveInputForItself)415 TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,
416 RegisteredAnimatorShouldOnlyReceiveInputForItself) {
417 std::unique_ptr<Thread> first_thread = CreateThread("FirstThread");
418 MockAnimationWorkletMutator* first_mutator =
419 MakeGarbageCollected<MockAnimationWorkletMutator>(
420 first_thread->GetTaskRunner());
421
422 mutator_->RegisterAnimationWorkletMutator(
423 WrapCrossThreadPersistent(first_mutator), first_thread->GetTaskRunner());
424
425 EXPECT_CALL(*first_mutator, GetWorkletId())
426 .Times(AtLeast(1))
427 .WillRepeatedly(Return(11));
428 EXPECT_CALL(*first_mutator, MutateRef(_))
429 .Times(1)
430 .WillOnce(Return(new AnimationWorkletOutput()));
431 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(1);
432
433 EXPECT_TRUE(mutator_->MutateAsynchronously(
434 CreateTestMutatorInput(), kNormalPriority, CreateTestCompleteCallback()));
435
436 WaitForTestCompletion();
437 }
438
TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,RegisteredAnimatorShouldNotBeMutatedWhenNoInput)439 TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,
440 RegisteredAnimatorShouldNotBeMutatedWhenNoInput) {
441 std::unique_ptr<Thread> first_thread = CreateThread("FirstThread");
442 MockAnimationWorkletMutator* first_mutator =
443 MakeGarbageCollected<MockAnimationWorkletMutator>(
444 first_thread->GetTaskRunner());
445
446 mutator_->RegisterAnimationWorkletMutator(
447 WrapCrossThreadPersistent(first_mutator), first_thread->GetTaskRunner());
448
449 AnimationWorkletInput::AddAndUpdateState state{
450 {22, 2}, "test2", 5000, nullptr, nullptr};
451
452 auto input = std::make_unique<AnimationWorkletDispatcherInput>();
453 input->Add(std::move(state));
454
455 EXPECT_CALL(*first_mutator, GetWorkletId())
456 .Times(AtLeast(1))
457 .WillRepeatedly(Return(11));
458
459 EXPECT_FALSE(mutator_->MutateAsynchronously(std::move(input), kNormalPriority,
460 CreateNotReachedCallback()));
461 }
462
TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,MutationUpdateIsNotInvokedWithNoRegisteredAnimators)463 TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,
464 MutationUpdateIsNotInvokedWithNoRegisteredAnimators) {
465 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(0);
466 std::unique_ptr<AnimationWorkletDispatcherInput> input =
467 std::make_unique<AnimationWorkletDispatcherInput>();
468 EXPECT_FALSE(mutator_->MutateAsynchronously(std::move(input), kNormalPriority,
469 CreateNotReachedCallback()));
470 }
471
TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,MutationUpdateIsNotInvokedWithNullOutput)472 TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,
473 MutationUpdateIsNotInvokedWithNullOutput) {
474 // Create a thread to run mutator tasks.
475 std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread");
476 MockAnimationWorkletMutator* first_mutator =
477 MakeGarbageCollected<MockAnimationWorkletMutator>(
478 first_thread->GetTaskRunner());
479
480 mutator_->RegisterAnimationWorkletMutator(
481 WrapCrossThreadPersistent(first_mutator), first_thread->GetTaskRunner());
482
483 EXPECT_CALL(*first_mutator, GetWorkletId())
484 .Times(AtLeast(1))
485 .WillRepeatedly(Return(11));
486 EXPECT_CALL(*first_mutator, MutateRef(_)).Times(1).WillOnce(Return(nullptr));
487 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(0);
488
489 EXPECT_TRUE(mutator_->MutateAsynchronously(
490 CreateTestMutatorInput(), kNormalPriority,
491 CreateTestCompleteCallback(MutateStatus::kCompletedNoUpdate)));
492
493 WaitForTestCompletion();
494 }
495
TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,MutationUpdateIsInvokedCorrectlyWithSingleRegisteredAnimator)496 TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,
497 MutationUpdateIsInvokedCorrectlyWithSingleRegisteredAnimator) {
498 // Create a thread to run mutator tasks.
499 std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread");
500 MockAnimationWorkletMutator* first_mutator =
501 MakeGarbageCollected<MockAnimationWorkletMutator>(
502 first_thread->GetTaskRunner());
503
504 mutator_->RegisterAnimationWorkletMutator(
505 WrapCrossThreadPersistent(first_mutator), first_thread->GetTaskRunner());
506
507 EXPECT_CALL(*first_mutator, GetWorkletId())
508 .Times(AtLeast(1))
509 .WillRepeatedly(Return(11));
510 EXPECT_CALL(*first_mutator, MutateRef(_))
511 .Times(1)
512 .WillOnce(Return(new AnimationWorkletOutput()));
513 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(1);
514
515 EXPECT_TRUE(mutator_->MutateAsynchronously(
516 CreateTestMutatorInput(), kNormalPriority, CreateTestCompleteCallback()));
517
518 WaitForTestCompletion();
519
520 // Above call blocks until complete signal is received.
521 Mock::VerifyAndClearExpectations(client_.get());
522
523 // Ensure mutator is not invoked after unregistration.
524 mutator_->UnregisterAnimationWorkletMutator(
525 WrapCrossThreadPersistent(first_mutator));
526 EXPECT_FALSE(mutator_->MutateAsynchronously(
527 CreateTestMutatorInput(), kNormalPriority, CreateNotReachedCallback()));
528
529 Mock::VerifyAndClearExpectations(client_.get());
530 }
531
TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,MutationUpdateInvokedCorrectlyWithTwoRegisteredAnimatorsOnSameThread)532 TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,
533 MutationUpdateInvokedCorrectlyWithTwoRegisteredAnimatorsOnSameThread) {
534 std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread");
535 MockAnimationWorkletMutator* first_mutator =
536 MakeGarbageCollected<MockAnimationWorkletMutator>(
537 first_thread->GetTaskRunner());
538 MockAnimationWorkletMutator* second_mutator =
539 MakeGarbageCollected<MockAnimationWorkletMutator>(
540 first_thread->GetTaskRunner());
541
542 mutator_->RegisterAnimationWorkletMutator(
543 WrapCrossThreadPersistent(first_mutator), first_thread->GetTaskRunner());
544 mutator_->RegisterAnimationWorkletMutator(
545 WrapCrossThreadPersistent(second_mutator), first_thread->GetTaskRunner());
546
547 EXPECT_CALL(*first_mutator, GetWorkletId())
548 .Times(AtLeast(1))
549 .WillRepeatedly(Return(11));
550 EXPECT_CALL(*first_mutator, MutateRef(_))
551 .Times(1)
552 .WillOnce(Return(new AnimationWorkletOutput()));
553 EXPECT_CALL(*second_mutator, GetWorkletId())
554 .Times(AtLeast(1))
555 .WillRepeatedly(Return(22));
556 EXPECT_CALL(*second_mutator, MutateRef(_))
557 .Times(1)
558 .WillOnce(Return(new AnimationWorkletOutput()));
559 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(2);
560
561 EXPECT_TRUE(mutator_->MutateAsynchronously(
562 CreateTestMutatorInput(), kNormalPriority, CreateTestCompleteCallback()));
563
564 WaitForTestCompletion();
565 }
566
TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,MutationUpdateInvokedCorrectlyWithTwoRegisteredAnimatorsOnDifferentThreads)567 TEST_F(
568 AnimationWorkletMutatorDispatcherImplAsyncTest,
569 MutationUpdateInvokedCorrectlyWithTwoRegisteredAnimatorsOnDifferentThreads) {
570 std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread");
571 MockAnimationWorkletMutator* first_mutator =
572 MakeGarbageCollected<MockAnimationWorkletMutator>(
573 first_thread->GetTaskRunner());
574
575 std::unique_ptr<Thread> second_thread = CreateThread("SecondAnimationThread");
576 MockAnimationWorkletMutator* second_mutator =
577 MakeGarbageCollected<MockAnimationWorkletMutator>(
578 second_thread->GetTaskRunner());
579
580 mutator_->RegisterAnimationWorkletMutator(
581 WrapCrossThreadPersistent(first_mutator), first_thread->GetTaskRunner());
582 mutator_->RegisterAnimationWorkletMutator(
583 WrapCrossThreadPersistent(second_mutator),
584 second_thread->GetTaskRunner());
585
586 EXPECT_CALL(*first_mutator, GetWorkletId())
587 .Times(AtLeast(1))
588 .WillRepeatedly(Return(11));
589 EXPECT_CALL(*first_mutator, MutateRef(_))
590 .Times(1)
591 .WillOnce(Return(new AnimationWorkletOutput()));
592 EXPECT_CALL(*second_mutator, GetWorkletId())
593 .Times(AtLeast(1))
594 .WillRepeatedly(Return(22));
595 EXPECT_CALL(*second_mutator, MutateRef(_))
596 .Times(1)
597 .WillOnce(Return(new AnimationWorkletOutput()));
598 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(2);
599
600 EXPECT_TRUE(mutator_->MutateAsynchronously(
601 CreateTestMutatorInput(), kNormalPriority, CreateTestCompleteCallback()));
602
603 WaitForTestCompletion();
604 }
605
TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,MutationUpdateDroppedWhenBusy)606 TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,
607 MutationUpdateDroppedWhenBusy) {
608 std::unique_ptr<Thread> first_thread = CreateThread("FirstThread");
609 MockAnimationWorkletMutator* first_mutator =
610 MakeGarbageCollected<MockAnimationWorkletMutator>(
611 first_thread->GetTaskRunner());
612 mutator_->RegisterAnimationWorkletMutator(
613 WrapCrossThreadPersistent(first_mutator), first_thread->GetTaskRunner());
614
615 EXPECT_CALL(*first_mutator, GetWorkletId())
616 .Times(AtLeast(1))
617 .WillRepeatedly(Return(11));
618 EXPECT_CALL(*first_mutator, MutateRef(_))
619 .Times(1)
620 .WillOnce(Return(new AnimationWorkletOutput()));
621 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(1);
622
623 // Block Responses until all requests have been queued.
624 first_mutator->BlockWorkletThread();
625 // Response for first mutator call is blocked until after the second
626 // call is sent.
627 EXPECT_TRUE(mutator_->MutateAsynchronously(
628 CreateTestMutatorInput(), kNormalPriority, CreateTestCompleteCallback()));
629 // Second request dropped since busy processing first.
630 EXPECT_FALSE(mutator_->MutateAsynchronously(CreateTestMutatorInput(),
631 MutateQueuingStrategy::kDrop,
632 CreateNotReachedCallback()));
633 // Unblock first request.
634 first_mutator->UnblockWorkletThread();
635
636 WaitForTestCompletion();
637 }
638
TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,MutationUpdateQueuedWhenBusy)639 TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,
640 MutationUpdateQueuedWhenBusy) {
641 std::unique_ptr<Thread> first_thread = CreateThread("FirstThread");
642
643 MockAnimationWorkletMutator* first_mutator =
644 MakeGarbageCollected<MockAnimationWorkletMutator>(
645 first_thread->GetTaskRunner());
646 mutator_->RegisterAnimationWorkletMutator(
647 WrapCrossThreadPersistent(first_mutator), first_thread->GetTaskRunner());
648
649 EXPECT_CALL(*first_mutator, GetWorkletId())
650 .Times(AtLeast(2))
651 .WillRepeatedly(Return(11));
652 EXPECT_CALL(*first_mutator, MutateRef(_))
653 .Times(2)
654 .WillOnce(Return(new AnimationWorkletOutput()))
655 .WillOnce(Return(new AnimationWorkletOutput()));
656 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(2);
657 EXPECT_CALL(*this, IntermediateResultCallbackRef()).Times(1);
658
659 // Block Responses until all requests have been queued.
660 first_mutator->BlockWorkletThread();
661 // Response for first mutator call is blocked until after the second
662 // call is sent.
663 EXPECT_TRUE(mutator_->MutateAsynchronously(
664 CreateTestMutatorInput(), kNormalPriority,
665 CreateIntermediateResultCallback(MutateStatus::kCompletedWithUpdate)));
666 // First request still processing, queue request.
667 EXPECT_TRUE(mutator_->MutateAsynchronously(
668 CreateTestMutatorInput(), kNormalPriority, CreateTestCompleteCallback()));
669 // Unblock first request.
670 first_mutator->UnblockWorkletThread();
671
672 WaitForTestCompletion();
673 }
674
TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,MutationUpdateQueueWithReplacementWhenBusy)675 TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,
676 MutationUpdateQueueWithReplacementWhenBusy) {
677 std::unique_ptr<Thread> first_thread = CreateThread("FirstThread");
678
679 MockAnimationWorkletMutator* first_mutator =
680 MakeGarbageCollected<MockAnimationWorkletMutator>(
681 first_thread->GetTaskRunner());
682 mutator_->RegisterAnimationWorkletMutator(
683 WrapCrossThreadPersistent(first_mutator), first_thread->GetTaskRunner());
684
685 EXPECT_CALL(*first_mutator, GetWorkletId())
686 .Times(AtLeast(2))
687 .WillRepeatedly(Return(11));
688 EXPECT_CALL(*first_mutator, MutateRef(_))
689 .Times(2)
690 .WillOnce(Return(new AnimationWorkletOutput()))
691 .WillOnce(Return(new AnimationWorkletOutput()));
692 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(2);
693 EXPECT_CALL(*this, IntermediateResultCallbackRef()).Times(2);
694
695 // Block Responses until all requests have been queued.
696 first_mutator->BlockWorkletThread();
697 // Response for first mutator call is blocked until after the second
698 // call is sent.
699 EXPECT_TRUE(mutator_->MutateAsynchronously(
700 CreateTestMutatorInput(), kNormalPriority,
701 CreateIntermediateResultCallback(MutateStatus::kCompletedWithUpdate)));
702 // First request still processing, queue a second request, which will get
703 // canceled by a third request.
704 EXPECT_TRUE(mutator_->MutateAsynchronously(
705 CreateTestMutatorInput(), kNormalPriority,
706 CreateIntermediateResultCallback(MutateStatus::kCanceled)));
707 // First request still processing, clobber second request in queue.
708 EXPECT_TRUE(mutator_->MutateAsynchronously(
709 CreateTestMutatorInput(), kNormalPriority, CreateTestCompleteCallback()));
710 // Unblock first request.
711 first_mutator->UnblockWorkletThread();
712
713 WaitForTestCompletion();
714 }
715
TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,MutationUpdateMultipleQueuesWhenBusy)716 TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,
717 MutationUpdateMultipleQueuesWhenBusy) {
718 std::unique_ptr<Thread> first_thread = CreateThread("FirstThread");
719
720 MockAnimationWorkletMutator* first_mutator =
721 MakeGarbageCollected<MockAnimationWorkletMutator>(
722 first_thread->GetTaskRunner());
723 mutator_->RegisterAnimationWorkletMutator(
724 WrapCrossThreadPersistent(first_mutator), first_thread->GetTaskRunner());
725
726 EXPECT_CALL(*first_mutator, GetWorkletId())
727 .Times(AtLeast(3))
728 .WillRepeatedly(Return(11));
729 EXPECT_CALL(*first_mutator, MutateRef(_))
730 .Times(3)
731 .WillOnce(Return(new AnimationWorkletOutput()))
732 .WillOnce(Return(new AnimationWorkletOutput()))
733 .WillOnce(Return(new AnimationWorkletOutput()));
734 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(3);
735 EXPECT_CALL(*this, IntermediateResultCallbackRef()).Times(2);
736
737 // Block Responses until all requests have been queued.
738 first_mutator->BlockWorkletThread();
739 // Response for first mutator call is blocked until after the second
740 // call is sent.
741 EXPECT_TRUE(mutator_->MutateAsynchronously(
742 CreateTestMutatorInput(), kNormalPriority,
743 CreateIntermediateResultCallback(MutateStatus::kCompletedWithUpdate)));
744 // First request still processing, queue a second request.
745 EXPECT_TRUE(mutator_->MutateAsynchronously(
746 CreateTestMutatorInput(), kNormalPriority, CreateTestCompleteCallback()));
747 // First request still processing. This request uses a separate queue from the
748 // second request. It should not replace the second request but should be
749 // dispatched ahead of the second request.
750 EXPECT_TRUE(mutator_->MutateAsynchronously(
751 CreateTestMutatorInput(), kHighPriority,
752 CreateIntermediateResultCallback(MutateStatus::kCompletedWithUpdate)));
753 // Unblock first request.
754 first_mutator->UnblockWorkletThread();
755
756 WaitForTestCompletion();
757 }
758
TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest,HistogramTester)759 TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest, HistogramTester) {
760 const char* histogram_name =
761 "Animation.AnimationWorklet.Dispatcher.AsynchronousMutateDuration";
762 base::HistogramTester histogram_tester;
763
764 std::unique_ptr<base::TickClock> mock_clock =
765 std::make_unique<base::SimpleTestTickClock>();
766 base::SimpleTestTickClock* mock_clock_ptr =
767 static_cast<base::SimpleTestTickClock*>(mock_clock.get());
768 mutator_->SetClockForTesting(std::move(mock_clock));
769
770 std::unique_ptr<Thread> thread = CreateThread("MyThread");
771 MockAnimationWorkletMutator* mutator =
772 MakeGarbageCollected<MockAnimationWorkletMutator>(
773 thread->GetTaskRunner());
774 mutator_->RegisterAnimationWorkletMutator(WrapCrossThreadPersistent(mutator),
775 thread->GetTaskRunner());
776
777 EXPECT_CALL(*mutator, GetWorkletId())
778 .Times(AtLeast(2))
779 .WillRepeatedly(Return(11));
780 EXPECT_CALL(*mutator, MutateRef(_))
781 .Times(2)
782 .WillOnce(Return(new AnimationWorkletOutput()))
783 .WillOnce(Return(new AnimationWorkletOutput()));
784 EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(2);
785
786 // Block Responses until all requests have been queued.
787 mutator->BlockWorkletThread();
788
789 base::TimeDelta time_delta = base::TimeDelta::FromMilliseconds(10);
790
791 // Expected Elapsed time is the sum of all clock advancements until unblocked,
792 // which totals to 30 ms.
793 EXPECT_TRUE(mutator_->MutateAsynchronously(
794 CreateTestMutatorInput(), kHighPriority,
795 CreateIntermediateResultCallback(MutateStatus::kCompletedWithUpdate)));
796 mock_clock_ptr->Advance(time_delta);
797
798 // This request will get stomped by the next request, but the start time is
799 // preserved.
800 EXPECT_TRUE(mutator_->MutateAsynchronously(
801 CreateTestMutatorInput(), kNormalPriority,
802 CreateIntermediateResultCallback(MutateStatus::kCanceled)));
803 mock_clock_ptr->Advance(time_delta);
804
805 // Replaces previous request. Since 10 ms has elapsed prior to replacing the
806 // previous request, the expected elapsed time is 20 ms.
807 EXPECT_TRUE(mutator_->MutateAsynchronously(
808 CreateTestMutatorInput(), kNormalPriority, CreateTestCompleteCallback()));
809 mock_clock_ptr->Advance(time_delta);
810
811 mutator->UnblockWorkletThread();
812 WaitForTestCompletion();
813
814 histogram_tester.ExpectTotalCount(histogram_name, 2);
815 // Times are in microseconds.
816 histogram_tester.ExpectBucketCount(histogram_name, 20000, 1);
817 histogram_tester.ExpectBucketCount(histogram_name, 30000, 1);
818 }
819
820 } // namespace
821
822 } // namespace blink
823