 Chromium Code Reviews
 Chromium Code Reviews| Index: content/renderer/gpu/render_widget_compositor_unittest.cc | 
| diff --git a/content/renderer/gpu/render_widget_compositor_unittest.cc b/content/renderer/gpu/render_widget_compositor_unittest.cc | 
| index 6a7a8cc7a27d8677c7a020f69409faa0bd3bd62c..cf88ccc3c0bb57daf6b14c8e4237f96e49fccbaf 100644 | 
| --- a/content/renderer/gpu/render_widget_compositor_unittest.cc | 
| +++ b/content/renderer/gpu/render_widget_compositor_unittest.cc | 
| @@ -5,6 +5,8 @@ | 
| #include "content/renderer/gpu/render_widget_compositor.h" | 
| #include "cc/output/begin_frame_args.h" | 
| +#include "cc/test/failure_output_surface.h" | 
| +#include "cc/trees/layer_tree_host.h" | 
| #include "content/public/test/mock_render_thread.h" | 
| #include "content/renderer/render_widget.h" | 
| #include "testing/gmock/include/gmock/gmock.h" | 
| @@ -34,7 +36,7 @@ class TestRenderWidget : public RenderWidget { | 
| MockWebWidget mock_webwidget_; | 
| - private: | 
| + protected: | 
| ~TestRenderWidget() override { webwidget_ = NULL; } | 
| DISALLOW_COPY_AND_ASSIGN(TestRenderWidget); | 
| @@ -75,4 +77,209 @@ TEST_F(RenderWidgetCompositorTest, BeginMainFrame) { | 
| render_widget_compositor_->BeginMainFrame(args); | 
| } | 
| +class RenderWidgetCompositorOutputSurface; | 
| + | 
| +class RenderWidgetOutputSurface : public TestRenderWidget { | 
| + public: | 
| + RenderWidgetOutputSurface() : compositor_(NULL) {} | 
| + void SetCompositor(RenderWidgetCompositorOutputSurface* compositor); | 
| + | 
| + scoped_ptr<cc::OutputSurface> CreateOutputSurface(bool fallback) override; | 
| + | 
| + protected: | 
| + ~RenderWidgetOutputSurface() {} | 
| + | 
| + private: | 
| + RenderWidgetCompositorOutputSurface* compositor_; | 
| + | 
| + DISALLOW_COPY_AND_ASSIGN(RenderWidgetOutputSurface); | 
| +}; | 
| + | 
| +// Verify that failing to create an output surface will cause the compositor | 
| +// to attempt to repeatedly create another output surface. After enough | 
| +// failures, verify that it attempts to create a fallback output surface. | 
| +// The use null output surface parameter allows testing whether failures | 
| +// from RenderWidget (couldn't create an output surface) vs failures from | 
| +// the compositor (couldn't bind the output surface) are handled identically. | 
| +class RenderWidgetCompositorOutputSurface : public RenderWidgetCompositor { | 
| + public: | 
| + RenderWidgetCompositorOutputSurface(RenderWidget* widget, bool threaded) | 
| + : RenderWidgetCompositor(widget, threaded), | 
| + expected_failures_(0), | 
| + expected_successes_(0), | 
| + expected_fallback_successes_(0), | 
| + expected_requests_(0), | 
| + num_requests_(0), | 
| + num_requests_since_last_success_(0), | 
| + num_successes_(0), | 
| + num_fallback_successes_(0), | 
| + num_failures_(0), | 
| + last_create_was_fallback_(false), | 
| + use_null_output_surface_(true) { | 
| + cc::LayerTreeSettings settings; | 
| + Initialize(settings); | 
| + } | 
| + | 
| + scoped_ptr<cc::OutputSurface> CreateOutputSurface(bool fallback) { | 
| + EXPECT_EQ(num_requests_since_last_success_ > | 
| + OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK, | 
| + fallback); | 
| + last_create_was_fallback_ = fallback; | 
| + bool success = num_failures_ >= expected_failures_; | 
| + if (success) | 
| + return cc::FakeOutputSurface::Create3d(); | 
| + return use_null_output_surface_ | 
| + ? nullptr | 
| + : make_scoped_ptr(new cc::FailureOutputSurface(false)); | 
| + } | 
| + | 
| + void RequestNewOutputSurface() override { | 
| + ++num_requests_; | 
| + ++num_requests_since_last_success_; | 
| + RenderWidgetCompositor::RequestNewOutputSurface(); | 
| + } | 
| + | 
| + void DidInitializeOutputSurface() override { | 
| + if (last_create_was_fallback_) | 
| + ++num_fallback_successes_; | 
| + else | 
| + ++num_successes_; | 
| + | 
| + if (num_requests_ == expected_requests_) { | 
| + EndTest(); | 
| + } else { | 
| + num_requests_since_last_success_ = 0; | 
| + RenderWidgetCompositor::DidInitializeOutputSurface(); | 
| + layer_tree_host()->DidLoseOutputSurface(); | 
| + RequestNewOutputSurface(); | 
| + } | 
| + } | 
| + | 
| + void DidFailToInitializeOutputSurface() override { | 
| + ++num_failures_; | 
| + if (num_requests_ == expected_requests_) { | 
| + EndTest(); | 
| + return; | 
| + } | 
| + | 
| + RenderWidgetCompositor::DidFailToInitializeOutputSurface(); | 
| + } | 
| + | 
| + void SetUp(bool use_null_output_surface, | 
| + int expected_failures, | 
| + int expected_successes, | 
| + int expected_fallback_succeses) { | 
| + use_null_output_surface_ = use_null_output_surface; | 
| + expected_failures_ = expected_failures; | 
| + expected_successes_ = expected_successes; | 
| + expected_fallback_successes_ = expected_fallback_succeses; | 
| + expected_requests_ = | 
| + expected_failures_ + expected_successes_ + expected_fallback_successes_; | 
| + } | 
| + | 
| + void EndTest() { base::MessageLoop::current()->Quit(); } | 
| + | 
| + void AfterTest() { | 
| + EXPECT_EQ(expected_failures_, num_failures_); | 
| + EXPECT_EQ(expected_successes_, num_successes_); | 
| + EXPECT_EQ(expected_fallback_successes_, num_fallback_successes_); | 
| + EXPECT_EQ(expected_requests_, num_requests_); | 
| + } | 
| + | 
| + private: | 
| + int expected_failures_; | 
| + int expected_successes_; | 
| + int expected_fallback_successes_; | 
| + int expected_requests_; | 
| + int num_requests_; | 
| + int num_requests_since_last_success_; | 
| + int num_successes_; | 
| + int num_fallback_successes_; | 
| + int num_failures_; | 
| + bool last_create_was_fallback_; | 
| + bool use_null_output_surface_; | 
| + | 
| + DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorOutputSurface); | 
| +}; | 
| + | 
| +class RenderWidgetCompositorOutputSurfaceTest : public testing::Test { | 
| + public: | 
| + RenderWidgetCompositorOutputSurfaceTest() | 
| + : render_widget_(make_scoped_refptr(new RenderWidgetOutputSurface)), | 
| + render_widget_compositor_(make_scoped_ptr( | 
| + new RenderWidgetCompositorOutputSurface(render_widget_.get(), | 
| + false))) { | 
| + render_widget_->SetCompositor(render_widget_compositor_.get()); | 
| + } | 
| + | 
| + void RunTest(bool use_null_output_surface, | 
| + int expected_failures, | 
| 
no sievers
2014/12/02 20:38:07
nit: should this be called |num_failures| or |num_
 
enne (OOO)
2014/12/02 21:09:33
num_failures_before_success sounds good.  Done.
 | 
| + int expected_successes, | 
| + int expected_fallback_succeses) { | 
| + render_widget_compositor_->SetUp(use_null_output_surface, expected_failures, | 
| + expected_successes, | 
| + expected_fallback_succeses); | 
| + base::MessageLoop::current()->PostTask( | 
| + FROM_HERE, | 
| + base::Bind(&RenderWidgetCompositor::RequestNewOutputSurface, | 
| + base::Unretained(render_widget_compositor_.get()))); | 
| + // TODO(enne): should probably add timeout logic | 
| 
no sievers
2014/12/02 20:38:07
Hmm or maybe not? Don't the unit test harnesses pr
 
enne (OOO)
2014/12/02 21:09:33
Maybe they do on the bots? cc unit tests post a mo
 | 
| + base::MessageLoop::current()->Run(); | 
| + render_widget_compositor_->AfterTest(); | 
| + } | 
| + | 
| + protected: | 
| + base::MessageLoop ye_olde_message_loope_; | 
| + MockRenderThread render_thread_; | 
| + scoped_refptr<RenderWidgetOutputSurface> render_widget_; | 
| + scoped_ptr<RenderWidgetCompositorOutputSurface> render_widget_compositor_; | 
| + | 
| + private: | 
| + DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorOutputSurfaceTest); | 
| +}; | 
| + | 
| +scoped_ptr<cc::OutputSurface> RenderWidgetOutputSurface::CreateOutputSurface( | 
| + bool fallback) { | 
| + return compositor_->CreateOutputSurface(fallback); | 
| +} | 
| + | 
| +void RenderWidgetOutputSurface::SetCompositor( | 
| + RenderWidgetCompositorOutputSurface* compositor) { | 
| + compositor_ = compositor; | 
| +} | 
| + | 
| +TEST_F(RenderWidgetCompositorOutputSurfaceTest, SucceedOnce) { | 
| + RunTest(false, 0, 1, 0); | 
| +} | 
| + | 
| +TEST_F(RenderWidgetCompositorOutputSurfaceTest, SucceedTwice) { | 
| + RunTest(false, 0, 2, 0); | 
| +} | 
| + | 
| +TEST_F(RenderWidgetCompositorOutputSurfaceTest, FailOnceNull) { | 
| + EXPECT_GT(RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK, 2); | 
| 
no sievers
2014/12/02 20:38:07
nit: static_assert here and below
 
enne (OOO)
2014/12/02 21:09:33
Done.
 | 
| + RunTest(true, 1, 1, 0); | 
| +} | 
| + | 
| +TEST_F(RenderWidgetCompositorOutputSurfaceTest, FailOnceBind) { | 
| + EXPECT_GT(RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK, 2); | 
| + RunTest(false, 1, 1, 0); | 
| +} | 
| + | 
| +TEST_F(RenderWidgetCompositorOutputSurfaceTest, FallbackSuccessNull) { | 
| + RunTest(true, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK, | 
| + 0, 1); | 
| +} | 
| + | 
| +TEST_F(RenderWidgetCompositorOutputSurfaceTest, FallbackSuccessBind) { | 
| + RunTest(false, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK, | 
| + 0, 1); | 
| +} | 
| + | 
| +TEST_F(RenderWidgetCompositorOutputSurfaceTest, FallbackSuccessNormalSuccess) { | 
| + // The first success is a fallback, but the next should not be a fallback. | 
| + RunTest(false, RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK, | 
| + 1, 1); | 
| +} | 
| + | 
| } // namespace content |