blob: ab2bf4d6dd1592e59ba3f0e8c012da6db26bf8b9 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include <utility>
#include "base/run_loop.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/renderer/presentation/presentation_connection_proxy.h"
#include "content/renderer/presentation/presentation_dispatcher.h"
#include "content/renderer/presentation/test_presentation_connection.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/WebKit/public/platform/modules/presentation/WebPresentationAvailabilityObserver.h"
#include "third_party/WebKit/public/platform/modules/presentation/WebPresentationConnection.h"
#include "third_party/WebKit/public/platform/modules/presentation/WebPresentationConnectionCallbacks.h"
#include "third_party/WebKit/public/platform/modules/presentation/WebPresentationController.h"
#include "third_party/WebKit/public/platform/modules/presentation/WebPresentationError.h"
#include "third_party/WebKit/public/platform/modules/presentation/WebPresentationReceiver.h"
#include "third_party/WebKit/public/platform/modules/presentation/WebPresentationSessionInfo.h"
#include "third_party/WebKit/public/web/WebArrayBuffer.h"
using ::testing::_;
using ::testing::Invoke;
using blink::WebArrayBuffer;
using blink::WebPresentationAvailabilityCallbacks;
using blink::WebPresentationAvailabilityObserver;
using blink::WebPresentationConnectionCallbacks;
using blink::WebPresentationError;
using blink::WebPresentationSessionInfo;
using blink::WebString;
using blink::WebURL;
using blink::WebVector;
using blink::mojom::PresentationConnection;
using blink::mojom::PresentationService;
using blink::mojom::PresentationServiceClientPtr;
using blink::mojom::ConnectionMessage;
using blink::mojom::ConnectionMessagePtr;
// TODO(crbug.com/576808): Add test cases for the following:
// - State changes
// - Messages received
// - Discarding queued messages when the frame navigates
// - Screen availability not supported
// - Default presentation starting
namespace content {
class MockPresentationAvailabilityObserver
: public WebPresentationAvailabilityObserver {
public:
explicit MockPresentationAvailabilityObserver(const std::vector<GURL>& urls)
: urls_(urls) {}
~MockPresentationAvailabilityObserver() override {}
MOCK_METHOD1(availabilityChanged, void(bool is_available));
const WebVector<WebURL>& urls() const override { return urls_; }
private:
const WebVector<WebURL> urls_;
};
class MockPresentationService : public PresentationService {
public:
void SetClient(PresentationServiceClientPtr client) override {}
MOCK_METHOD1(SetDefaultPresentationUrls,
void(const std::vector<GURL>& presentation_urls));
MOCK_METHOD1(ListenForScreenAvailability, void(const GURL& availability_url));
MOCK_METHOD1(StopListeningForScreenAvailability,
void(const GURL& availability_url));
MOCK_METHOD2(StartSession,
void(const std::vector<GURL>& presentation_urls,
const StartSessionCallback& callback));
MOCK_METHOD3(JoinSession,
void(const std::vector<GURL>& presentation_urls,
const base::Optional<std::string>& presentation_id,
const JoinSessionCallback& callback));
// *Internal method is to work around lack of support for move-only types in
// GMock.
void SendConnectionMessage(
const PresentationSessionInfo& session_info,
ConnectionMessagePtr message_request,
const SendConnectionMessageCallback& callback) override {
SendConnectionMessageInternal(session_info, message_request.get(),
callback);
}
MOCK_METHOD3(SendConnectionMessageInternal,
void(const PresentationSessionInfo& session_info,
ConnectionMessage* message_request,
const SendConnectionMessageCallback& callback));
MOCK_METHOD2(CloseConnection,
void(const GURL& presentation_url,
const std::string& presentation_id));
MOCK_METHOD2(Terminate,
void(const GURL& presentation_url,
const std::string& presentation_id));
MOCK_METHOD1(ListenForConnectionMessages,
void(const PresentationSessionInfo& session_info));
void SetPresentationConnection(
const PresentationSessionInfo& session_info,
blink::mojom::PresentationConnectionPtr controller_conn_ptr,
blink::mojom::PresentationConnectionRequest receiver_conn_request)
override {
SetPresentationConnection(session_info, controller_conn_ptr.get());
}
MOCK_METHOD2(SetPresentationConnection,
void(const PresentationSessionInfo& session_info,
PresentationConnection* connection));
};
class TestPresentationConnectionProxy : public PresentationConnectionProxy {
public:
TestPresentationConnectionProxy(blink::WebPresentationConnection* connection)
: PresentationConnectionProxy(connection) {}
void SendConnectionMessage(blink::mojom::ConnectionMessagePtr session_message,
const OnMessageCallback& callback) const override {
SendConnectionMessageInternal(session_message.get(), callback);
}
MOCK_CONST_METHOD2(SendConnectionMessageInternal,
void(blink::mojom::ConnectionMessage*,
const OnMessageCallback&));
};
class TestPresentationReceiver : public blink::WebPresentationReceiver {
public:
blink::WebPresentationConnection* onReceiverConnectionAvailable(
const blink::WebPresentationSessionInfo&) override {
return &connection_;
}
TestPresentationConnection connection_;
};
class MockPresentationAvailabilityCallbacks
: public blink::WebCallbacks<bool, const blink::WebPresentationError&> {
public:
MOCK_METHOD1(onSuccess, void(bool value));
MOCK_METHOD1(onError, void(const blink::WebPresentationError&));
};
class TestWebPresentationConnectionCallback
: public WebPresentationConnectionCallbacks {
public:
// Does not take ownership of |connection|.
TestWebPresentationConnectionCallback(WebURL url,
WebString id,
TestPresentationConnection* connection)
: url_(url), id_(id), callback_called_(false), connection_(connection) {}
~TestWebPresentationConnectionCallback() override {
EXPECT_TRUE(callback_called_);
}
void onSuccess(const WebPresentationSessionInfo& info) override {
callback_called_ = true;
EXPECT_EQ(info.url, url_);
EXPECT_EQ(info.id, id_);
}
blink::WebPresentationConnection* getConnection() override {
return connection_;
}
private:
const WebURL url_;
const WebString id_;
bool callback_called_;
TestPresentationConnection* connection_;
};
class TestWebPresentationConnectionErrorCallback
: public WebPresentationConnectionCallbacks {
public:
TestWebPresentationConnectionErrorCallback(
WebPresentationError::ErrorType error_type,
WebString message)
: error_type_(error_type), message_(message), callback_called_(false) {}
~TestWebPresentationConnectionErrorCallback() override {
EXPECT_TRUE(callback_called_);
}
void onError(const WebPresentationError& error) override {
callback_called_ = true;
EXPECT_EQ(error.errorType, error_type_);
EXPECT_EQ(error.message, message_);
}
blink::WebPresentationConnection* getConnection() override { return nullptr; }
private:
const WebPresentationError::ErrorType error_type_;
const WebString message_;
bool callback_called_;
};
class TestPresentationDispatcher : public PresentationDispatcher {
public:
explicit TestPresentationDispatcher(
MockPresentationService* presentation_service)
: PresentationDispatcher(nullptr),
mock_presentation_service_(presentation_service) {}
~TestPresentationDispatcher() override {}
private:
void ConnectToPresentationServiceIfNeeded() override {
if (!mock_binding_) {
mock_binding_ = base::MakeUnique<mojo::Binding<PresentationService>>(
mock_presentation_service_,
mojo::MakeRequest(&presentation_service_));
}
}
MockPresentationService* mock_presentation_service_;
std::unique_ptr<mojo::Binding<PresentationService>> mock_binding_;
};
class PresentationDispatcherTest : public ::testing::Test {
public:
using OnMessageCallback = PresentationConnectionProxy::OnMessageCallback;
enum class URLState { Available, Unavailable, Unsupported, Unknown };
PresentationDispatcherTest()
: gurl1_(GURL("https://www.example.com/1.html")),
gurl2_(GURL("https://www.example.com/2.html")),
gurl3_(GURL("https://www.example.com/3.html")),
gurl4_(GURL("https://www.example.com/4.html")),
gurls_({gurl1_, gurl2_, gurl3_, gurl4_}),
url1_(WebURL(gurl1_)),
url2_(WebURL(gurl2_)),
url3_(WebURL(gurl3_)),
url4_(WebURL(gurl4_)),
urls_(WebVector<WebURL>(gurls_)),
presentation_id_(WebString::fromUTF8("test-id")),
array_buffer_(WebArrayBuffer::create(4, 1)),
observer_(gurls_),
mock_observer1_({gurl1_, gurl2_, gurl3_}),
mock_observer2_({gurl2_, gurl3_, gurl4_}),
mock_observer3_({gurl2_, gurl3_}),
mock_observers_({&mock_observer1_, &mock_observer2_, &mock_observer3_}),
dispatcher_(&presentation_service_) {}
~PresentationDispatcherTest() override {}
void SetUp() override {
// Set some test data.
*array_buffer_data() = 42;
}
uint8_t* array_buffer_data() {
return static_cast<uint8_t*>(array_buffer_.data());
}
void ChangeURLState(const GURL& url, URLState state) {
switch (state) {
case URLState::Available:
dispatcher_.OnScreenAvailabilityUpdated(url, true);
break;
case URLState::Unavailable:
dispatcher_.OnScreenAvailabilityUpdated(url, false);
break;
case URLState::Unsupported:
dispatcher_.OnScreenAvailabilityNotSupported(url);
break;
case URLState::Unknown:
break;
}
}
// Tests that PresenationService is called for getAvailability(urls), after
// |urls| change state to |states|. This function takes ownership of
// |mock_callback|.
void TestGetAvailability(
const std::vector<GURL>& urls,
const std::vector<URLState>& states,
MockPresentationAvailabilityCallbacks* mock_callback) {
DCHECK_EQ(urls.size(), states.size());
for (const auto& url : urls) {
EXPECT_CALL(presentation_service_, ListenForScreenAvailability(url))
.Times(1);
EXPECT_CALL(presentation_service_,
StopListeningForScreenAvailability(url))
.Times(1);
}
base::RunLoop run_loop;
client()->getAvailability(urls, base::WrapUnique(mock_callback));
for (size_t i = 0; i < urls.size(); i++)
ChangeURLState(urls[i], states[i]);
run_loop.RunUntilIdle();
}
blink::WebPresentationClient* client() { return &dispatcher_; }
protected:
const GURL gurl1_;
const GURL gurl2_;
const GURL gurl3_;
const GURL gurl4_;
const std::vector<GURL> gurls_;
const WebURL url1_;
const WebURL url2_;
const WebURL url3_;
const WebURL url4_;
const WebVector<WebURL> urls_;
const WebString presentation_id_;
const WebArrayBuffer array_buffer_;
MockPresentationAvailabilityObserver observer_;
MockPresentationAvailabilityObserver mock_observer1_;
MockPresentationAvailabilityObserver mock_observer2_;
MockPresentationAvailabilityObserver mock_observer3_;
std::vector<MockPresentationAvailabilityObserver*> mock_observers_;
MockPresentationService presentation_service_;
TestPresentationDispatcher dispatcher_;
private:
content::TestBrowserThreadBundle thread_bundle_;
};
TEST_F(PresentationDispatcherTest, TestStartSession) {
TestPresentationConnection connection;
EXPECT_FALSE(connection.proxy());
{
base::RunLoop run_loop;
EXPECT_CALL(presentation_service_, ListenForConnectionMessages(_));
EXPECT_CALL(presentation_service_, SetPresentationConnection(_, _));
EXPECT_CALL(presentation_service_, StartSession(gurls_, _))
.WillOnce(Invoke([this](
const std::vector<GURL>& presentation_urls,
const PresentationService::StartSessionCallback& callback) {
PresentationSessionInfo session_info(gurl1_, presentation_id_.utf8());
callback.Run(session_info, base::nullopt);
}));
dispatcher_.startSession(
urls_, base::MakeUnique<TestWebPresentationConnectionCallback>(
url1_, presentation_id_, &connection));
run_loop.RunUntilIdle();
}
EXPECT_TRUE(connection.proxy());
}
TEST_F(PresentationDispatcherTest, TestStartSessionError) {
WebString error_message = WebString::fromUTF8("Test error message");
base::RunLoop run_loop;
EXPECT_CALL(presentation_service_, StartSession(gurls_, _))
.WillOnce(Invoke([&error_message](
const std::vector<GURL>& presentation_urls,
const PresentationService::StartSessionCallback& callback) {
callback.Run(
base::nullopt,
PresentationError(content::PRESENTATION_ERROR_NO_AVAILABLE_SCREENS,
error_message.utf8()));
}));
dispatcher_.startSession(
urls_,
base::MakeUnique<TestWebPresentationConnectionErrorCallback>(
WebPresentationError::ErrorTypeNoAvailableScreens, error_message));
run_loop.RunUntilIdle();
}
TEST_F(PresentationDispatcherTest, TestJoinSessionError) {
WebString error_message = WebString::fromUTF8("Test error message");
base::RunLoop run_loop;
EXPECT_CALL(presentation_service_, JoinSession(gurls_, _, _))
.WillOnce(Invoke([this, &error_message](
const std::vector<GURL>& presentation_urls,
const base::Optional<std::string>& presentation_id,
const PresentationService::JoinSessionCallback& callback) {
EXPECT_TRUE(presentation_id.has_value());
EXPECT_EQ(presentation_id_.utf8(), presentation_id.value());
callback.Run(
base::nullopt,
PresentationError(content::PRESENTATION_ERROR_NO_AVAILABLE_SCREENS,
error_message.utf8()));
}));
dispatcher_.joinSession(
urls_, presentation_id_,
base::MakeUnique<TestWebPresentationConnectionErrorCallback>(
WebPresentationError::ErrorTypeNoAvailableScreens, error_message));
run_loop.RunUntilIdle();
}
TEST_F(PresentationDispatcherTest, TestJoinSession) {
TestPresentationConnection connection;
EXPECT_FALSE(connection.proxy());
{
base::RunLoop run_loop;
EXPECT_CALL(presentation_service_, ListenForConnectionMessages(_));
EXPECT_CALL(presentation_service_, SetPresentationConnection(_, _));
EXPECT_CALL(presentation_service_, JoinSession(gurls_, _, _))
.WillOnce(Invoke([this](
const std::vector<GURL>& presentation_urls,
const base::Optional<std::string>& presentation_id,
const PresentationService::JoinSessionCallback& callback) {
EXPECT_TRUE(presentation_id.has_value());
EXPECT_EQ(presentation_id_.utf8(), presentation_id.value());
callback.Run(PresentationSessionInfo(gurl1_, presentation_id_.utf8()),
base::nullopt);
}));
dispatcher_.joinSession(
urls_, presentation_id_,
base::MakeUnique<TestWebPresentationConnectionCallback>(
url1_, presentation_id_, &connection));
run_loop.RunUntilIdle();
}
EXPECT_TRUE(connection.proxy());
}
TEST_F(PresentationDispatcherTest, TestSendString) {
WebString message = WebString::fromUTF8("test message");
TestPresentationConnection connection;
TestPresentationConnectionProxy connection_proxy(&connection);
base::RunLoop run_loop;
EXPECT_CALL(connection_proxy, SendConnectionMessageInternal(_, _))
.WillOnce(Invoke([this, &message](ConnectionMessage* session_message,
const OnMessageCallback& callback) {
EXPECT_EQ(blink::mojom::PresentationMessageType::TEXT,
session_message->type);
EXPECT_EQ(message.utf8(), session_message->message.value());
}));
dispatcher_.sendString(url1_, presentation_id_, message, &connection_proxy);
run_loop.RunUntilIdle();
}
TEST_F(PresentationDispatcherTest, TestSendArrayBuffer) {
TestPresentationConnection connection;
TestPresentationConnectionProxy connection_proxy(&connection);
base::RunLoop run_loop;
EXPECT_CALL(connection_proxy, SendConnectionMessageInternal(_, _))
.WillOnce(Invoke([this](ConnectionMessage* message_request,
const OnMessageCallback& callback) {
std::vector<uint8_t> data(
array_buffer_data(),
array_buffer_data() + array_buffer_.byteLength());
EXPECT_TRUE(message_request->data.has_value());
EXPECT_EQ(data, message_request->data.value());
}));
dispatcher_.sendArrayBuffer(url1_, presentation_id_, array_buffer_data(),
array_buffer_.byteLength(), &connection_proxy);
run_loop.RunUntilIdle();
}
TEST_F(PresentationDispatcherTest, TestSendBlobData) {
TestPresentationConnection connection;
TestPresentationConnectionProxy connection_proxy(&connection);
base::RunLoop run_loop;
EXPECT_CALL(connection_proxy, SendConnectionMessageInternal(_, _))
.WillOnce(Invoke([this](ConnectionMessage* message_request,
const OnMessageCallback& callback) {
std::vector<uint8_t> data(
array_buffer_data(),
array_buffer_data() + array_buffer_.byteLength());
EXPECT_TRUE(message_request->data.has_value());
EXPECT_EQ(data, message_request->data.value());
callback.Run(true);
}));
dispatcher_.sendBlobData(url1_, presentation_id_, array_buffer_data(),
array_buffer_.byteLength(), &connection_proxy);
run_loop.RunUntilIdle();
}
TEST_F(PresentationDispatcherTest, TestOnReceiverConnectionAvailable) {
PresentationSessionInfo session_info(gurl1_, presentation_id_.utf8());
blink::mojom::PresentationConnectionPtr controller_connection_ptr;
TestPresentationConnection controller_connection;
TestPresentationConnectionProxy controller_connection_proxy(
&controller_connection);
mojo::Binding<blink::mojom::PresentationConnection> binding(
&controller_connection_proxy,
mojo::MakeRequest(&controller_connection_ptr));
blink::mojom::PresentationConnectionPtr receiver_connection_ptr;
TestPresentationReceiver receiver;
dispatcher_.setReceiver(&receiver);
base::RunLoop run_loop;
EXPECT_CALL(controller_connection,
didChangeState(blink::WebPresentationConnectionState::Connected));
EXPECT_CALL(receiver.connection_,
didChangeState(blink::WebPresentationConnectionState::Connected));
dispatcher_.OnReceiverConnectionAvailable(
std::move(session_info), std::move(controller_connection_ptr),
mojo::MakeRequest(&receiver_connection_ptr));
EXPECT_TRUE(receiver_connection_ptr);
EXPECT_TRUE(receiver.connection_.proxy());
run_loop.RunUntilIdle();
}
TEST_F(PresentationDispatcherTest, TestCloseSession) {
base::RunLoop run_loop;
EXPECT_CALL(presentation_service_,
CloseConnection(gurl1_, presentation_id_.utf8()));
dispatcher_.closeSession(url1_, presentation_id_);
run_loop.RunUntilIdle();
}
TEST_F(PresentationDispatcherTest, TestTerminateSession) {
base::RunLoop run_loop;
EXPECT_CALL(presentation_service_,
Terminate(gurl1_, presentation_id_.utf8()));
dispatcher_.terminateSession(url1_, presentation_id_);
run_loop.RunUntilIdle();
}
TEST_F(PresentationDispatcherTest, TestListenForScreenAvailability) {
base::RunLoop run_loop1;
for (const auto& gurl : gurls_) {
EXPECT_CALL(presentation_service_, ListenForScreenAvailability(gurl));
EXPECT_CALL(presentation_service_,
StopListeningForScreenAvailability(gurl));
}
dispatcher_.getAvailability(
urls_, base::MakeUnique<WebPresentationAvailabilityCallbacks>());
dispatcher_.OnScreenAvailabilityUpdated(url1_, true);
run_loop1.RunUntilIdle();
base::RunLoop run_loop2;
for (const auto& gurl : gurls_)
EXPECT_CALL(presentation_service_, ListenForScreenAvailability(gurl));
client()->startListening(&observer_);
run_loop2.RunUntilIdle();
base::RunLoop run_loop3;
EXPECT_CALL(observer_, availabilityChanged(false));
dispatcher_.OnScreenAvailabilityUpdated(url1_, false);
EXPECT_CALL(observer_, availabilityChanged(true));
dispatcher_.OnScreenAvailabilityUpdated(url1_, true);
for (const auto& gurl : gurls_) {
EXPECT_CALL(presentation_service_,
StopListeningForScreenAvailability(gurl));
}
client()->stopListening(&observer_);
run_loop3.RunUntilIdle();
// After stopListening(), |observer_| should no longer be notified.
base::RunLoop run_loop4;
EXPECT_CALL(observer_, availabilityChanged(false)).Times(0);
dispatcher_.OnScreenAvailabilityUpdated(url1_, false);
run_loop4.RunUntilIdle();
}
TEST_F(PresentationDispatcherTest, TestSetDefaultPresentationUrls) {
base::RunLoop run_loop;
EXPECT_CALL(presentation_service_, SetDefaultPresentationUrls(gurls_));
dispatcher_.setDefaultPresentationUrls(urls_);
run_loop.RunUntilIdle();
}
TEST_F(PresentationDispatcherTest, GetAvailabilityOneUrlNoAvailabilityChange) {
auto* mock_callback =
new testing::StrictMock<MockPresentationAvailabilityCallbacks>();
EXPECT_CALL(presentation_service_, ListenForScreenAvailability(gurl1_))
.Times(1);
base::RunLoop run_loop;
client()->getAvailability(std::vector<GURL>({gurl1_}),
base::WrapUnique(mock_callback));
run_loop.RunUntilIdle();
}
TEST_F(PresentationDispatcherTest, GetAvailabilityOneUrlBecomesAvailable) {
auto* mock_callback = new MockPresentationAvailabilityCallbacks();
EXPECT_CALL(*mock_callback, onSuccess(true));
TestGetAvailability({url1_}, {URLState::Available}, mock_callback);
}
TEST_F(PresentationDispatcherTest, GetAvailabilityOneUrlBecomesUnavailable) {
auto* mock_callback = new MockPresentationAvailabilityCallbacks();
EXPECT_CALL(*mock_callback, onSuccess(false));
TestGetAvailability({url1_}, {URLState::Unavailable}, mock_callback);
}
TEST_F(PresentationDispatcherTest, GetAvailabilityOneUrlBecomesNotSupported) {
auto* mock_callback = new MockPresentationAvailabilityCallbacks();
EXPECT_CALL(*mock_callback, onError(_));
TestGetAvailability({url1_}, {URLState::Unsupported}, mock_callback);
}
TEST_F(PresentationDispatcherTest,
GetAvailabilityMultipleUrlsAllBecomesAvailable) {
auto* mock_callback = new MockPresentationAvailabilityCallbacks();
EXPECT_CALL(*mock_callback, onSuccess(true)).Times(1);
TestGetAvailability({url1_, url2_},
{URLState::Available, URLState::Available},
mock_callback);
}
TEST_F(PresentationDispatcherTest,
GetAvailabilityMultipleUrlsAllBecomesUnavailable) {
auto* mock_callback = new MockPresentationAvailabilityCallbacks();
EXPECT_CALL(*mock_callback, onSuccess(false)).Times(1);
TestGetAvailability({url1_, url2_},
{URLState::Unavailable, URLState::Unavailable},
mock_callback);
}
TEST_F(PresentationDispatcherTest,
GetAvailabilityMultipleUrlsAllBecomesUnsupported) {
auto* mock_callback = new MockPresentationAvailabilityCallbacks();
EXPECT_CALL(*mock_callback, onError(_)).Times(1);
TestGetAvailability({url1_, url2_},
{URLState::Unsupported, URLState::Unsupported},
mock_callback);
}
TEST_F(PresentationDispatcherTest,
GetAvailabilityReturnsDirectlyForAlreadyListeningUrls) {
// First getAvailability() call.
auto* mock_callback_1 = new MockPresentationAvailabilityCallbacks();
EXPECT_CALL(*mock_callback_1, onSuccess(false)).Times(1);
std::vector<URLState> state_seq = {URLState::Unavailable, URLState::Available,
URLState::Unavailable};
TestGetAvailability({url1_, url2_, url3_}, state_seq, mock_callback_1);
// Second getAvailability() call.
for (const auto& url : mock_observer3_.urls()) {
EXPECT_CALL(presentation_service_, ListenForScreenAvailability((GURL)url))
.Times(1);
}
auto* mock_callback_2 = new MockPresentationAvailabilityCallbacks();
EXPECT_CALL(*mock_callback_2, onSuccess(true)).Times(1);
base::RunLoop run_loop;
client()->getAvailability(mock_observer3_.urls(),
base::WrapUnique(mock_callback_2));
run_loop.RunUntilIdle();
}
TEST_F(PresentationDispatcherTest, StartListeningListenToEachURLOnce) {
for (const auto& gurl : gurls_) {
EXPECT_CALL(presentation_service_, ListenForScreenAvailability(gurl))
.Times(1);
}
base::RunLoop run_loop;
for (auto* mock_observer : mock_observers_) {
client()->getAvailability(
mock_observer->urls(),
base::MakeUnique<WebPresentationAvailabilityCallbacks>());
client()->startListening(mock_observer);
}
run_loop.RunUntilIdle();
}
TEST_F(PresentationDispatcherTest, StopListeningListenToEachURLOnce) {
for (const auto& gurl : gurls_) {
EXPECT_CALL(presentation_service_, ListenForScreenAvailability(gurl))
.Times(1);
EXPECT_CALL(presentation_service_, StopListeningForScreenAvailability(gurl))
.Times(1);
}
EXPECT_CALL(mock_observer1_, availabilityChanged(false));
EXPECT_CALL(mock_observer2_, availabilityChanged(false));
EXPECT_CALL(mock_observer3_, availabilityChanged(false));
// Set up |availability_set_| and |listening_status_|
base::RunLoop run_loop;
for (auto* mock_observer : mock_observers_) {
client()->getAvailability(
mock_observer->urls(),
base::MakeUnique<WebPresentationAvailabilityCallbacks>());
client()->startListening(mock_observer);
}
// Clean up callbacks.
ChangeURLState(gurl2_, URLState::Unavailable);
for (auto* mock_observer : mock_observers_)
client()->stopListening(mock_observer);
run_loop.RunUntilIdle();
}
TEST_F(PresentationDispatcherTest,
StopListeningDoesNotStopIfURLListenedByOthers) {
for (const auto& gurl : gurls_) {
EXPECT_CALL(presentation_service_, ListenForScreenAvailability(gurl))
.Times(1);
}
EXPECT_CALL(presentation_service_, StopListeningForScreenAvailability(gurl1_))
.Times(1);
EXPECT_CALL(presentation_service_, StopListeningForScreenAvailability(gurl2_))
.Times(0);
EXPECT_CALL(presentation_service_, StopListeningForScreenAvailability(gurl3_))
.Times(0);
// Set up |availability_set_| and |listening_status_|
base::RunLoop run_loop;
for (auto& mock_observer : mock_observers_) {
client()->getAvailability(
mock_observer->urls(),
base::MakeUnique<WebPresentationAvailabilityCallbacks>());
}
for (auto* mock_observer : mock_observers_)
client()->startListening(mock_observer);
EXPECT_CALL(mock_observer1_, availabilityChanged(false));
EXPECT_CALL(mock_observer2_, availabilityChanged(false));
EXPECT_CALL(mock_observer3_, availabilityChanged(false));
// Clean up callbacks.
ChangeURLState(gurl2_, URLState::Unavailable);
client()->stopListening(&mock_observer1_);
run_loop.RunUntilIdle();
}
TEST_F(PresentationDispatcherTest,
OnScreenAvailabilityUpdatedInvokesAvailabilityChanged) {
for (const auto& gurl : gurls_) {
EXPECT_CALL(presentation_service_, ListenForScreenAvailability(gurl))
.Times(1);
}
EXPECT_CALL(mock_observer1_, availabilityChanged(true));
base::RunLoop run_loop;
for (auto* mock_observer : mock_observers_) {
client()->getAvailability(
mock_observer->urls(),
base::MakeUnique<WebPresentationAvailabilityCallbacks>());
client()->startListening(mock_observer);
}
ChangeURLState(gurl1_, URLState::Available);
run_loop.RunUntilIdle();
EXPECT_CALL(mock_observer1_, availabilityChanged(false));
base::RunLoop run_loop_2;
ChangeURLState(gurl1_, URLState::Unavailable);
run_loop_2.RunUntilIdle();
}
TEST_F(PresentationDispatcherTest,
OnScreenAvailabilityUpdatedInvokesMultipleAvailabilityChanged) {
for (const auto& gurl : gurls_) {
EXPECT_CALL(presentation_service_, ListenForScreenAvailability(gurl))
.Times(1);
}
for (auto* mock_observer : mock_observers_)
EXPECT_CALL(*mock_observer, availabilityChanged(true));
base::RunLoop run_loop;
for (auto* mock_observer : mock_observers_) {
client()->getAvailability(
mock_observer->urls(),
base::MakeUnique<WebPresentationAvailabilityCallbacks>());
client()->startListening(mock_observer);
}
ChangeURLState(gurl2_, URLState::Available);
run_loop.RunUntilIdle();
for (auto* mock_observer : mock_observers_)
EXPECT_CALL(*mock_observer, availabilityChanged(false));
base::RunLoop run_loop_2;
ChangeURLState(gurl2_, URLState::Unavailable);
run_loop_2.RunUntilIdle();
}
} // namespace content