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

Unified Diff: content/renderer/presentation/presentation_dispatcher_unittest.cc

Issue 2597853002: Unit test for PresentationDispatcher (Closed)
Patch Set: Address Mark's comments Created 4 years 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 side-by-side diff with in-line comments
Download patch
Index: content/renderer/presentation/presentation_dispatcher_unittest.cc
diff --git a/content/renderer/presentation/presentation_dispatcher_unittest.cc b/content/renderer/presentation/presentation_dispatcher_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..23a08028ebf8bb3bdfd2204694d4813219fb4c3d
--- /dev/null
+++ b/content/renderer/presentation/presentation_dispatcher_unittest.cc
@@ -0,0 +1,433 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
mark a. foltz 2017/01/03 18:39:20 2017 :)
takumif 2017/01/03 23:29:51 Done. :)
+// 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_dispatcher.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/WebPresentationError.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::WebPresentationConnectionCallback;
+using blink::WebPresentationError;
+using blink::WebPresentationSessionInfo;
+using blink::WebString;
+using blink::WebURL;
+using blink::WebVector;
+using blink::mojom::PresentationError;
+using blink::mojom::PresentationErrorPtr;
+using blink::mojom::PresentationErrorType;
+using blink::mojom::PresentationService;
+using blink::mojom::PresentationServiceClientPtr;
+using blink::mojom::PresentationSessionInfo;
+using blink::mojom::PresentationSessionInfoPtr;
+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(WebURL url) : url_(url) {}
+ ~MockPresentationAvailabilityObserver() override {}
+
+ MOCK_METHOD1(availabilityChanged, void(bool is_available));
+ const WebURL url() const override { return url_; }
+
+ private:
+ const WebURL url_;
+};
+
+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(
+ PresentationSessionInfoPtr session_info,
+ ConnectionMessagePtr message_request,
+ const SendConnectionMessageCallback& callback) override {
+ SendConnectionMessageInternal(session_info.get(), message_request.get(),
+ callback);
+ }
+ MOCK_METHOD3(SendConnectionMessageInternal,
+ void(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));
+
+ // *Internal method is to work around lack of support for move-only types in
+ // GMock.
+ void ListenForConnectionMessages(
+ PresentationSessionInfoPtr session_info) override {
+ ListenForConnectionMessagesInternal(session_info.get());
+ }
+ MOCK_METHOD1(ListenForConnectionMessagesInternal,
+ void(PresentationSessionInfo* session_info));
+};
+
+class TestWebPresentationConnectionCallback
+ : public WebPresentationConnectionCallback {
+ public:
+ TestWebPresentationConnectionCallback(WebURL url,
+ WebString id,
+ bool* callback_called)
+ : url_(url), id_(id), callback_called_(callback_called) {}
+ ~TestWebPresentationConnectionCallback() override {}
+
+ void onSuccess(const WebPresentationSessionInfo& info) override {
+ *callback_called_ = true;
mark a. foltz 2017/01/03 18:39:20 It seems like the only time you would instantiate
takumif 2017/01/03 23:29:50 Done.
+ EXPECT_EQ(info.url, url_);
+ EXPECT_EQ(info.id, id_);
+ }
+
+ private:
+ const WebURL url_;
+ const WebString id_;
+ bool* const callback_called_;
+};
+
+class TestWebPresentationConnectionErrorCallback
+ : public WebPresentationConnectionCallback {
+ public:
+ TestWebPresentationConnectionErrorCallback(
+ WebPresentationError::ErrorType error_type,
+ WebString message,
+ bool* callback_called)
+ : error_type_(error_type),
+ message_(message),
+ callback_called_(callback_called) {}
+ ~TestWebPresentationConnectionErrorCallback() override {}
+
+ void onError(const WebPresentationError& error) override {
+ *callback_called_ = true;
mark a. foltz 2017/01/03 18:39:20 See comment above about making this a private memb
takumif 2017/01/03 23:29:50 Done.
+ EXPECT_EQ(error.errorType, error_type_);
+ EXPECT_EQ(error.message, message_);
+ }
+
+ private:
+ const WebPresentationError::ErrorType error_type_;
+ const WebString message_;
+ bool* const 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:
+ PresentationDispatcherTest()
+ : gurl1_(GURL("https://www.example.com/1.html")),
+ gurl2_(GURL("https://www.example.com/2.html")),
+ gurls_({gurl1_, gurl2_}),
+ url1_(WebURL(gurl1_)),
+ url2_(WebURL(gurl2_)),
+ urls_(WebVector<WebURL>(gurls_)),
+ presentation_id_(WebString::fromUTF8("test-id")),
+ array_buffer_(WebArrayBuffer::create(4, 1)),
+ observer_(url1_) {}
+ ~PresentationDispatcherTest() override {}
+
+ void SetUp() override {
+ presentation_service_ = base::MakeUnique<MockPresentationService>();
mark a. foltz 2017/01/03 18:39:20 I don't see a reason why these can't be instantiat
takumif 2017/01/03 23:29:50 Done.
+ dispatcher_ =
+ base::MakeUnique<TestPresentationDispatcher>(presentation_service());
+
+ // Set some test data.
+ *(static_cast<uint8_t*>(array_buffer_.data())) = 42;
+ }
+
+ void TearDown() override {
+ dispatcher_.reset();
+ presentation_service_.reset();
+ }
+
+ PresentationDispatcher* dispatcher() { return dispatcher_.get(); }
mark a. foltz 2017/01/03 18:39:20 It's common to declare objects used in test cases
takumif 2017/01/03 23:29:50 Done.
+ MockPresentationService* presentation_service() {
+ return presentation_service_.get();
+ }
+
+ protected:
+ const GURL gurl1_;
+ const GURL gurl2_;
+ const std::vector<GURL> gurls_;
+ const WebURL url1_;
+ const WebURL url2_;
+ const WebVector<WebURL> urls_;
+ const WebString presentation_id_;
+ const WebArrayBuffer array_buffer_;
+ MockPresentationAvailabilityObserver observer_;
+
+ private:
+ content::TestBrowserThreadBundle thread_bundle_;
+ std::unique_ptr<PresentationDispatcher> dispatcher_;
+ std::unique_ptr<MockPresentationService> presentation_service_;
+};
+
+TEST_F(PresentationDispatcherTest, TestStartSession) {
+ bool callback_called = false;
+ base::RunLoop run_loop;
+
+ EXPECT_CALL(*presentation_service(), StartSession(gurls_, _))
+ .WillOnce(Invoke([&](
+ const std::vector<GURL>& presentation_urls,
+ const PresentationService::StartSessionCallback& callback) {
+ PresentationSessionInfoPtr session_info(PresentationSessionInfo::New());
+ session_info->url = gurl1_;
+ session_info->id = presentation_id_.utf8();
+ callback.Run(std::move(session_info), PresentationErrorPtr());
+ }));
+ dispatcher()->startSession(
+ urls_, base::MakeUnique<TestWebPresentationConnectionCallback>(
+ url1_, presentation_id_, &callback_called));
+ run_loop.RunUntilIdle();
+ EXPECT_TRUE(callback_called);
+}
+
+TEST_F(PresentationDispatcherTest, TestStartSessionError) {
+ WebString error_message = WebString::fromUTF8("Test error message");
+ bool callback_called = false;
+ base::RunLoop run_loop;
+
+ EXPECT_CALL(*presentation_service(), StartSession(gurls_, _))
+ .WillOnce(Invoke(
+ [&](const std::vector<GURL>& presentation_urls,
mark a. foltz 2017/01/03 18:39:20 I slightly prefer explicit captures to default cap
takumif 2017/01/03 23:29:50 Done. Although I can capture |this| but not indivi
+ const PresentationService::StartSessionCallback& callback) {
+ PresentationErrorPtr error(PresentationError::New());
+ error->error_type = PresentationErrorType::NO_AVAILABLE_SCREENS;
+ error->message = error_message.utf8();
+ callback.Run(PresentationSessionInfoPtr(), std::move(error));
+ }));
+ dispatcher()->startSession(
+ urls_, base::MakeUnique<TestWebPresentationConnectionErrorCallback>(
+ WebPresentationError::ErrorTypeNoAvailableScreens,
+ error_message, &callback_called));
+ run_loop.RunUntilIdle();
+ EXPECT_TRUE(callback_called);
+}
+
+TEST_F(PresentationDispatcherTest, TestJoinSessionError) {
+ WebString error_message = WebString::fromUTF8("Test error message");
+ bool callback_called = false;
+ base::RunLoop run_loop;
+
+ EXPECT_CALL(*presentation_service(), JoinSession(gurls_, _, _))
+ .WillOnce(
+ Invoke([&](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());
+ PresentationErrorPtr error(PresentationError::New());
+ error->error_type = PresentationErrorType::NO_AVAILABLE_SCREENS;
+ error->message = error_message.utf8();
+ callback.Run(PresentationSessionInfoPtr(), std::move(error));
+ }));
+ dispatcher()->joinSession(
+ urls_, presentation_id_,
+ base::MakeUnique<TestWebPresentationConnectionErrorCallback>(
+ WebPresentationError::ErrorTypeNoAvailableScreens, error_message,
+ &callback_called));
+ run_loop.RunUntilIdle();
+ EXPECT_TRUE(callback_called);
+}
+
+TEST_F(PresentationDispatcherTest, TestJoinSession) {
+ bool callback_called = false;
+ base::RunLoop run_loop;
+
+ EXPECT_CALL(*presentation_service(), JoinSession(gurls_, _, _))
+ .WillOnce(Invoke([&](
+ 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());
+ PresentationSessionInfoPtr session_info(PresentationSessionInfo::New());
+ session_info->url = gurl1_;
+ session_info->id = presentation_id_.utf8();
+ callback.Run(std::move(session_info), PresentationErrorPtr());
+ }));
+ dispatcher()->joinSession(
+ urls_, presentation_id_,
+ base::MakeUnique<TestWebPresentationConnectionCallback>(
+ url1_, presentation_id_, &callback_called));
+ run_loop.RunUntilIdle();
+ EXPECT_TRUE(callback_called);
+}
+
+TEST_F(PresentationDispatcherTest, TestSendString) {
+ WebString message = WebString::fromUTF8("test message");
+ base::RunLoop run_loop;
+ EXPECT_CALL(*presentation_service(), SendConnectionMessageInternal(_, _, _))
+ .WillOnce(Invoke([&](
+ PresentationSessionInfo* session_info,
+ ConnectionMessage* message_request,
+ const PresentationService::SendConnectionMessageCallback& callback) {
+ EXPECT_EQ(gurl1_, session_info->url);
+ EXPECT_EQ(presentation_id_.utf8(), session_info->id);
+ EXPECT_TRUE(message_request->message.has_value());
+ EXPECT_EQ(message.utf8(), message_request->message.value());
+ callback.Run(true);
+ }));
+ dispatcher()->sendString(url1_, presentation_id_, message);
+ run_loop.RunUntilIdle();
+}
+
+TEST_F(PresentationDispatcherTest, TestSendArrayBuffer) {
+ base::RunLoop run_loop;
+ EXPECT_CALL(*presentation_service(), SendConnectionMessageInternal(_, _, _))
+ .WillOnce(Invoke([&](
+ PresentationSessionInfo* session_info,
+ ConnectionMessage* message_request,
+ const PresentationService::SendConnectionMessageCallback& callback) {
+ EXPECT_EQ(gurl1_, session_info->url);
+ EXPECT_EQ(presentation_id_.utf8(), session_info->id);
+ std::vector<uint8_t> data(
+ static_cast<const uint8_t*>(array_buffer_.data()),
mark a. foltz 2017/01/03 18:39:20 Consider computing this pointer in the test base c
takumif 2017/01/03 23:29:50 Done.
+ static_cast<const uint8_t*>(array_buffer_.data()) +
+ array_buffer_.byteLength());
+ EXPECT_TRUE(message_request->data.has_value());
+ EXPECT_EQ(data, message_request->data.value());
+ callback.Run(true);
+ }));
+ dispatcher()->sendArrayBuffer(
+ url1_, presentation_id_,
+ static_cast<const uint8_t*>(array_buffer_.data()),
+ array_buffer_.byteLength());
+ run_loop.RunUntilIdle();
+}
+
+TEST_F(PresentationDispatcherTest, TestSendBlobData) {
+ base::RunLoop run_loop;
+ EXPECT_CALL(*presentation_service(), SendConnectionMessageInternal(_, _, _))
+ .WillOnce(Invoke([&](
+ PresentationSessionInfo* session_info,
+ ConnectionMessage* message_request,
+ const PresentationService::SendConnectionMessageCallback& callback) {
+ EXPECT_EQ(gurl1_, session_info->url);
+ EXPECT_EQ(presentation_id_.utf8(), session_info->id);
+ std::vector<uint8_t> data(
+ static_cast<const uint8_t*>(array_buffer_.data()),
+ static_cast<const uint8_t*>(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_,
+ static_cast<const uint8_t*>(array_buffer_.data()),
+ array_buffer_.byteLength());
+ 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;
+ EXPECT_CALL(*presentation_service(), ListenForScreenAvailability(gurl1_));
+ dispatcher()->getAvailability(
+ url1_, base::MakeUnique<WebPresentationAvailabilityCallbacks>());
+ dispatcher()->OnScreenAvailabilityUpdated(url1_, true);
+ run_loop1.RunUntilIdle();
+
+ base::RunLoop run_loop2;
+ EXPECT_CALL(*presentation_service(), ListenForScreenAvailability(gurl1_));
+ dispatcher()->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);
+ EXPECT_CALL(*presentation_service(),
+ StopListeningForScreenAvailability(gurl1_));
+ dispatcher()->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();
+}
+
+} // namespace content

Powered by Google App Engine
This is Rietveld 408576698