1 // Copyright 2015 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 #ifndef CHROME_BROWSER_MEDIA_ROUTER_TEST_MEDIA_ROUTER_MOJO_TEST_H_
6 #define CHROME_BROWSER_MEDIA_ROUTER_TEST_MEDIA_ROUTER_MOJO_TEST_H_
7 
8 #include <memory>
9 #include <string>
10 #include <utility>
11 #include <vector>
12 
13 #include "base/macros.h"
14 #include "base/memory/ref_counted.h"
15 #include "chrome/browser/media/router/event_page_request_manager.h"
16 #include "chrome/browser/media/router/mojo/media_router_mojo_impl.h"
17 #include "chrome/browser/media/router/test/provider_test_helpers.h"
18 #include "chrome/test/base/testing_profile.h"
19 #include "components/media_router/browser/test/mock_media_router.h"
20 #include "components/media_router/common/mojom/media_router.mojom.h"
21 #include "content/public/test/browser_task_environment.h"
22 #include "extensions/browser/event_page_tracker.h"
23 #include "extensions/common/extension.h"
24 #include "mojo/public/cpp/bindings/pending_receiver.h"
25 #include "mojo/public/cpp/bindings/pending_remote.h"
26 #include "mojo/public/cpp/bindings/receiver.h"
27 #include "mojo/public/cpp/bindings/receiver_set.h"
28 #include "testing/gmock/include/gmock/gmock.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30 
31 namespace media_router {
32 
33 class MediaRouterMojoImpl;
34 
35 // TODO(takumif): Move MockMediaRouteProvider into its own files.
36 class MockMediaRouteProvider : public mojom::MediaRouteProvider {
37  public:
38   using RouteCallback =
39       base::OnceCallback<void(const base::Optional<MediaRoute>&,
40                               mojom::RoutePresentationConnectionPtr,
41                               const base::Optional<std::string>&,
42                               RouteRequestResult::ResultCode)>;
43 
44   MockMediaRouteProvider();
45   ~MockMediaRouteProvider() override;
46 
CreateRoute(const std::string & source_urn,const std::string & sink_id,const std::string & presentation_id,const url::Origin & origin,int tab_id,base::TimeDelta timeout,bool incognito,CreateRouteCallback callback)47   void CreateRoute(const std::string& source_urn,
48                    const std::string& sink_id,
49                    const std::string& presentation_id,
50                    const url::Origin& origin,
51                    int tab_id,
52                    base::TimeDelta timeout,
53                    bool incognito,
54                    CreateRouteCallback callback) override {
55     CreateRouteInternal(source_urn, sink_id, presentation_id, origin, tab_id,
56                         timeout, incognito, callback);
57   }
58   MOCK_METHOD8(CreateRouteInternal,
59                void(const std::string& source_urn,
60                     const std::string& sink_id,
61                     const std::string& presentation_id,
62                     const url::Origin& origin,
63                     int tab_id,
64                     base::TimeDelta timeout,
65                     bool incognito,
66                     CreateRouteCallback& callback));
JoinRoute(const std::string & source_urn,const std::string & presentation_id,const url::Origin & origin,int tab_id,base::TimeDelta timeout,bool incognito,JoinRouteCallback callback)67   void JoinRoute(const std::string& source_urn,
68                  const std::string& presentation_id,
69                  const url::Origin& origin,
70                  int tab_id,
71                  base::TimeDelta timeout,
72                  bool incognito,
73                  JoinRouteCallback callback) override {
74     JoinRouteInternal(source_urn, presentation_id, origin, tab_id, timeout,
75                       incognito, callback);
76   }
77   MOCK_METHOD7(JoinRouteInternal,
78                void(const std::string& source_urn,
79                     const std::string& presentation_id,
80                     const url::Origin& origin,
81                     int tab_id,
82                     base::TimeDelta timeout,
83                     bool incognito,
84                     JoinRouteCallback& callback));
ConnectRouteByRouteId(const std::string & source_urn,const std::string & route_id,const std::string & presentation_id,const url::Origin & origin,int tab_id,base::TimeDelta timeout,bool incognito,JoinRouteCallback callback)85   void ConnectRouteByRouteId(const std::string& source_urn,
86                              const std::string& route_id,
87                              const std::string& presentation_id,
88                              const url::Origin& origin,
89                              int tab_id,
90                              base::TimeDelta timeout,
91                              bool incognito,
92                              JoinRouteCallback callback) override {
93     ConnectRouteByRouteIdInternal(source_urn, route_id, presentation_id, origin,
94                                   tab_id, timeout, incognito, callback);
95   }
96   MOCK_METHOD8(ConnectRouteByRouteIdInternal,
97                void(const std::string& source_urn,
98                     const std::string& route_id,
99                     const std::string& presentation_id,
100                     const url::Origin& origin,
101                     int tab_id,
102                     base::TimeDelta timeout,
103                     bool incognito,
104                     JoinRouteCallback& callback));
105   MOCK_METHOD1(DetachRoute, void(const std::string& route_id));
TerminateRoute(const std::string & route_id,TerminateRouteCallback callback)106   void TerminateRoute(const std::string& route_id,
107                       TerminateRouteCallback callback) override {
108     TerminateRouteInternal(route_id, callback);
109   }
110   MOCK_METHOD2(TerminateRouteInternal,
111                void(const std::string& route_id,
112                     TerminateRouteCallback& callback));
113   MOCK_METHOD1(StartObservingMediaSinks, void(const std::string& source));
114   MOCK_METHOD1(StopObservingMediaSinks, void(const std::string& source));
115   MOCK_METHOD2(SendRouteMessage,
116                void(const std::string& media_route_id,
117                     const std::string& message));
118   MOCK_METHOD2(SendRouteBinaryMessage,
119                void(const std::string& media_route_id,
120                     const std::vector<uint8_t>& data));
121   MOCK_METHOD1(StartListeningForRouteMessages,
122                void(const std::string& route_id));
123   MOCK_METHOD1(StopListeningForRouteMessages,
124                void(const std::string& route_id));
125   MOCK_METHOD1(OnPresentationSessionDetached,
126                void(const std::string& route_id));
127   MOCK_METHOD1(StartObservingMediaRoutes, void(const std::string& source));
128   MOCK_METHOD1(StopObservingMediaRoutes, void(const std::string& source));
129   MOCK_METHOD0(EnableMdnsDiscovery, void());
130   MOCK_METHOD1(UpdateMediaSinks, void(const std::string& source));
131   MOCK_METHOD2(ProvideSinks,
132                void(const std::string&, const std::vector<MediaSinkInternal>&));
CreateMediaRouteController(const std::string & route_id,mojo::PendingReceiver<mojom::MediaController> media_controller,mojo::PendingRemote<mojom::MediaStatusObserver> observer,CreateMediaRouteControllerCallback callback)133   void CreateMediaRouteController(
134       const std::string& route_id,
135       mojo::PendingReceiver<mojom::MediaController> media_controller,
136       mojo::PendingRemote<mojom::MediaStatusObserver> observer,
137       CreateMediaRouteControllerCallback callback) override {
138     CreateMediaRouteControllerInternal(route_id, media_controller, observer,
139                                        callback);
140   }
141   MOCK_METHOD4(
142       CreateMediaRouteControllerInternal,
143       void(const std::string& route_id,
144            mojo::PendingReceiver<mojom::MediaController>& media_controller,
145            mojo::PendingRemote<mojom::MediaStatusObserver>& observer,
146            CreateMediaRouteControllerCallback& callback));
GetState(GetStateCallback callback)147   void GetState(GetStateCallback callback) override {
148     GetStateInternal(callback);
149   }
150   MOCK_METHOD1(GetStateInternal, void(const GetStateCallback& callback));
151 
152   // These methods execute the callbacks with the success or timeout result
153   // code. If the callback takes a route, the route set in SetRouteToReturn() is
154   // used.
155   void RouteRequestSuccess(RouteCallback& cb) const;
156   void RouteRequestTimeout(RouteCallback& cb) const;
157   void TerminateRouteSuccess(TerminateRouteCallback& cb) const;
158   void CreateMediaRouteControllerSuccess(
159       CreateMediaRouteControllerCallback& cb) const;
160 
161   // Sets the route to pass into callbacks.
162   void SetRouteToReturn(const MediaRoute& route);
163 
164  private:
165   // The route that is passed into callbacks.
166   base::Optional<MediaRoute> route_;
167 
168   DISALLOW_COPY_AND_ASSIGN(MockMediaRouteProvider);
169 };
170 
171 class MockEventPageTracker : public extensions::EventPageTracker {
172  public:
173   MockEventPageTracker();
174   ~MockEventPageTracker();
175 
176   MOCK_METHOD1(IsEventPageSuspended, bool(const std::string& extension_id));
177   MOCK_METHOD2(WakeEventPage,
178                bool(const std::string& extension_id,
179                     base::OnceCallback<void(bool)> callback));
180 };
181 
182 class MockEventPageRequestManager : public EventPageRequestManager {
183  public:
184   static std::unique_ptr<KeyedService> Create(content::BrowserContext* context);
185 
186   explicit MockEventPageRequestManager(content::BrowserContext* context);
187   ~MockEventPageRequestManager() override;
188 
189   MOCK_METHOD1(SetExtensionId, void(const std::string& extension_id));
190   void RunOrDefer(base::OnceClosure request,
191                   MediaRouteProviderWakeReason wake_reason) override;
192   MOCK_METHOD2(RunOrDeferInternal,
193                void(base::OnceClosure& request,
194                     MediaRouteProviderWakeReason wake_reason));
195   MOCK_METHOD0(OnMojoConnectionsReady, void());
196   MOCK_METHOD0(OnMojoConnectionError, void());
197 
198  private:
199   DISALLOW_COPY_AND_ASSIGN(MockEventPageRequestManager);
200 };
201 
202 class MockMediaStatusObserver : public mojom::MediaStatusObserver {
203  public:
204   explicit MockMediaStatusObserver(
205       mojo::PendingReceiver<mojom::MediaStatusObserver> receiver);
206   ~MockMediaStatusObserver() override;
207 
208   MOCK_METHOD1(OnMediaStatusUpdated, void(mojom::MediaStatusPtr status));
209 
210  private:
211   mojo::Receiver<mojom::MediaStatusObserver> receiver_;
212 };
213 
214 class MockMediaController : public mojom::MediaController {
215  public:
216   MockMediaController();
217   ~MockMediaController() override;
218 
219   void Bind(mojo::PendingReceiver<mojom::MediaController> receiver);
220   mojo::PendingRemote<mojom::MediaController> BindInterfaceRemote();
221   void CloseReceiver();
222 
223   MOCK_METHOD0(Play, void());
224   MOCK_METHOD0(Pause, void());
225   MOCK_METHOD1(SetMute, void(bool mute));
226   MOCK_METHOD1(SetVolume, void(float volume));
227   MOCK_METHOD1(Seek, void(base::TimeDelta time));
228   MOCK_METHOD0(NextTrack, void());
229   MOCK_METHOD0(PreviousTrack, void());
230 
231  private:
232   mojo::Receiver<mojom::MediaController> receiver_{this};
233 };
234 
235 // Tests the API call flow between the MediaRouterMojoImpl and the Media Router
236 // Mojo service in both directions.
237 class MediaRouterMojoTest : public ::testing::Test {
238  public:
239   MediaRouterMojoTest();
240   ~MediaRouterMojoTest() override;
241 
242  protected:
243   void SetUp() override;
244   void TearDown() override;
245 
246   // Creates a MediaRouterMojoImpl instance to be used for this test.
247   virtual std::unique_ptr<MediaRouterMojoImpl> CreateMediaRouter() = 0;
248 
249   // Notify media router that the provider provides a route or a sink.
250   // Need to be called after the provider is registered.
251   void ProvideTestRoute(MediaRouteProviderId provider_id,
252                         const MediaRoute::Id& route_id);
253   void ProvideTestSink(MediaRouteProviderId provider_id,
254                        const MediaSink::Id& sink_id);
255 
256   // Register |mock_extension_provider_| or |mock_wired_display_provider_| with
257   // |media_router_|.
258   void RegisterExtensionProvider();
259   void RegisterWiredDisplayProvider();
260 
261   // Tests that calling MediaRouter methods result in calls to corresponding
262   // MediaRouteProvider methods.
263   void TestCreateRoute();
264   void TestJoinRoute(const std::string& presentation_id);
265   void TestConnectRouteByRouteId();
266   void TestTerminateRoute();
267   void TestSendRouteMessage();
268   void TestSendRouteBinaryMessage();
269   void TestDetachRoute();
270 
extension_id()271   const std::string& extension_id() const { return extension_->id(); }
272 
router()273   MediaRouterMojoImpl* router() const { return media_router_.get(); }
274 
profile()275   Profile* profile() { return &profile_; }
276 
277   // Mock objects.
278   MockMediaRouteProvider mock_extension_provider_;
279   MockMediaRouteProvider mock_wired_display_provider_;
280   MockEventPageRequestManager* request_manager_ = nullptr;
281 
282  private:
283   // Helper method for RegisterExtensionProvider() and
284   // RegisterWiredDisplayProvider().
285   void RegisterMediaRouteProvider(mojom::MediaRouteProvider* provider,
286                                   MediaRouteProviderId provider_id);
287 
288   content::BrowserTaskEnvironment task_environment_;
289   scoped_refptr<const extensions::Extension> extension_;
290   TestingProfile profile_;
291   std::unique_ptr<MediaRouterMojoImpl> media_router_;
292   mojo::ReceiverSet<mojom::MediaRouteProvider> provider_receivers_;
293   std::unique_ptr<MediaRoutesObserver> routes_observer_;
294   std::unique_ptr<MockMediaSinksObserver> sinks_observer_;
295 
296   DISALLOW_COPY_AND_ASSIGN(MediaRouterMojoTest);
297 };
298 
299 // An object whose Invoke method can be passed as a MediaRouteResponseCallback.
300 class RouteResponseCallbackHandler {
301  public:
302   RouteResponseCallbackHandler();
303   ~RouteResponseCallbackHandler();
304 
305   // Calls DoInvoke with the contents of |connection| and |result|.
306   void Invoke(mojom::RoutePresentationConnectionPtr connection,
307               const RouteRequestResult& result);
308 
309   MOCK_METHOD5(DoInvoke,
310                void(const MediaRoute* route,
311                     const std::string& presentation_id,
312                     const std::string& error_text,
313                     RouteRequestResult::ResultCode result_code,
314                     mojom::RoutePresentationConnectionPtr& connection));
315 
316  private:
317   DISALLOW_COPY_AND_ASSIGN(RouteResponseCallbackHandler);
318 };
319 
320 }  // namespace media_router
321 
322 #endif  // CHROME_BROWSER_MEDIA_ROUTER_TEST_MEDIA_ROUTER_MOJO_TEST_H_
323