Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(313)

Side by Side Diff: chrome/browser/media/cast_remoting_connector_unittest.cc

Issue 2310753002: Media Remoting: Data/Control plumbing between renderer and Media Router. (Closed)
Patch Set: Just a REBASE on ToT before commit. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 "chrome/browser/media/cast_remoting_connector.h"
6
7 #include <utility>
8 #include <vector>
9
10 #include "base/callback.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/run_loop.h"
13 #include "chrome/browser/media/router/media_route.h"
14 #include "chrome/browser/media/router/media_routes_observer.h"
15 #include "chrome/browser/media/router/media_source.h"
16 #include "chrome/browser/media/router/mock_media_router.h"
17 #include "chrome/browser/media/router/route_message.h"
18 #include "chrome/browser/media/router/route_message_observer.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/test/test_browser_thread_bundle.h"
21 #include "media/mojo/interfaces/remoting.mojom.h"
22 #include "mojo/public/cpp/bindings/binding.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 using content::BrowserThread;
27
28 using media::mojom::RemoterPtr;
29 using media::mojom::RemoterRequest;
30 using media::mojom::RemotingSourcePtr;
31 using media::mojom::RemotingSourceRequest;
32 using media::mojom::RemotingStartFailReason;
33 using media::mojom::RemotingStopReason;
34
35 using media_router::MediaRoutesObserver;
36 using media_router::MediaRoute;
37 using media_router::MediaSource;
38 using media_router::RouteMessage;
39 using media_router::RouteMessageObserver;
40
41 using ::testing::_;
42 using ::testing::AtLeast;
43
44 namespace {
45
46 constexpr char kRemotingMediaSource[] =
47 "urn:x-org.chromium.media:source:tab_content_remoting:123";
48 constexpr char kRemotingMediaSink[] = "wiggles";
49 constexpr char kRemotingMediaRoute[] =
50 "urn:x-org.chromium:media:route:garbly_gook_ssi7m4oa8oma7rasd/cast-wiggles";
51
52 // Implements basic functionality of a subset of the MediaRouter for use by the
53 // unit tests in this module. Note that MockMediaRouter will complain at runtime
54 // if any methods were called that should not have been called.
55 class FakeMediaRouter : public media_router::MockMediaRouter {
56 public:
57 FakeMediaRouter()
58 : routes_observer_(nullptr), message_observer_(nullptr),
59 weak_factory_(this) {}
60 ~FakeMediaRouter() final {}
61
62 //
63 // These methods are called by test code to create/destroy a media route and
64 // pass messages in both directions.
65 //
66
67 void OnRemotingRouteExists(bool exists) {
68 routes_.clear();
69 if (exists) {
70 routes_.push_back(MediaRoute(
71 kRemotingMediaRoute, MediaSource(routes_observer_->source_id()),
72 kRemotingMediaSink, "Cast Media Remoting", false, "", false));
73 } else {
74 // Cancel delivery of all messages in both directions.
75 inbound_messages_.clear();
76 for (const auto& entry : outbound_messages_) {
77 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
78 base::Bind(entry.second, false));
79 }
80 outbound_messages_.clear();
81 }
82 BrowserThread::PostTask(
83 BrowserThread::UI, FROM_HERE,
84 base::Bind(&FakeMediaRouter::DoUpdateRoutes,
85 weak_factory_.GetWeakPtr()));
86 }
87
88 void OnMessageFromProvider(const std::string& message) {
89 inbound_messages_.push_back(RouteMessage());
90 inbound_messages_.back().type = RouteMessage::TEXT;
91 inbound_messages_.back().text = message;
92 BrowserThread::PostTask(
93 BrowserThread::UI, FROM_HERE,
94 base::Bind(&FakeMediaRouter::DoDeliverInboundMessages,
95 weak_factory_.GetWeakPtr()));
96 }
97
98 void OnBinaryMessageFromProvider(const std::vector<uint8_t>& message) {
99 inbound_messages_.push_back(RouteMessage());
100 inbound_messages_.back().type = RouteMessage::BINARY;
101 inbound_messages_.back().binary = std::vector<uint8_t>(message);
102 BrowserThread::PostTask(
103 BrowserThread::UI, FROM_HERE,
104 base::Bind(&FakeMediaRouter::DoDeliverInboundMessages,
105 weak_factory_.GetWeakPtr()));
106 }
107
108 void TakeMessagesSentToProvider(RouteMessage::Type type,
109 std::vector<RouteMessage>* messages) {
110 decltype(outbound_messages_) untaken_messages;
111 for (const auto& entry : outbound_messages_) {
112 if (entry.first.type == type) {
113 messages->push_back(entry.first);
114 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
115 base::Bind(entry.second, true));
116 } else {
117 untaken_messages.push_back(entry);
118 }
119 }
120 outbound_messages_.swap(untaken_messages);
121 }
122
123 protected:
124 void RegisterMediaRoutesObserver(MediaRoutesObserver* observer) final {
125 CHECK(!routes_observer_);
126 routes_observer_ = observer;
127 CHECK(routes_observer_);
128 BrowserThread::PostTask(
129 BrowserThread::UI, FROM_HERE,
130 base::Bind(&FakeMediaRouter::DoUpdateRoutes,
131 weak_factory_.GetWeakPtr()));
132 }
133
134 void UnregisterMediaRoutesObserver(MediaRoutesObserver* observer) final {
135 CHECK_EQ(routes_observer_, observer);
136 routes_observer_ = nullptr;
137 }
138
139 void RegisterRouteMessageObserver(RouteMessageObserver* observer) final {
140 CHECK(!message_observer_);
141 message_observer_ = observer;
142 CHECK(message_observer_);
143 }
144
145 void UnregisterRouteMessageObserver(RouteMessageObserver* observer) final {
146 CHECK_EQ(message_observer_, observer);
147 message_observer_ = nullptr;
148 }
149
150 void SendRouteMessage(const MediaRoute::Id& route_id,
151 const std::string& text,
152 const SendRouteMessageCallback& callback) final {
153 EXPECT_EQ(message_observer_->route_id(), route_id);
154 ASSERT_FALSE(callback.is_null());
155 RouteMessage message;
156 message.type = RouteMessage::TEXT;
157 message.text = text;
158 outbound_messages_.push_back(std::make_pair(message, callback));
159 }
160
161 void SendRouteBinaryMessage(
162 const MediaRoute::Id& route_id,
163 std::unique_ptr<std::vector<uint8_t>> data,
164 const SendRouteMessageCallback& callback) final {
165 EXPECT_EQ(message_observer_->route_id(), route_id);
166 ASSERT_TRUE(!!data);
167 ASSERT_FALSE(callback.is_null());
168 RouteMessage message;
169 message.type = RouteMessage::BINARY;
170 message.binary = std::move(*data);
171 outbound_messages_.push_back(std::make_pair(message, callback));
172 }
173
174 private:
175 // Asynchronous callback to notify the MediaRoutesObserver of a change in
176 // routes.
177 void DoUpdateRoutes() {
178 if (routes_observer_)
179 routes_observer_->OnRoutesUpdated(routes_, std::vector<MediaRoute::Id>());
180 }
181
182 // Asynchronous callback to deliver messages to the RouteMessageObserver.
183 void DoDeliverInboundMessages() {
184 if (message_observer_)
185 message_observer_->OnMessagesReceived(inbound_messages_);
186 inbound_messages_.clear();
187 }
188
189 MediaRoutesObserver* routes_observer_;
190 RouteMessageObserver* message_observer_;
191
192 std::vector<MediaRoute> routes_;
193 // Messages from Cast Provider to the connector.
194 std::vector<RouteMessage> inbound_messages_;
195 // Messages from the connector to the Cast Provider.
196 using OutboundMessageAndCallback =
197 std::pair<RouteMessage, SendRouteMessageCallback>;
198 std::vector<OutboundMessageAndCallback> outbound_messages_;
199
200 base::WeakPtrFactory<FakeMediaRouter> weak_factory_;
201 };
202
203 class MockRemotingSource : public media::mojom::RemotingSource {
204 public:
205 MockRemotingSource() : binding_(this) {}
206 ~MockRemotingSource() final {}
207
208 void Bind(RemotingSourceRequest request) {
209 binding_.Bind(std::move(request));
210 }
211
212 MOCK_METHOD0(OnSinkAvailable, void());
213 MOCK_METHOD0(OnSinkGone, void());
214 MOCK_METHOD0(OnStarted, void());
215 MOCK_METHOD1(OnStartFailed, void(RemotingStartFailReason));
216 MOCK_METHOD1(OnMessageFromSink, void(const std::vector<uint8_t>&));
217 MOCK_METHOD1(OnStopped, void(RemotingStopReason));
218
219 private:
220 mojo::Binding<media::mojom::RemotingSource> binding_;
221 };
222
223 } // namespace
224
225 class CastRemotingConnectorTest : public ::testing::Test {
226 public:
227 CastRemotingConnectorTest()
228 : remoting_source_(kRemotingMediaSource),
229 connector_(&media_router_, remoting_source_.id()) {}
230
231 void TearDown() final {
232 // Allow any pending Mojo operations to complete before destruction. For
233 // example, when one end of a Mojo message pipe is closed, a task is posted
234 // to later destroy objects that were owned by the message pipe.
235 RunUntilIdle();
236 }
237
238 protected:
239 RemoterPtr CreateRemoter(MockRemotingSource* source) {
240 RemotingSourcePtr source_ptr;
241 source->Bind(mojo::GetProxy(&source_ptr));
242 RemoterPtr remoter_ptr;
243 connector_.CreateBridge(std::move(source_ptr),
244 mojo::GetProxy(&remoter_ptr));
245 return remoter_ptr;
246 }
247
248 void ProviderDiscoversSink() {
249 media_router_.OnRemotingRouteExists(true);
250 }
251
252 void ProviderLosesSink() {
253 media_router_.OnRemotingRouteExists(false);
254 }
255
256 void ConnectorSentMessageToProvider(const std::string& expected_message) {
257 std::vector<RouteMessage> messages;
258 media_router_.TakeMessagesSentToProvider(RouteMessage::TEXT, &messages);
259 bool did_see_expected_message = false;
260 for (const RouteMessage& message : messages) {
261 if (message.text && expected_message == *message.text) {
262 did_see_expected_message = true;
263 } else {
264 ADD_FAILURE()
265 << "Unexpected message: " << message.ToHumanReadableString();
266 }
267 }
268 EXPECT_TRUE(did_see_expected_message);
269 }
270
271 void ConnectorSentMessageToSink(
272 const std::vector<uint8_t>& expected_message) {
273 std::vector<RouteMessage> messages;
274 media_router_.TakeMessagesSentToProvider(RouteMessage::BINARY, &messages);
275 bool did_see_expected_message = false;
276 for (const RouteMessage& message : messages) {
277 if (message.binary && expected_message == *message.binary) {
278 did_see_expected_message = true;
279 } else {
280 ADD_FAILURE()
281 << "Unexpected message: " << message.ToHumanReadableString();
282 }
283 }
284 EXPECT_TRUE(did_see_expected_message);
285 }
286
287 void ConnectorSentNoMessagesToProvider() {
288 std::vector<RouteMessage> messages;
289 media_router_.TakeMessagesSentToProvider(RouteMessage::TEXT, &messages);
290 EXPECT_TRUE(messages.empty());
291 }
292
293 void ConnectorSentNoMessagesToSink() {
294 std::vector<RouteMessage> messages;
295 media_router_.TakeMessagesSentToProvider(RouteMessage::BINARY, &messages);
296 EXPECT_TRUE(messages.empty());
297 }
298
299 void ProviderPassesMessageFromSink(
300 const std::vector<uint8_t>& message) {
301 media_router_.OnBinaryMessageFromProvider(message);
302 }
303
304 void ProviderSaysToRemotingConnector(const std::string& message) {
305 media_router_.OnMessageFromProvider(message);
306 }
307
308 void MediaRouterTerminatesRoute() {
309 media_router_.OnRemotingRouteExists(false);
310 }
311
312 static void RunUntilIdle() {
313 base::RunLoop().RunUntilIdle();
314 }
315
316 private:
317 content::TestBrowserThreadBundle browser_thread_bundle_;
318 FakeMediaRouter media_router_;
319 const MediaSource remoting_source_;
320 CastRemotingConnector connector_;
321 };
322
323 TEST_F(CastRemotingConnectorTest, NeverNotifiesThatSinkIsAvailable) {
324 MockRemotingSource source;
325 RemoterPtr remoter = CreateRemoter(&source);
326
327 EXPECT_CALL(source, OnSinkAvailable()).Times(0);
328 EXPECT_CALL(source, OnSinkGone()).Times(AtLeast(0));
329 RunUntilIdle();
330 }
331
332 TEST_F(CastRemotingConnectorTest, NotifiesWhenSinkIsAvailableAndThenGone) {
333 MockRemotingSource source;
334 RemoterPtr remoter = CreateRemoter(&source);
335
336 EXPECT_CALL(source, OnSinkAvailable()).Times(1);
337 ProviderDiscoversSink();
338 RunUntilIdle();
339
340 EXPECT_CALL(source, OnSinkGone()).Times(AtLeast(1));
341 ProviderLosesSink();
342 RunUntilIdle();
343 }
344
345 TEST_F(CastRemotingConnectorTest,
346 NotifiesMultipleSourcesWhenSinkIsAvailableAndThenGone) {
347 MockRemotingSource source1;
348 RemoterPtr remoter1 = CreateRemoter(&source1);
349 MockRemotingSource source2;
350 RemoterPtr remoter2 = CreateRemoter(&source2);
351
352 EXPECT_CALL(source1, OnSinkAvailable()).Times(1);
353 EXPECT_CALL(source2, OnSinkAvailable()).Times(1);
354 ProviderDiscoversSink();
355 RunUntilIdle();
356
357 EXPECT_CALL(source1, OnSinkGone()).Times(AtLeast(1));
358 EXPECT_CALL(source2, OnSinkGone()).Times(AtLeast(1));
359 ProviderLosesSink();
360 RunUntilIdle();
361 }
362
363 TEST_F(CastRemotingConnectorTest, HandlesTeardownOfRemotingSourceFirst) {
364 std::unique_ptr<MockRemotingSource> source(new MockRemotingSource);
365 RemoterPtr remoter = CreateRemoter(source.get());
366
367 EXPECT_CALL(*source, OnSinkAvailable()).Times(1);
368 ProviderDiscoversSink();
369 RunUntilIdle();
370
371 source.reset();
372 RunUntilIdle();
373 }
374
375 TEST_F(CastRemotingConnectorTest, HandlesTeardownOfRemoterFirst) {
376 MockRemotingSource source;
377 RemoterPtr remoter = CreateRemoter(&source);
378
379 EXPECT_CALL(source, OnSinkAvailable()).Times(1);
380 ProviderDiscoversSink();
381 RunUntilIdle();
382
383 remoter.reset();
384 RunUntilIdle();
385 }
386
387 namespace {
388
389 // The possible ways a remoting session may be terminated in the "full
390 // run-through" tests.
391 enum HowItEnds {
392 SOURCE_TERMINATES, // The render process decides to end remoting.
393 MOJO_PIPE_CLOSES, // A Mojo message pipe closes unexpectedly.
394 ROUTE_TERMINATES, // The Media Router UI was used to terminate the route.
395 EXTERNAL_FAILURE, // The sink is cut-off, perhaps due to a network outage.
396 };
397
398 } // namespace
399
400 class CastRemotingConnectorFullSessionTest
401 : public CastRemotingConnectorTest,
402 public ::testing::WithParamInterface<HowItEnds> {
403 public:
404 HowItEnds how_it_ends() const { return GetParam(); }
405 };
406
407 // Performs a full run-through of starting and stopping remoting, with
408 // communications between source and sink established at the correct times, and
409 // tests that end-to-end behavior is correct depending on what caused the
410 // remoting session to end.
411 TEST_P(CastRemotingConnectorFullSessionTest, GoesThroughAllTheMotions) {
412 std::unique_ptr<MockRemotingSource> source(new MockRemotingSource());
413 RemoterPtr remoter = CreateRemoter(source.get());
414 std::unique_ptr<MockRemotingSource> other_source(new MockRemotingSource());
415 RemoterPtr other_remoter = CreateRemoter(other_source.get());
416
417 // Throughout this test |other_source| should not participate in the
418 // remoting session, and so these method calls should never occur:
419 EXPECT_CALL(*other_source, OnStarted()).Times(0);
420 EXPECT_CALL(*other_source, OnStopped(_)).Times(0);
421 EXPECT_CALL(*other_source, OnMessageFromSink(_)).Times(0);
422
423 // Both sinks should be notified when the Cast Provider tells the connector
424 // a remoting sink is available.
425 EXPECT_CALL(*source, OnSinkAvailable()).Times(1).RetiresOnSaturation();
426 EXPECT_CALL(*other_source, OnSinkAvailable()).Times(1).RetiresOnSaturation();
427 ProviderDiscoversSink();
428 RunUntilIdle();
429
430 // When |source| starts a remoting session, |other_source| is notified the
431 // sink is gone, the Cast Provider is notified that remoting has started,
432 // and |source| is notified that its request was successful.
433 EXPECT_CALL(*source, OnStarted()).Times(1).RetiresOnSaturation();
434 EXPECT_CALL(*other_source, OnSinkGone()).Times(1).RetiresOnSaturation();
435 remoter->Start();
436 RunUntilIdle();
437 ConnectorSentMessageToProvider("START_CAST_REMOTING:session=1");
438
439 // The |source| should now be able to send binary messages to the sink.
440 // |other_source| should not!
441 const std::vector<uint8_t> message_to_sink = { 3, 1, 4, 1, 5, 9 };
442 remoter->SendMessageToSink(message_to_sink);
443 const std::vector<uint8_t> ignored_message_to_sink = { 1, 2, 3 };
444 other_remoter->SendMessageToSink(ignored_message_to_sink);
445 RunUntilIdle();
446 ConnectorSentMessageToSink(message_to_sink);
447
448 // The sink should also be able to send binary messages to the |source|.
449 const std::vector<uint8_t> message_to_source = { 2, 7, 1, 8, 2, 8 };
450 EXPECT_CALL(*source, OnMessageFromSink(message_to_source)).Times(1)
451 .RetiresOnSaturation();
452 ProviderPassesMessageFromSink(message_to_source);
453 RunUntilIdle();
454
455 // The |other_source| should not be allowed to start a remoting session.
456 EXPECT_CALL(*other_source,
457 OnStartFailed(RemotingStartFailReason::CANNOT_START_MULTIPLE))
458 .Times(1).RetiresOnSaturation();
459 other_remoter->Start();
460 RunUntilIdle();
461 ConnectorSentNoMessagesToProvider();
462
463 // What happens from here depends on how this remoting session will end...
464 switch (how_it_ends()) {
465 case SOURCE_TERMINATES: {
466 // When the |source| stops the remoting session, the Cast Provider is
467 // notified the session has stopped, and the |source| receives both an
468 // OnStopped() and an OnSinkGone() notification.
469 const RemotingStopReason reason = RemotingStopReason::LOCAL_PLAYBACK;
470 EXPECT_CALL(*source, OnSinkGone()).Times(1).RetiresOnSaturation();
471 EXPECT_CALL(*source, OnStopped(reason)).Times(1).RetiresOnSaturation();
472 remoter->Stop(reason);
473 RunUntilIdle();
474 ConnectorSentMessageToProvider("STOP_CAST_REMOTING:session=1");
475
476 // Since remoting is stopped, any further messaging in either direction
477 // must be dropped.
478 const std::vector<uint8_t> message_to_sink = { 1, 6, 1, 8, 0, 3 };
479 const std::vector<uint8_t> message_to_source = { 6, 2, 8, 3, 1, 8 };
480 EXPECT_CALL(*source, OnMessageFromSink(_)).Times(0);
481 remoter->SendMessageToSink(message_to_sink);
482 ProviderPassesMessageFromSink(message_to_source);
483 RunUntilIdle();
484 ConnectorSentNoMessagesToSink();
485
486 // When the sink is ready, the Cast Provider sends a notification to the
487 // connector. The connector will notify both sources that a sink is once
488 // again available.
489 EXPECT_CALL(*source, OnSinkAvailable()).Times(1).RetiresOnSaturation();
490 EXPECT_CALL(*other_source, OnSinkAvailable()).Times(1)
491 .RetiresOnSaturation();
492 ProviderSaysToRemotingConnector("STOPPED_CAST_REMOTING:session=1");
493 RunUntilIdle();
494
495 // When the sink is no longer available, the Cast Provider notifies the
496 // connector, and both sources are then notified the sink is gone.
497 EXPECT_CALL(*source, OnSinkGone()).Times(AtLeast(1));
498 EXPECT_CALL(*other_source, OnSinkGone()).Times(AtLeast(1));
499 ProviderLosesSink();
500 RunUntilIdle();
501
502 break;
503 }
504
505 case MOJO_PIPE_CLOSES:
506 // When the Mojo pipes for |other_source| close, this should not affect
507 // the current remoting session.
508 other_source.reset();
509 other_remoter.reset();
510 RunUntilIdle();
511 ConnectorSentNoMessagesToProvider();
512
513 // Now, when the Mojo pipes for |source| close, the Cast Provider will be
514 // notified that the session has stopped.
515 source.reset();
516 remoter.reset();
517 RunUntilIdle();
518 ConnectorSentMessageToProvider("STOP_CAST_REMOTING:session=1");
519
520 // The Cast Provider will detect when the sink is ready for the next
521 // remoting session, and then notify the connector. However, there are no
522 // sources to propagate this notification to.
523 ProviderSaysToRemotingConnector("STOPPED_CAST_REMOTING:session=1");
524 RunUntilIdle();
525
526 break;
527
528 case ROUTE_TERMINATES:
529 // When the Media Router terminates the route (e.g., because a user
530 // terminated the route from the UI), the source and sink are immediately
531 // cut off from one another.
532 EXPECT_CALL(*source, OnSinkGone()).Times(AtLeast(1));
533 EXPECT_CALL(*source, OnStopped(RemotingStopReason::ROUTE_TERMINATED))
534 .Times(1).RetiresOnSaturation();
535 EXPECT_CALL(*other_source, OnSinkGone()).Times(AtLeast(0));
536 MediaRouterTerminatesRoute();
537 RunUntilIdle();
538 ConnectorSentNoMessagesToProvider();
539
540 // Furthermore, the connector and Cast Provider are also cut off from one
541 // another and should not be able to exchange messages anymore. Therefore,
542 // the connector will never try to notify the sources that the sink is
543 // available again.
544 EXPECT_CALL(*source, OnSinkAvailable()).Times(0);
545 EXPECT_CALL(*other_source, OnSinkAvailable()).Times(0);
546 ProviderSaysToRemotingConnector("STOPPED_CAST_REMOTING:session=1");
547 RunUntilIdle();
548
549 break;
550
551 case EXTERNAL_FAILURE: {
552 // When the Cast Provider is cut-off from the sink, it sends a fail
553 // notification to the connector. The connector, in turn, force-stops the
554 // remoting session and notifies the |source|.
555 EXPECT_CALL(*source, OnSinkGone()).Times(1).RetiresOnSaturation();
556 EXPECT_CALL(*source, OnStopped(RemotingStopReason::UNEXPECTED_FAILURE))
557 .Times(1).RetiresOnSaturation();
558 ProviderSaysToRemotingConnector("FAILED_CAST_REMOTING:session=1");
559 RunUntilIdle();
560
561 // Since remoting is stopped, any further messaging in either direction
562 // must be dropped.
563 const std::vector<uint8_t> message_to_sink = { 1, 6, 1, 8, 0, 3 };
564 const std::vector<uint8_t> message_to_source = { 6, 2, 8, 3, 1, 8 };
565 EXPECT_CALL(*source, OnMessageFromSink(_)).Times(0);
566 remoter->SendMessageToSink(message_to_sink);
567 ProviderPassesMessageFromSink(message_to_source);
568 RunUntilIdle();
569 ConnectorSentNoMessagesToSink();
570
571 // Later, if whatever caused the external failure has resolved, the Cast
572 // Provider will notify the connector that the sink is available one
573 // again.
574 EXPECT_CALL(*source, OnSinkAvailable()).Times(1).RetiresOnSaturation();
575 EXPECT_CALL(*other_source, OnSinkAvailable()).Times(1)
576 .RetiresOnSaturation();
577 ProviderSaysToRemotingConnector("STOPPED_CAST_REMOTING:session=1");
578 RunUntilIdle();
579
580 // When the sink is no longer available, the Cast Provider notifies the
581 // connector, and both sources are then notified the sink is gone.
582 EXPECT_CALL(*source, OnSinkGone()).Times(AtLeast(1));
583 EXPECT_CALL(*other_source, OnSinkGone()).Times(AtLeast(1));
584 ProviderLosesSink();
585 RunUntilIdle();
586
587 break;
588 }
589 }
590 }
591
592 INSTANTIATE_TEST_CASE_P(, CastRemotingConnectorFullSessionTest,
593 ::testing::Values(SOURCE_TERMINATES,
594 MOJO_PIPE_CLOSES,
595 ROUTE_TERMINATES,
596 EXTERNAL_FAILURE));
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698