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 "content/browser/presentation/presentation_service_impl.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <iterator>
11 #include <memory>
12 #include <string>
13 #include <utility>
14 #include <vector>
15
16 #include "base/bind.h"
17 #include "base/bind_helpers.h"
18 #include "base/macros.h"
19 #include "base/optional.h"
20 #include "base/run_loop.h"
21 #include "content/browser/presentation/presentation_test_utils.h"
22 #include "content/public/browser/presentation_request.h"
23 #include "content/public/browser/presentation_service_delegate.h"
24 #include "content/public/test/mock_navigation_handle.h"
25 #include "content/test/test_render_frame_host.h"
26 #include "content/test/test_render_view_host.h"
27 #include "content/test/test_web_contents.h"
28 #include "mojo/public/cpp/bindings/interface_ptr.h"
29 #include "mojo/public/cpp/bindings/pending_receiver.h"
30 #include "mojo/public/cpp/bindings/pending_remote.h"
31 #include "mojo/public/cpp/bindings/receiver.h"
32 #include "mojo/public/cpp/bindings/remote.h"
33 #include "testing/gmock/include/gmock/gmock.h"
34
35
36 namespace content {
37
38 namespace {
39
40 const char kPresentationId[] = "presentationId";
41 const char kPresentationUrl1[] = "http://foo.com/index.html";
42 const char kPresentationUrl2[] = "http://example.com/index.html";
43 const char kPresentationUrl3[] = "http://example.net/index.html";
44
45 } // namespace
46
47 class PresentationServiceImplTest : public RenderViewHostImplTestHarness {
48 public:
PresentationServiceImplTest()49 PresentationServiceImplTest()
50 : presentation_url1_(GURL(kPresentationUrl1)),
51 presentation_url2_(GURL(kPresentationUrl2)),
52 presentation_url3_(GURL(kPresentationUrl3)) {}
53
SetUp()54 void SetUp() override {
55 RenderViewHostImplTestHarness::SetUp();
56 // This needed to keep the WebContentsObserverSanityChecker checks happy for
57 // when AppendChild is called.
58 NavigateAndCommit(GURL("about:blank"));
59
60 EXPECT_CALL(mock_delegate_, AddObserver(_, _, _)).Times(1);
61 TestRenderFrameHost* render_frame_host = contents()->GetMainFrame();
62 render_frame_host->InitializeRenderFrameIfNeeded();
63 service_impl_.reset(new PresentationServiceImpl(
64 render_frame_host, contents(), &mock_delegate_, nullptr));
65
66 mojo::PendingRemote<PresentationController> presentation_controller_remote;
67 controller_receiver_.emplace(
68 &mock_controller_,
69 presentation_controller_remote.InitWithNewPipeAndPassReceiver());
70 service_impl_->SetController(std::move(presentation_controller_remote));
71
72 presentation_urls_.push_back(presentation_url1_);
73 presentation_urls_.push_back(presentation_url2_);
74
75 expect_presentation_success_cb_ =
76 base::BindOnce(&PresentationServiceImplTest::ExpectPresentationSuccess,
77 base::Unretained(this));
78 expect_presentation_error_cb_ =
79 base::BindOnce(&PresentationServiceImplTest::ExpectPresentationError,
80 base::Unretained(this));
81 }
82
TearDown()83 void TearDown() override {
84 if (service_impl_.get()) {
85 ExpectDelegateReset();
86 EXPECT_CALL(mock_delegate_, RemoveObserver(_, _)).Times(1);
87 service_impl_.reset();
88 }
89 RenderViewHostImplTestHarness::TearDown();
90 }
91
Navigate(bool main_frame)92 void Navigate(bool main_frame) {
93 RenderFrameHost* rfh = main_rfh();
94 RenderFrameHostTester* rfh_tester = RenderFrameHostTester::For(rfh);
95 if (!main_frame)
96 rfh = rfh_tester->AppendChild("subframe");
97 MockNavigationHandle handle(GURL(), rfh);
98 handle.set_has_committed(true);
99 service_impl_->DidFinishNavigation(&handle);
100 }
101
ListenForScreenAvailabilityAndWait(const GURL & url,bool delegate_success)102 void ListenForScreenAvailabilityAndWait(const GURL& url,
103 bool delegate_success) {
104 EXPECT_CALL(mock_delegate_, AddScreenAvailabilityListener())
105 .WillOnce(Return(delegate_success));
106 service_impl_->ListenForScreenAvailability(url);
107
108 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&mock_delegate_));
109 }
110
SimulateScreenAvailabilityChangeAndWait(const GURL & url,ScreenAvailability availability)111 void SimulateScreenAvailabilityChangeAndWait(
112 const GURL& url,
113 ScreenAvailability availability) {
114 auto listener_it = service_impl_->screen_availability_listeners_.find(url);
115 ASSERT_TRUE(listener_it->second);
116
117 EXPECT_CALL(mock_controller_,
118 OnScreenAvailabilityUpdated(url, availability));
119 listener_it->second->OnScreenAvailabilityChanged(availability);
120 base::RunLoop().RunUntilIdle();
121 }
122
ExpectDelegateReset()123 void ExpectDelegateReset() {
124 EXPECT_CALL(mock_delegate_, Reset(_, _)).Times(1);
125 }
126
ExpectCleanState()127 void ExpectCleanState() {
128 EXPECT_TRUE(service_impl_->default_presentation_urls_.empty());
129 EXPECT_EQ(
130 service_impl_->screen_availability_listeners_.find(presentation_url1_),
131 service_impl_->screen_availability_listeners_.end());
132 }
133
ExpectPresentationSuccess(PresentationConnectionResultPtr result,PresentationErrorPtr error)134 void ExpectPresentationSuccess(PresentationConnectionResultPtr result,
135 PresentationErrorPtr error) {
136 EXPECT_TRUE(result);
137 EXPECT_FALSE(error);
138 presentation_cb_was_run_ = true;
139 }
140
ExpectPresentationError(PresentationConnectionResultPtr result,PresentationErrorPtr error)141 void ExpectPresentationError(PresentationConnectionResultPtr result,
142 PresentationErrorPtr error) {
143 EXPECT_FALSE(result);
144 EXPECT_TRUE(error);
145 presentation_cb_was_run_ = true;
146 }
147
ExpectPresentationCallbackWasRun() const148 void ExpectPresentationCallbackWasRun() const {
149 EXPECT_TRUE(presentation_cb_was_run_)
150 << "ExpectPresentationSuccess or ExpectPresentationError was called";
151 }
152
153 MockPresentationServiceDelegate mock_delegate_;
154 MockReceiverPresentationServiceDelegate mock_receiver_delegate_;
155
156 std::unique_ptr<PresentationServiceImpl> service_impl_;
157
158 MockPresentationController mock_controller_;
159 base::Optional<mojo::Receiver<PresentationController>> controller_receiver_;
160
161 GURL presentation_url1_;
162 GURL presentation_url2_;
163 GURL presentation_url3_;
164 std::vector<GURL> presentation_urls_;
165
166 NewPresentationCallback expect_presentation_success_cb_;
167 NewPresentationCallback expect_presentation_error_cb_;
168 bool presentation_cb_was_run_ = false;
169 };
170
TEST_F(PresentationServiceImplTest,ListenForScreenAvailability)171 TEST_F(PresentationServiceImplTest, ListenForScreenAvailability) {
172 ListenForScreenAvailabilityAndWait(presentation_url1_, true);
173
174 SimulateScreenAvailabilityChangeAndWait(presentation_url1_,
175 ScreenAvailability::AVAILABLE);
176 SimulateScreenAvailabilityChangeAndWait(presentation_url1_,
177 ScreenAvailability::UNAVAILABLE);
178 SimulateScreenAvailabilityChangeAndWait(presentation_url1_,
179 ScreenAvailability::AVAILABLE);
180 }
181
TEST_F(PresentationServiceImplTest,ScreenAvailabilityNotSupported)182 TEST_F(PresentationServiceImplTest, ScreenAvailabilityNotSupported) {
183 mock_delegate_.set_screen_availability_listening_supported(false);
184 EXPECT_CALL(mock_controller_,
185 OnScreenAvailabilityUpdated(presentation_url1_,
186 ScreenAvailability::DISABLED));
187 ListenForScreenAvailabilityAndWait(presentation_url1_, false);
188 base::RunLoop().RunUntilIdle();
189 }
190
TEST_F(PresentationServiceImplTest,OnDelegateDestroyed)191 TEST_F(PresentationServiceImplTest, OnDelegateDestroyed) {
192 ListenForScreenAvailabilityAndWait(presentation_url1_, true);
193
194 service_impl_->OnDelegateDestroyed();
195
196 // TearDown() expects |mock_delegate_| to have been notified when
197 // |service_impl_| is destroyed; this does not apply here since the delegate
198 // is destroyed first.
199 service_impl_.reset();
200 }
201
TEST_F(PresentationServiceImplTest,DidNavigateThisFrame)202 TEST_F(PresentationServiceImplTest, DidNavigateThisFrame) {
203 ListenForScreenAvailabilityAndWait(presentation_url1_, true);
204
205 ExpectDelegateReset();
206 Navigate(true);
207 ExpectCleanState();
208 }
209
TEST_F(PresentationServiceImplTest,DidNavigateOtherFrame)210 TEST_F(PresentationServiceImplTest, DidNavigateOtherFrame) {
211 ListenForScreenAvailabilityAndWait(presentation_url1_, true);
212
213 Navigate(false);
214
215 // Availability is reported and callback is invoked since it was not
216 // removed.
217 SimulateScreenAvailabilityChangeAndWait(presentation_url1_,
218 ScreenAvailability::AVAILABLE);
219 }
220
TEST_F(PresentationServiceImplTest,DelegateFails)221 TEST_F(PresentationServiceImplTest, DelegateFails) {
222 ListenForScreenAvailabilityAndWait(presentation_url1_, false);
223 ASSERT_EQ(
224 service_impl_->screen_availability_listeners_.end(),
225 service_impl_->screen_availability_listeners_.find(presentation_url1_));
226 }
227
TEST_F(PresentationServiceImplTest,SetDefaultPresentationUrls)228 TEST_F(PresentationServiceImplTest, SetDefaultPresentationUrls) {
229 EXPECT_CALL(mock_delegate_, SetDefaultPresentationUrls(
230 PresentationUrlsAre(presentation_urls_), _))
231 .Times(1);
232
233 service_impl_->SetDefaultPresentationUrls(presentation_urls_);
234
235 // Sets different DPUs.
236 std::vector<GURL> more_urls = presentation_urls_;
237 more_urls.push_back(presentation_url3_);
238
239 PresentationConnectionCallback callback;
240 EXPECT_CALL(mock_delegate_,
241 SetDefaultPresentationUrls(PresentationUrlsAre(more_urls), _))
242 .WillOnce(SaveArgByMove<1>(&callback));
243 service_impl_->SetDefaultPresentationUrls(more_urls);
244
245 PresentationInfo presentation_info(presentation_url2_, kPresentationId);
246
247 EXPECT_CALL(mock_controller_, OnDefaultPresentationStarted(_))
248 .WillOnce([&presentation_info](PresentationConnectionResultPtr result) {
249 EXPECT_THAT(*result->presentation_info, InfoEquals(presentation_info));
250 });
251 EXPECT_CALL(mock_delegate_, ListenForConnectionStateChange(_, _, _, _));
252
253 mojo::PendingRemote<PresentationConnection> presentation_connection_remote;
254 mojo::Remote<PresentationConnection> controller_remote;
255 ignore_result(
256 presentation_connection_remote.InitWithNewPipeAndPassReceiver());
257 std::move(callback).Run(PresentationConnectionResult::New(
258 blink::mojom::PresentationInfo::New(presentation_url2_, kPresentationId),
259 std::move(presentation_connection_remote),
260 controller_remote.BindNewPipeAndPassReceiver()));
261 base::RunLoop().RunUntilIdle();
262 }
263
TEST_F(PresentationServiceImplTest,SetDefaultPresentationUrlsNoopsOnNonMainFrame)264 TEST_F(PresentationServiceImplTest,
265 SetDefaultPresentationUrlsNoopsOnNonMainFrame) {
266 RenderFrameHost* rfh = main_rfh();
267 RenderFrameHostTester* rfh_tester = RenderFrameHostTester::For(rfh);
268 rfh = rfh_tester->AppendChild("subframe");
269
270 EXPECT_CALL(mock_delegate_, RemoveObserver(_, _)).Times(1);
271 EXPECT_CALL(mock_delegate_, AddObserver(_, _, _)).Times(1);
272 service_impl_.reset(
273 new PresentationServiceImpl(rfh, contents(), &mock_delegate_, nullptr));
274
275 EXPECT_CALL(mock_delegate_, SetDefaultPresentationUrls(_, _)).Times(0);
276 service_impl_->SetDefaultPresentationUrls(presentation_urls_);
277 }
278
TEST_F(PresentationServiceImplTest,ListenForConnectionStateChange)279 TEST_F(PresentationServiceImplTest, ListenForConnectionStateChange) {
280 PresentationInfo connection(presentation_url1_, kPresentationId);
281 PresentationConnectionStateChangedCallback state_changed_cb;
282 // Trigger state change. It should be propagated back up to
283 // |mock_controller_|.
284 PresentationInfo presentation_connection(presentation_url1_, kPresentationId);
285
286 EXPECT_CALL(mock_delegate_, ListenForConnectionStateChange(_, _, _, _))
287 .WillOnce(SaveArg<3>(&state_changed_cb));
288 service_impl_->ListenForConnectionStateChange(connection);
289
290 EXPECT_CALL(mock_controller_, OnConnectionStateChanged(
291 InfoPtrEquals(presentation_connection),
292 PresentationConnectionState::TERMINATED));
293 state_changed_cb.Run(PresentationConnectionStateChangeInfo(
294 PresentationConnectionState::TERMINATED));
295 base::RunLoop().RunUntilIdle();
296 }
297
TEST_F(PresentationServiceImplTest,ListenForConnectionClose)298 TEST_F(PresentationServiceImplTest, ListenForConnectionClose) {
299 PresentationInfo connection(presentation_url1_, kPresentationId);
300 PresentationConnectionStateChangedCallback state_changed_cb;
301 EXPECT_CALL(mock_delegate_, ListenForConnectionStateChange(_, _, _, _))
302 .WillOnce(SaveArg<3>(&state_changed_cb));
303 service_impl_->ListenForConnectionStateChange(connection);
304
305 // Trigger connection close. It should be propagated back up to
306 // |mock_controller_|.
307 PresentationInfo presentation_connection(presentation_url1_, kPresentationId);
308 PresentationConnectionStateChangeInfo closed_info(
309 PresentationConnectionState::CLOSED);
310 closed_info.close_reason = PresentationConnectionCloseReason::WENT_AWAY;
311 closed_info.message = "Foo";
312
313 EXPECT_CALL(
314 mock_controller_,
315 OnConnectionClosed(InfoPtrEquals(presentation_connection),
316 PresentationConnectionCloseReason::WENT_AWAY, "Foo"));
317 state_changed_cb.Run(closed_info);
318 base::RunLoop().RunUntilIdle();
319 }
320
TEST_F(PresentationServiceImplTest,SetSameDefaultPresentationUrls)321 TEST_F(PresentationServiceImplTest, SetSameDefaultPresentationUrls) {
322 EXPECT_CALL(mock_delegate_, SetDefaultPresentationUrls(_, _)).Times(1);
323 service_impl_->SetDefaultPresentationUrls(presentation_urls_);
324 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&mock_delegate_));
325
326 // Same URLs as before; no-ops.
327 service_impl_->SetDefaultPresentationUrls(presentation_urls_);
328 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&mock_delegate_));
329 }
330
TEST_F(PresentationServiceImplTest,StartPresentationSuccess)331 TEST_F(PresentationServiceImplTest, StartPresentationSuccess) {
332 PresentationConnectionCallback saved_success_cb;
333 EXPECT_CALL(mock_delegate_, StartPresentation(_, _, _))
334 .WillOnce([&saved_success_cb](const auto& request, auto success_cb,
335 auto error_cb) {
336 saved_success_cb = std::move(success_cb);
337 });
338 service_impl_->StartPresentation(presentation_urls_,
339 std::move(expect_presentation_success_cb_));
340 EXPECT_FALSE(saved_success_cb.is_null());
341 EXPECT_CALL(mock_delegate_, ListenForConnectionStateChange(_, _, _, _))
342 .Times(1);
343 std::move(saved_success_cb)
344 .Run(PresentationConnectionResult::New(
345 blink::mojom::PresentationInfo::New(presentation_url1_,
346 kPresentationId),
347 mojo::NullRemote(), mojo::NullReceiver()));
348 ExpectPresentationCallbackWasRun();
349 }
350
TEST_F(PresentationServiceImplTest,StartPresentationError)351 TEST_F(PresentationServiceImplTest, StartPresentationError) {
352 base::OnceCallback<void(const PresentationError&)> saved_error_cb;
353 EXPECT_CALL(mock_delegate_, StartPresentation(_, _, _))
354 .WillOnce([&](const auto& request, auto success_cb, auto error_cb) {
355 saved_error_cb = std::move(error_cb);
356 });
357 service_impl_->StartPresentation(presentation_urls_,
358 std::move(expect_presentation_error_cb_));
359 EXPECT_FALSE(saved_error_cb.is_null());
360 std::move(saved_error_cb)
361 .Run(PresentationError(PresentationErrorType::UNKNOWN, "Error message"));
362 ExpectPresentationCallbackWasRun();
363 }
364
TEST_F(PresentationServiceImplTest,StartPresentationInProgress)365 TEST_F(PresentationServiceImplTest, StartPresentationInProgress) {
366 EXPECT_CALL(mock_delegate_, StartPresentation(_, _, _)).Times(1);
367 // Uninvoked callbacks must outlive |service_impl_| since they get invoked
368 // at |service_impl_|'s destruction.
369 service_impl_->StartPresentation(presentation_urls_, base::DoNothing());
370
371 // This request should fail immediately, since there is already a
372 // StartPresentation in progress.
373 service_impl_->StartPresentation(presentation_urls_,
374 std::move(expect_presentation_error_cb_));
375 ExpectPresentationCallbackWasRun();
376 }
377
TEST_F(PresentationServiceImplTest,ReconnectPresentationSuccess)378 TEST_F(PresentationServiceImplTest, ReconnectPresentationSuccess) {
379 PresentationConnectionCallback saved_success_cb;
380 EXPECT_CALL(mock_delegate_, ReconnectPresentation(_, kPresentationId, _, _))
381 .WillOnce([&saved_success_cb](const auto& request, const auto& id,
382 auto success_cb, auto error_cb) {
383 saved_success_cb = std::move(success_cb);
384 });
385 service_impl_->ReconnectPresentation(
386 presentation_urls_, kPresentationId,
387 std::move(expect_presentation_success_cb_));
388 EXPECT_FALSE(saved_success_cb.is_null());
389 EXPECT_CALL(mock_delegate_, ListenForConnectionStateChange(_, _, _, _))
390 .Times(1);
391 std::move(saved_success_cb)
392 .Run(PresentationConnectionResult::New(
393 blink::mojom::PresentationInfo::New(presentation_url1_,
394 kPresentationId),
395 mojo::NullRemote(), mojo::NullReceiver()));
396 ExpectPresentationCallbackWasRun();
397 }
398
TEST_F(PresentationServiceImplTest,ReconnectPresentationError)399 TEST_F(PresentationServiceImplTest, ReconnectPresentationError) {
400 base::OnceCallback<void(const PresentationError&)> saved_error_cb;
401 EXPECT_CALL(mock_delegate_, ReconnectPresentation(_, kPresentationId, _, _))
402 .WillOnce([&](const auto& request, const std::string& id, auto success_cb,
403 auto error_cb) { saved_error_cb = std::move(error_cb); });
404 service_impl_->ReconnectPresentation(
405 presentation_urls_, kPresentationId,
406 std::move(expect_presentation_error_cb_));
407 EXPECT_FALSE(saved_error_cb.is_null());
408 std::move(saved_error_cb)
409 .Run(PresentationError(PresentationErrorType::UNKNOWN, "Error message"));
410 ExpectPresentationCallbackWasRun();
411 }
412
TEST_F(PresentationServiceImplTest,MaxPendingReconnectPresentationRequests)413 TEST_F(PresentationServiceImplTest, MaxPendingReconnectPresentationRequests) {
414 const char* presentation_url = "http://fooUrl%d";
415 const char* presentation_id = "presentationId%d";
416 int num_requests = PresentationServiceImpl::kMaxQueuedRequests;
417 int i = 0;
418 EXPECT_CALL(mock_delegate_, ReconnectPresentation(_, _, _, _))
419 .Times(num_requests);
420 for (; i < num_requests; ++i) {
421 std::vector<GURL> urls = {GURL(base::StringPrintf(presentation_url, i))};
422 // Uninvoked callbacks must outlive |service_impl_| since they get invoked
423 // at |service_impl_|'s destruction.
424 service_impl_->ReconnectPresentation(
425 urls, base::StringPrintf(presentation_id, i), base::DoNothing());
426 }
427
428 std::vector<GURL> urls = {GURL(base::StringPrintf(presentation_url, i))};
429 // Exceeded maximum queue size, should invoke mojo callback with error.
430 service_impl_->ReconnectPresentation(
431 urls, base::StringPrintf(presentation_id, i),
432 std::move(expect_presentation_error_cb_));
433 ExpectPresentationCallbackWasRun();
434 }
435
TEST_F(PresentationServiceImplTest,CloseConnection)436 TEST_F(PresentationServiceImplTest, CloseConnection) {
437 EXPECT_CALL(mock_delegate_, CloseConnection(_, _, Eq(kPresentationId)));
438 service_impl_->CloseConnection(presentation_url1_, kPresentationId);
439 }
440
TEST_F(PresentationServiceImplTest,Terminate)441 TEST_F(PresentationServiceImplTest, Terminate) {
442 EXPECT_CALL(mock_delegate_, Terminate(_, _, Eq(kPresentationId)));
443 service_impl_->Terminate(presentation_url1_, kPresentationId);
444 }
445
TEST_F(PresentationServiceImplTest,ReceiverPresentationServiceDelegate)446 TEST_F(PresentationServiceImplTest, ReceiverPresentationServiceDelegate) {
447 EXPECT_CALL(mock_receiver_delegate_, AddObserver(_, _, _)).Times(1);
448
449 PresentationServiceImpl service_impl(main_rfh(), contents(), nullptr,
450 &mock_receiver_delegate_);
451
452 ReceiverConnectionAvailableCallback callback;
453 EXPECT_CALL(mock_receiver_delegate_,
454 RegisterReceiverConnectionAvailableCallback(_))
455 .WillOnce(SaveArg<0>(&callback));
456
457 MockPresentationReceiver mock_receiver;
458 mojo::Receiver<blink::mojom::PresentationReceiver>
459 presentation_receiver_receiver(&mock_receiver);
460 service_impl.SetReceiver(
461 presentation_receiver_receiver.BindNewPipeAndPassRemote());
462 EXPECT_FALSE(callback.is_null());
463
464 PresentationInfo expected(presentation_url1_, kPresentationId);
465
466 // Client gets notified of receiver connections.
467 mojo::PendingRemote<PresentationConnection> controller_connection;
468 MockPresentationConnection mock_presentation_connection;
469 mojo::Receiver<PresentationConnection> connection_binding(
470 &mock_presentation_connection,
471 controller_connection.InitWithNewPipeAndPassReceiver());
472 mojo::Remote<PresentationConnection> receiver_connection;
473
474 EXPECT_CALL(mock_receiver,
475 OnReceiverConnectionAvailable(InfoPtrEquals(expected), _, _))
476 .Times(1);
477 callback.Run(PresentationInfo::New(expected),
478 std::move(controller_connection),
479 receiver_connection.BindNewPipeAndPassReceiver());
480 base::RunLoop().RunUntilIdle();
481
482 EXPECT_CALL(mock_receiver_delegate_, RemoveObserver(_, _)).Times(1);
483 }
484
TEST_F(PresentationServiceImplTest,ReceiverDelegateOnSubFrame)485 TEST_F(PresentationServiceImplTest, ReceiverDelegateOnSubFrame) {
486 EXPECT_CALL(mock_receiver_delegate_, AddObserver(_, _, _)).Times(1);
487
488 PresentationServiceImpl service_impl(main_rfh(), contents(), nullptr,
489 &mock_receiver_delegate_);
490 service_impl.is_main_frame_ = false;
491
492 ReceiverConnectionAvailableCallback callback;
493 EXPECT_CALL(mock_receiver_delegate_,
494 RegisterReceiverConnectionAvailableCallback(_))
495 .Times(0);
496
497 mojo::PendingRemote<PresentationController> presentation_controller_remote;
498 controller_receiver_.emplace(
499 &mock_controller_,
500 presentation_controller_remote.InitWithNewPipeAndPassReceiver());
501 service_impl.controller_delegate_ = nullptr;
502 service_impl.SetController(std::move(presentation_controller_remote));
503
504 EXPECT_CALL(mock_receiver_delegate_, Reset(_, _)).Times(0);
505 service_impl.Reset();
506
507 EXPECT_CALL(mock_receiver_delegate_, RemoveObserver(_, _)).Times(1);
508 }
509
510 } // namespace content
511