From 2515e12a809c08ece9e5b39b6a2f9b51e61e0f8a Mon Sep 17 00:00:00 2001
From: Bryant Chandler <bryantchandler@chromium.org>
Date: Thu, 30 Mar 2023 16:45:16 +0000
Subject: [PATCH] [fuchsia] Close async completer on destruction of server.

FIDL completers on two-way methods trigger a CHECK error if
`Reply` or `Close` isn't called before they are destroyed.
This CL adds a call to `Close` for the `WatchInfoChangeCompleter`
that is being held by `MediaPlayerImpl` to cover that case.

Bug: 1429266
Change-Id: I35dd8f3b9565614b64cc4765ddb0dfb91f7b12ab
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4384573
Reviewed-by: David Dorwin <ddorwin@chromium.org>
Commit-Queue: Bryant Chandler <bryantchandler@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1124255}
---
 .../webengine/browser/media_player_impl.cc    |  6 +++++-
 .../browser/media_player_impl_unittest.cc     | 19 +++++++++++++++++--
 2 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/fuchsia_web/webengine/browser/media_player_impl.cc b/fuchsia_web/webengine/browser/media_player_impl.cc
index bb5cd0de09c4e..425354a7f3ae3 100644
--- a/fuchsia_web/webengine/browser/media_player_impl.cc
+++ b/fuchsia_web/webengine/browser/media_player_impl.cc
@@ -103,7 +103,11 @@ MediaPlayerImpl::MediaPlayerImpl(
   pending_info_delta_.local(true);
 }
 
-MediaPlayerImpl::~MediaPlayerImpl() = default;
+MediaPlayerImpl::~MediaPlayerImpl() {
+  if (pending_info_change_callback_) {
+    pending_info_change_callback_->Close(ZX_ERR_PEER_CLOSED);
+  }
+}
 
 void MediaPlayerImpl::WatchInfoChange(
     MediaPlayerImpl::WatchInfoChangeCompleter::Sync& completer) {
diff --git a/fuchsia_web/webengine/browser/media_player_impl_unittest.cc b/fuchsia_web/webengine/browser/media_player_impl_unittest.cc
index 58d9f7bc22a70..f01e24adba77a 100644
--- a/fuchsia_web/webengine/browser/media_player_impl_unittest.cc
+++ b/fuchsia_web/webengine/browser/media_player_impl_unittest.cc
@@ -104,7 +104,7 @@ class MediaPlayerImplTest : public testing::Test {
   std::unique_ptr<MediaPlayerImpl> player_impl_;
 };
 
-// Verify that the |on_disconnect| closure is invoked if the client disconnects.
+// Verify that the `on_disconnect` closure is invoked if the client disconnects.
 TEST_F(MediaPlayerImplTest, OnDisconnectCalledOnDisconnect) {
   base::RunLoop run_loop;
   player_impl_ = std::make_unique<MediaPlayerImpl>(
@@ -113,7 +113,7 @@ TEST_F(MediaPlayerImplTest, OnDisconnectCalledOnDisconnect) {
   run_loop.Run();
 }
 
-// Verify that the |on_disconnect| closure is invoked if the client calls the
+// Verify that the `on_disconnect` closure is invoked if the client calls the
 // WatchInfoChange() API incorrectly.
 TEST_F(MediaPlayerImplTest, ClientDisconnectedOnBadApiUsage) {
   base::RunLoop on_disconnected_loop;
@@ -145,6 +145,21 @@ TEST_F(MediaPlayerImplTest, ClientDisconnectedOnBadApiUsage) {
   player_error_loop.Run();
 }
 
+// Verify that the completer is Closed on destruction of `MediaPlayerImpl`.
+// Otherwise it will trigger a CHECK for failing to reply.
+TEST_F(MediaPlayerImplTest, WatchInfoChangeAsyncCompleterClosedOnDestruction) {
+  player_impl_ = std::make_unique<MediaPlayerImpl>(
+      &fake_session_, std::move(player_server_end_),
+      MakeExpectedNotRunClosure(FROM_HERE));
+  player_->WatchInfoChange().Then([](auto result) {});
+  // The first call always replies immediately, so call a second call to hold a
+  // pending completer.
+  player_->WatchInfoChange().Then([](auto result) {});
+
+  // Pump the message loop to process the WatchInfoChange() call.
+  base::RunLoop().RunUntilIdle();
+}
+
 // Verify that the first WatchInfoChange() registers the observer.
 TEST_F(MediaPlayerImplTest, WatchInfoChangeRegistersObserver) {
   player_impl_ = std::make_unique<MediaPlayerImpl>(