| // Copyright 2015 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_MEDIA_ROUTER_TEST_MEDIA_ROUTER_MOJO_TEST_H_ |
| #define CHROME_BROWSER_MEDIA_ROUTER_TEST_MEDIA_ROUTER_MOJO_TEST_H_ |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "chrome/browser/media/router/mojo/media_router_desktop.h" |
| #include "chrome/browser/media/router/test/provider_test_helpers.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "components/media_router/browser/test/mock_media_router.h" |
| #include "components/media_router/common/mojom/media_router.mojom.h" |
| #include "components/media_router/common/mojom/media_status.mojom.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "mojo/public/cpp/bindings/pending_receiver.h" |
| #include "mojo/public/cpp/bindings/pending_remote.h" |
| #include "mojo/public/cpp/bindings/receiver.h" |
| #include "mojo/public/cpp/bindings/receiver_set.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace media_router { |
| |
| class MediaRouterDesktop; |
| |
| // TODO(takumif): Move MockMediaRouteProvider into its own files. |
| class MockMediaRouteProvider : public mojom::MediaRouteProvider { |
| public: |
| using RouteCallback = |
| base::OnceCallback<void(const std::optional<MediaRoute>&, |
| mojom::RoutePresentationConnectionPtr, |
| const std::optional<std::string>&, |
| mojom::RouteRequestResultCode)>; |
| |
| MockMediaRouteProvider(); |
| MockMediaRouteProvider(const MockMediaRouteProvider&) = delete; |
| MockMediaRouteProvider& operator=(const MockMediaRouteProvider&) = delete; |
| ~MockMediaRouteProvider() override; |
| |
| void CreateRoute(const std::string& source_urn, |
| const std::string& sink_id, |
| const std::string& presentation_id, |
| const url::Origin& origin, |
| int frame_tree_node_id, |
| base::TimeDelta timeout, |
| CreateRouteCallback callback) override { |
| CreateRouteInternal(source_urn, sink_id, presentation_id, origin, |
| frame_tree_node_id, timeout, callback); |
| } |
| MOCK_METHOD(void, |
| CreateRouteInternal, |
| (const std::string& source_urn, |
| const std::string& sink_id, |
| const std::string& presentation_id, |
| const url::Origin& origin, |
| int frame_tree_node_id, |
| base::TimeDelta timeout, |
| CreateRouteCallback& callback)); |
| void JoinRoute(const std::string& source_urn, |
| const std::string& presentation_id, |
| const url::Origin& origin, |
| int frame_tree_node_id, |
| base::TimeDelta timeout, |
| JoinRouteCallback callback) override { |
| JoinRouteInternal(source_urn, presentation_id, origin, frame_tree_node_id, |
| timeout, callback); |
| } |
| MOCK_METHOD(void, |
| JoinRouteInternal, |
| (const std::string& source_urn, |
| const std::string& presentation_id, |
| const url::Origin& origin, |
| int frame_tree_node_id, |
| base::TimeDelta timeout, |
| JoinRouteCallback& callback)); |
| MOCK_METHOD(void, DetachRoute, (const std::string& route_id)); |
| void TerminateRoute(const std::string& route_id, |
| TerminateRouteCallback callback) override { |
| TerminateRouteInternal(route_id, callback); |
| } |
| MOCK_METHOD2(TerminateRouteInternal, |
| void(const std::string& route_id, |
| TerminateRouteCallback& callback)); |
| MOCK_METHOD1(StartObservingMediaSinks, void(const std::string& source)); |
| MOCK_METHOD1(StopObservingMediaSinks, void(const std::string& source)); |
| MOCK_METHOD2(SendRouteMessage, |
| void(const std::string& media_route_id, |
| const std::string& message)); |
| MOCK_METHOD2(SendRouteBinaryMessage, |
| void(const std::string& media_route_id, |
| const std::vector<uint8_t>& data)); |
| MOCK_METHOD1(OnPresentationSessionDetached, |
| void(const std::string& route_id)); |
| MOCK_METHOD0(StartObservingMediaRoutes, void()); |
| MOCK_METHOD0(DiscoverSinksNow, void()); |
| void BindMediaController( |
| const std::string& route_id, |
| mojo::PendingReceiver<mojom::MediaController> media_controller, |
| mojo::PendingRemote<mojom::MediaStatusObserver> observer, |
| BindMediaControllerCallback callback) override { |
| BindMediaControllerInternal(route_id, media_controller, observer, callback); |
| } |
| MOCK_METHOD4( |
| BindMediaControllerInternal, |
| void(const std::string& route_id, |
| mojo::PendingReceiver<mojom::MediaController>& media_controller, |
| mojo::PendingRemote<mojom::MediaStatusObserver>& observer, |
| BindMediaControllerCallback& callback)); |
| void GetState(GetStateCallback callback) override { |
| GetStateInternal(callback); |
| } |
| MOCK_METHOD1(GetStateInternal, void(const GetStateCallback& callback)); |
| |
| // These methods execute the callbacks with the success or timeout result |
| // code. If the callback takes a route, the route set in SetRouteToReturn() is |
| // used. |
| void RouteRequestSuccess(RouteCallback& cb) const; |
| void RouteRequestTimeout(RouteCallback& cb) const; |
| void TerminateRouteSuccess(TerminateRouteCallback& cb) const; |
| void BindMediaControllerSuccess(BindMediaControllerCallback& cb) const; |
| |
| // Sets the route to pass into callbacks. |
| void SetRouteToReturn(const MediaRoute& route); |
| |
| private: |
| // The route that is passed into callbacks. |
| std::optional<MediaRoute> route_; |
| }; |
| |
| class MockMediaStatusObserver : public mojom::MediaStatusObserver { |
| public: |
| explicit MockMediaStatusObserver( |
| mojo::PendingReceiver<mojom::MediaStatusObserver> receiver); |
| ~MockMediaStatusObserver() override; |
| |
| MOCK_METHOD1(OnMediaStatusUpdated, void(mojom::MediaStatusPtr status)); |
| |
| // Use this instead of RunUntilIdle to explicitly show what we are waiting |
| // for in a test. |
| void FlushForTesting() { receiver_.FlushForTesting(); } |
| |
| private: |
| mojo::Receiver<mojom::MediaStatusObserver> receiver_; |
| }; |
| |
| class MockMediaController : public mojom::MediaController { |
| public: |
| MockMediaController(); |
| ~MockMediaController() override; |
| |
| void Bind(mojo::PendingReceiver<mojom::MediaController> receiver); |
| mojo::PendingRemote<mojom::MediaController> BindInterfaceRemote(); |
| void CloseReceiver(); |
| |
| MOCK_METHOD0(Play, void()); |
| MOCK_METHOD0(Pause, void()); |
| MOCK_METHOD1(SetMute, void(bool mute)); |
| MOCK_METHOD1(SetVolume, void(float volume)); |
| MOCK_METHOD1(Seek, void(base::TimeDelta time)); |
| MOCK_METHOD0(NextTrack, void()); |
| MOCK_METHOD0(PreviousTrack, void()); |
| |
| private: |
| mojo::Receiver<mojom::MediaController> receiver_{this}; |
| }; |
| |
| // Tests the API call flow between the MediaRouterDesktop and the Media Router |
| // Mojo service in both directions. |
| class MediaRouterMojoTest : public ::testing::Test { |
| public: |
| MediaRouterMojoTest(); |
| MediaRouterMojoTest(const MediaRouterMojoTest&) = delete; |
| MediaRouterMojoTest& operator=(const MediaRouterMojoTest&) = delete; |
| ~MediaRouterMojoTest() override; |
| |
| protected: |
| void SetUp() override; |
| void TearDown() override; |
| |
| // Creates a MediaRouterDesktop instance to be used for this test. |
| virtual std::unique_ptr<MediaRouterDesktop> CreateMediaRouter() = 0; |
| |
| // Notify media router that the provider provides a route or a sink. |
| // Need to be called after the provider is registered. |
| void ProvideTestRoute(mojom::MediaRouteProviderId provider_id, |
| const MediaRoute::Id& route_id); |
| void ProvideTestSink(mojom::MediaRouteProviderId provider_id, |
| const MediaSink::Id& sink_id); |
| |
| // Register |mock_cast_provider_| or |mock_wired_display_provider_| with |
| // |media_router_|. |
| void RegisterCastProvider(); |
| void RegisterWiredDisplayProvider(); |
| |
| // Tests that calling MediaRouter methods result in calls to corresponding |
| // MediaRouteProvider methods. |
| void TestCreateRoute(); |
| void TestJoinRoute(const std::string& presentation_id); |
| void TestTerminateRoute(); |
| void TestSendRouteMessage(); |
| void TestSendRouteBinaryMessage(); |
| void TestDetachRoute(); |
| |
| MediaRouterDesktop* router() const { return media_router_.get(); } |
| |
| Profile* profile() { return &profile_; } |
| |
| // Mock objects. |
| testing::NiceMock<MockMediaRouteProvider> mock_cast_provider_; |
| testing::NiceMock<MockMediaRouteProvider> mock_wired_display_provider_; |
| |
| private: |
| // Helper method for RegisterCastProvider() and |
| // RegisterWiredDisplayProvider(). |
| void RegisterMediaRouteProvider(mojom::MediaRouteProvider* provider, |
| mojom::MediaRouteProviderId provider_id); |
| |
| content::BrowserTaskEnvironment task_environment_; |
| TestingProfile profile_; |
| std::unique_ptr<MediaRouterDesktop> media_router_; |
| mojo::ReceiverSet<mojom::MediaRouteProvider> provider_receivers_; |
| std::unique_ptr<MediaRoutesObserver> routes_observer_; |
| std::unique_ptr<MockMediaSinksObserver> sinks_observer_; |
| }; |
| |
| // An object whose Invoke method can be passed as a MediaRouteResponseCallback. |
| class RouteResponseCallbackHandler { |
| public: |
| RouteResponseCallbackHandler(); |
| RouteResponseCallbackHandler(const RouteResponseCallbackHandler&) = delete; |
| RouteResponseCallbackHandler& operator=(const RouteResponseCallbackHandler&) = |
| delete; |
| ~RouteResponseCallbackHandler(); |
| |
| // Calls DoInvoke with the contents of |connection| and |result|. |
| void Invoke(mojom::RoutePresentationConnectionPtr connection, |
| const RouteRequestResult& result); |
| |
| MOCK_METHOD5(DoInvoke, |
| void(const MediaRoute* route, |
| const std::string& presentation_id, |
| const std::string& error_text, |
| mojom::RouteRequestResultCode result_code, |
| mojom::RoutePresentationConnectionPtr& connection)); |
| }; |
| |
| } // namespace media_router |
| |
| #endif // CHROME_BROWSER_MEDIA_ROUTER_TEST_MEDIA_ROUTER_MOJO_TEST_H_ |