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.
5 #include "base/memory/scoped_ptr.h"
6 #include "base/message_loop/message_loop.h"
7 #include "base/run_loop.h"
8 #include "content/browser/presentation/presentation_service_impl.h"
9 #include "content/public/browser/presentation_service_delegate.h"
10 #include "content/test/test_render_frame_host.h"
11 #include "content/test/test_render_view_host.h"
12 #include "content/test/test_web_contents.h"
13 #include "mojo/public/cpp/bindings/interface_ptr.h"
14 #include "testing/gmock/include/gmock/gmock.h"
18 using ::testing::InvokeWithoutArgs
;
19 using ::testing::Mock
;
20 using ::testing::Return
;
24 class MockPresentationServiceDelegate
: public PresentationServiceDelegate
{
26 MOCK_METHOD1(AddObserver
,
27 void(PresentationServiceDelegate::Observer
* observer
));
28 MOCK_METHOD1(RemoveObserver
,
29 void(PresentationServiceDelegate::Observer
* observer
));
30 MOCK_METHOD3(AddScreenAvailabilityListener
,
32 int render_process_id
,
34 PresentationScreenAvailabilityListener
* listener
));
35 MOCK_METHOD3(RemoveScreenAvailabilityListener
,
37 int render_process_id
,
39 PresentationScreenAvailabilityListener
* listener
));
40 MOCK_METHOD2(RemoveAllScreenAvailabilityListeners
,
42 int render_process_id
,
46 class PresentationServiceImplTest
: public RenderViewHostImplTestHarness
{
48 PresentationServiceImplTest() : callback_count_(0) {}
50 void SetUp() override
{
51 RenderViewHostImplTestHarness::SetUp();
53 EXPECT_CALL(mock_delegate_
, AddObserver(_
)).Times(1);
54 service_impl_
.reset(mojo::WeakBindToProxy(
55 new PresentationServiceImpl(
56 contents()->GetMainFrame(), contents(), &mock_delegate_
),
60 void TearDown() override
{
63 EXPECT_CALL(mock_delegate_
, RemoveObserver(Eq(service_impl_
.get())))
65 service_impl_
.reset();
67 RenderViewHostImplTestHarness::TearDown();
70 void GetScreenAvailabilityAndWait(
71 const std::string
& presentation_url
,
72 const base::Callback
<void(bool)>& callback
,
73 bool delegate_success
) {
74 VLOG(1) << "GetScreenAvailabilityAndWait for " << presentation_url
;
75 base::RunLoop run_loop
;
76 // This will call to |service_impl_| via mojo. Process the message
78 // The callback shouldn't be invoked since there is no availability
80 EXPECT_CALL(mock_delegate_
, AddScreenAvailabilityListener(_
, _
, _
))
82 InvokeWithoutArgs(&run_loop
, &base::RunLoop::Quit
),
83 Return(delegate_success
)));
84 service_ptr_
->GetScreenAvailability(presentation_url
, callback
);
87 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&mock_delegate_
));
90 void ExpectListenerDoesNotExist(const std::string
& presentation_url
) {
91 const auto& contexts
= service_impl_
->availability_contexts_
;
92 auto it
= contexts
.find(presentation_url
);
93 EXPECT_TRUE(it
== contexts
.end());
96 void RunLoopFor(base::TimeDelta duration
) {
97 base::RunLoop run_loop
;
98 base::MessageLoop::current()->PostDelayedTask(
99 FROM_HERE
, run_loop
.QuitClosure(), duration
);
103 void SaveQuitClosureAndRunLoop() {
104 base::RunLoop run_loop
;
105 run_loop_quit_closure_
= run_loop
.QuitClosure();
107 run_loop_quit_closure_
.Reset();
110 void ShouldNotBeCalled(bool available
) {
111 FAIL() << "Callback unexpectedly invoked with available = " << available
;
114 void SimulateScreenAvailabilityChange(
115 const std::string
& presentation_url
, bool available
) {
116 const auto& contexts
= service_impl_
->availability_contexts_
;
117 auto it
= contexts
.find(presentation_url
);
118 ASSERT_TRUE(it
!= contexts
.end());
119 it
->second
->OnScreenAvailabilityChanged(available
);
122 void ScreenAvailabilityChangedCallback(bool expected
, bool available
) {
124 EXPECT_EQ(expected
, available
);
125 if (!run_loop_quit_closure_
.is_null())
126 run_loop_quit_closure_
.Run();
129 MockPresentationServiceDelegate mock_delegate_
;
130 scoped_ptr
<PresentationServiceImpl
> service_impl_
;
131 mojo::InterfacePtr
<presentation::PresentationService
> service_ptr_
;
132 base::Closure run_loop_quit_closure_
;
136 TEST_F(PresentationServiceImplTest
, GetScreenAvailability
) {
137 std::string
presentation_url("http://fooUrl");
138 GetScreenAvailabilityAndWait(
141 &PresentationServiceImplTest::ScreenAvailabilityChangedCallback
,
142 base::Unretained(this), true),
145 // Different presentation URL.
146 GetScreenAvailabilityAndWait(
148 base::Bind(&PresentationServiceImplTest::ShouldNotBeCalled
,
149 base::Unretained(this)),
152 // Result now available; callback will be invoked with availability result.
153 SimulateScreenAvailabilityChange(presentation_url
, true);
154 SaveQuitClosureAndRunLoop();
156 EXPECT_EQ(1, callback_count_
);
158 // Result updated but callback not invoked since it's been erased.
159 SimulateScreenAvailabilityChange(presentation_url
, false);
161 // Register another callback which should immediately invoke callback
162 // since updated result is available.
163 service_ptr_
->GetScreenAvailability(
166 &PresentationServiceImplTest::ScreenAvailabilityChangedCallback
,
167 base::Unretained(this),
169 SaveQuitClosureAndRunLoop();
170 EXPECT_EQ(2, callback_count_
);
173 TEST_F(PresentationServiceImplTest
, RemoveAllListeners
) {
174 std::string
presentation_url("http://fooUrl");
175 GetScreenAvailabilityAndWait(
177 base::Bind(&PresentationServiceImplTest::ShouldNotBeCalled
,
178 base::Unretained(this)),
181 service_impl_
->RemoveAllListeners();
183 ExpectListenerDoesNotExist(presentation_url
);
185 EXPECT_EQ(0, callback_count_
);
188 TEST_F(PresentationServiceImplTest
, DidNavigateThisFrame
) {
189 std::string
presentation_url("http://fooUrl");
190 GetScreenAvailabilityAndWait(
192 base::Bind(&PresentationServiceImplTest::ShouldNotBeCalled
,
193 base::Unretained(this)),
196 service_impl_
->DidNavigateAnyFrame(
197 contents()->GetMainFrame(),
198 content::LoadCommittedDetails(),
199 content::FrameNavigateParams());
201 ExpectListenerDoesNotExist(presentation_url
);
204 TEST_F(PresentationServiceImplTest
, DidNavigateNotThisFrame
) {
205 std::string
presentation_url("http://fooUrl");
206 GetScreenAvailabilityAndWait(
209 &PresentationServiceImplTest::ScreenAvailabilityChangedCallback
,
210 base::Unretained(this),
214 // TODO(imcheng): How to get a different RenderFrameHost?
215 service_impl_
->DidNavigateAnyFrame(
217 content::LoadCommittedDetails(),
218 content::FrameNavigateParams());
220 // Availability is reported and callback is invoked since it was not
222 SimulateScreenAvailabilityChange(presentation_url
, true);
223 SaveQuitClosureAndRunLoop();
224 EXPECT_EQ(1, callback_count_
);
227 TEST_F(PresentationServiceImplTest
, ThisRenderFrameDeleted
) {
228 std::string
presentation_url("http://fooUrl");
229 GetScreenAvailabilityAndWait(
231 base::Bind(&PresentationServiceImplTest::ShouldNotBeCalled
,
232 base::Unretained(this)),
235 service_impl_
->RenderFrameDeleted(contents()->GetMainFrame());
237 ExpectListenerDoesNotExist(presentation_url
);
240 TEST_F(PresentationServiceImplTest
, NotThisRenderFrameDeleted
) {
241 std::string
presentation_url("http://fooUrl");
242 GetScreenAvailabilityAndWait(
245 &PresentationServiceImplTest::ScreenAvailabilityChangedCallback
,
246 base::Unretained(this),
250 // TODO(imcheng): How to get a different RenderFrameHost?
251 service_impl_
->RenderFrameDeleted(nullptr);
253 // Availability is reported and callback should be invoked since listener
254 // has not been deleted.
255 SimulateScreenAvailabilityChange(presentation_url
, true);
256 SaveQuitClosureAndRunLoop();
257 EXPECT_EQ(1, callback_count_
);
260 TEST_F(PresentationServiceImplTest
, GetScreenAvailabilityTwice
) {
261 std::string
presentation_url("http://fooUrl");
262 GetScreenAvailabilityAndWait(
264 base::Bind(&PresentationServiceImplTest::ShouldNotBeCalled
,
265 base::Unretained(this)),
268 // Second call should overwrite the callback from first call.
269 // It shouldn't result in an extra call to delegate.
270 service_ptr_
->GetScreenAvailability(
273 &PresentationServiceImplTest::ScreenAvailabilityChangedCallback
,
274 base::Unretained(this),
277 // Cannot use GetScreenAvailabilityAndWait here since the mock delegate
278 // won't be triggered again to quit the RunLoop.
279 RunLoopFor(base::TimeDelta::FromMilliseconds(50));
281 // Result now available; callback will be invoked with availability result.
282 SimulateScreenAvailabilityChange(presentation_url
, false);
283 SaveQuitClosureAndRunLoop();
285 EXPECT_EQ(1, callback_count_
);
288 TEST_F(PresentationServiceImplTest
, DelegateFails
) {
289 std::string
presentation_url("http://fooUrl");
290 GetScreenAvailabilityAndWait(
292 base::Bind(&PresentationServiceImplTest::ShouldNotBeCalled
,
293 base::Unretained(this)),
296 ExpectListenerDoesNotExist(presentation_url
);
299 } // namespace content