 Chromium Code Reviews
 Chromium Code Reviews Issue 1414533003:
  Make ui::Compositor BeginFrame subscription robust  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master
    
  
    Issue 1414533003:
  Make ui::Compositor BeginFrame subscription robust  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master| Index: ui/compositor/compositor_unittest.cc | 
| diff --git a/ui/compositor/compositor_unittest.cc b/ui/compositor/compositor_unittest.cc | 
| index a53bdc2ab0f2b5d1095bde808917bb7947ca3c72..39c50e57bcb5d233782b2109a1e45a30c0bfc523 100644 | 
| --- a/ui/compositor/compositor_unittest.cc | 
| +++ b/ui/compositor/compositor_unittest.cc | 
| @@ -19,6 +19,10 @@ using testing::_; | 
| namespace ui { | 
| namespace { | 
| +ACTION_P2(RemoveObserver, compositor, observer) { | 
| + compositor->RemoveBeginFrameObserver(observer); | 
| +} | 
| + | 
| class MockCompositorBeginFrameObserver : public CompositorBeginFrameObserver { | 
| public: | 
| MOCK_METHOD1(OnSendBeginFrame, void(const cc::BeginFrameArgs&)); | 
| @@ -91,27 +95,32 @@ TEST_F(CompositorTest, AddAndRemoveBeginFrameObserver) { | 
| cc::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, | 
| base::TimeTicks::FromInternalValue(33)); | 
| - // Simulate to trigger new BeginFrame by using |args|. | 
| - compositor()->SendBeginFramesToChildren(args); | 
| + MockCompositorBeginFrameObserver test_observer; | 
| + MockCompositorBeginFrameObserver test_observer2; | 
| + | 
| + // Add a single observer. | 
| + compositor()->AddBeginFrameObserver(&test_observer); | 
| + Mock::VerifyAndClearExpectations(&test_observer); | 
| // When |missed_begin_frame_args_| is sent, its type is set to MISSED. | 
| cc::BeginFrameArgs expected_args(args); | 
| - expected_args.type = cc::BeginFrameArgs::MISSED; | 
| + cc::BeginFrameArgs expected_missed_args(args); | 
| + expected_missed_args.type = cc::BeginFrameArgs::MISSED; | 
| - MockCompositorBeginFrameObserver test_observer; | 
| - MockCompositorBeginFrameObserver test_observer2; | 
| + // Simulate to trigger new BeginFrame by using |args|. | 
| 
brianderson
2015/10/21 23:12:59
Thanks for making this test more realistic, even t
 | 
| EXPECT_CALL(test_observer, OnSendBeginFrame(expected_args)); | 
| - EXPECT_CALL(test_observer2, OnSendBeginFrame(expected_args)); | 
| + compositor()->SendBeginFramesToChildren(args); | 
| + Mock::VerifyAndClearExpectations(&test_observer); | 
| // When new observer is added, Compositor immediately calls OnSendBeginFrame | 
| // with |missed_begin_frame_args_|. | 
| - compositor()->AddBeginFrameObserver(&test_observer); | 
| + EXPECT_CALL(test_observer2, OnSendBeginFrame(expected_missed_args)); | 
| compositor()->AddBeginFrameObserver(&test_observer2); | 
| Mock::VerifyAndClearExpectations(&test_observer); | 
| Mock::VerifyAndClearExpectations(&test_observer2); | 
| // When |test_observer2| is removed and added again, it will be called again. | 
| - EXPECT_CALL(test_observer2, OnSendBeginFrame(expected_args)); | 
| + EXPECT_CALL(test_observer2, OnSendBeginFrame(expected_missed_args)); | 
| compositor()->RemoveBeginFrameObserver(&test_observer2); | 
| compositor()->AddBeginFrameObserver(&test_observer2); | 
| Mock::VerifyAndClearExpectations(&test_observer2); | 
| @@ -127,6 +136,62 @@ TEST_F(CompositorTest, AddAndRemoveBeginFrameObserver) { | 
| compositor()->RemoveBeginFrameObserver(&test_observer2); | 
| } | 
| +TEST_F(CompositorTest, RemoveBeginFrameObserverWhileSendingBeginFrame) { | 
| 
brianderson
2015/10/21 23:12:59
It would be nice if these tests could verify the s
 
jdduke (slow)
2015/10/21 23:46:16
Yeah, I started looking into that kind of validati
 | 
| + cc::BeginFrameArgs args = cc::CreateBeginFrameArgsForTesting( | 
| + BEGINFRAME_FROM_HERE, base::TimeTicks::FromInternalValue(33)); | 
| + | 
| + cc::BeginFrameArgs expected_args(args); | 
| + cc::BeginFrameArgs expected_missed_args(args); | 
| + expected_missed_args.type = cc::BeginFrameArgs::MISSED; | 
| + | 
| + // Add both observers, and simulate removal of |test_observer2| during | 
| + // BeginFrame dispatch (implicitly triggered when the observer is added). | 
| + MockCompositorBeginFrameObserver test_observer; | 
| + MockCompositorBeginFrameObserver test_observer2; | 
| + EXPECT_CALL(test_observer, OnSendBeginFrame(expected_args)); | 
| + EXPECT_CALL(test_observer2, OnSendBeginFrame(expected_missed_args)) | 
| + .WillOnce(RemoveObserver(compositor(), &test_observer2)); | 
| + | 
| + // When a new observer is added, Compositor immediately calls OnSendBeginFrame | 
| + // with |missed_begin_frame_args_|. | 
| + compositor()->AddBeginFrameObserver(&test_observer); | 
| + compositor()->SendBeginFramesToChildren(args); | 
| + compositor()->AddBeginFrameObserver(&test_observer2); | 
| + Mock::VerifyAndClearExpectations(&test_observer); | 
| + Mock::VerifyAndClearExpectations(&test_observer2); | 
| + | 
| + // |test_observer2| was removed during the previous implicit BeginFrame | 
| + // dispatch, and should not get the new frame. | 
| + expected_args.type = cc::BeginFrameArgs::NORMAL; | 
| + EXPECT_CALL(test_observer, OnSendBeginFrame(expected_args)); | 
| + EXPECT_CALL(test_observer2, OnSendBeginFrame(expected_args)).Times(0); | 
| 
danakj
2015/10/22 18:36:00
put _ instead of expected_args. We don't want to h
 
jdduke (slow)
2015/10/22 19:13:19
Done.
 | 
| + compositor()->SendBeginFramesToChildren(args); | 
| + Mock::VerifyAndClearExpectations(&test_observer); | 
| + Mock::VerifyAndClearExpectations(&test_observer2); | 
| + | 
| + // Now remove |test_observer| during explicit BeginFrame dispatch. | 
| + EXPECT_CALL(test_observer, OnSendBeginFrame(expected_args)) | 
| + .WillOnce(RemoveObserver(compositor(), &test_observer)); | 
| + EXPECT_CALL(test_observer2, OnSendBeginFrame(expected_args)).Times(0); | 
| 
danakj
2015/10/22 18:35:59
dittos
 
jdduke (slow)
2015/10/22 19:13:19
Done.
 | 
| + compositor()->SendBeginFramesToChildren(args); | 
| + Mock::VerifyAndClearExpectations(&test_observer); | 
| + Mock::VerifyAndClearExpectations(&test_observer2); | 
| + | 
| + // No observers should get the new frame. | 
| + EXPECT_CALL(test_observer, OnSendBeginFrame(expected_args)).Times(0); | 
| + EXPECT_CALL(test_observer2, OnSendBeginFrame(expected_args)).Times(0); | 
| + compositor()->SendBeginFramesToChildren(args); | 
| + Mock::VerifyAndClearExpectations(&test_observer); | 
| + Mock::VerifyAndClearExpectations(&test_observer2); | 
| + | 
| + // Adding a new observer should not trigger a missed frame, as the | 
| + // previous frame had no observers. | 
| + EXPECT_CALL(test_observer, OnSendBeginFrame(expected_args)).Times(0); | 
| + compositor()->AddBeginFrameObserver(&test_observer); | 
| + compositor()->RemoveBeginFrameObserver(&test_observer); | 
| + Mock::VerifyAndClearExpectations(&test_observer); | 
| +} | 
| + | 
| TEST_F(CompositorTest, ReleaseWidgetWithOutputSurfaceNeverCreated) { | 
| compositor()->SetVisible(false); | 
| EXPECT_EQ(gfx::kNullAcceleratedWidget, |