1 // Copyright 2018 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 #include "components/mirroring/service/session_monitor.h"
6 
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/json/json_reader.h"
10 #include "base/json/json_writer.h"
11 #include "base/macros.h"
12 #include "base/test/mock_callback.h"
13 #include "base/test/task_environment.h"
14 #include "base/time/default_tick_clock.h"
15 #include "components/mirroring/service/message_dispatcher.h"
16 #include "components/mirroring/service/mirror_settings.h"
17 #include "components/mirroring/service/value_util.h"
18 #include "components/mirroring/service/wifi_status_monitor.h"
19 #include "media/cast/cast_environment.h"
20 #include "media/cast/test/utility/net_utility.h"
21 #include "mojo/public/cpp/bindings/receiver.h"
22 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
23 #include "net/base/ip_endpoint.h"
24 #include "services/network/test/test_url_loader_factory.h"
25 #include "testing/gmock/include/gmock/gmock.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 
28 using mirroring::mojom::CastMessage;
29 using mirroring::mojom::SessionError;
30 
31 namespace mirroring {
32 
33 namespace {
34 
35 constexpr int kRetentionBytes = 512 * 1024;  // 512k.
36 
VerifyStringValue(const base::Value & raw_value,const std::string & key,const std::string & expected_value)37 void VerifyStringValue(const base::Value& raw_value,
38                        const std::string& key,
39                        const std::string& expected_value) {
40   std::string data;
41   EXPECT_TRUE(GetString(raw_value, key, &data));
42   EXPECT_EQ(expected_value, data);
43 }
44 
VerifyBoolValue(const base::Value & raw_value,const std::string & key,bool expected_value)45 void VerifyBoolValue(const base::Value& raw_value,
46                      const std::string& key,
47                      bool expected_value) {
48   bool data;
49   EXPECT_TRUE(GetBool(raw_value, key, &data));
50   EXPECT_EQ(expected_value, data);
51 }
52 
VerifyDoubleValue(const base::Value & raw_value,const std::string & key,double expected_value)53 void VerifyDoubleValue(const base::Value& raw_value,
54                        const std::string& key,
55                        double expected_value) {
56   double data;
57   EXPECT_TRUE(GetDouble(raw_value, key, &data));
58   EXPECT_NEAR(expected_value, data, DBL_EPSILON * 2);
59 }
60 
VerifyWifiStatus(const base::Value & raw_value,double starting_snr,int starting_speed,int num_of_status)61 void VerifyWifiStatus(const base::Value& raw_value,
62                       double starting_snr,
63                       int starting_speed,
64                       int num_of_status) {
65   EXPECT_TRUE(raw_value.is_dict());
66   auto* found = raw_value.FindKey("tags");
67   EXPECT_TRUE(found && found->is_dict());
68   auto* wifi_status = found->FindKey("receiverWifiStatus");
69   EXPECT_TRUE(wifi_status && wifi_status->is_list());
70   base::Value::ConstListView status_list = wifi_status->GetList();
71   EXPECT_EQ(num_of_status, static_cast<int>(status_list.size()));
72   for (int i = 0; i < num_of_status; ++i) {
73     double snr = -1;
74     int32_t speed = -1;
75     int32_t timestamp = 0;
76     EXPECT_TRUE(GetDouble(status_list[i], "wifiSnr", &snr));
77     EXPECT_EQ(starting_snr + i, snr);
78     EXPECT_TRUE(GetInt(status_list[i], "wifiSpeed", &speed));
79     EXPECT_EQ(starting_speed + i, speed);
80     EXPECT_TRUE(GetInt(status_list[i], "timestamp", &timestamp));
81   }
82 }
83 
84 }  // namespace
85 
86 class SessionMonitorTest : public mojom::CastMessageChannel,
87                            public ::testing::Test {
88  public:
SessionMonitorTest()89   SessionMonitorTest()
90       : receiver_address_(media::cast::test::GetFreeLocalPort().address()),
91         message_dispatcher_(receiver_.BindNewPipeAndPassRemote(),
92                             inbound_channel_.BindNewPipeAndPassReceiver(),
93                             error_callback_.Get()) {}
~SessionMonitorTest()94   ~SessionMonitorTest() override {}
95 
96  protected:
97   // mojom::CastMessageChannel implementation.
98   MOCK_METHOD1(Send, void(mojom::CastMessagePtr));
99 
CreateSessionMonitor(int max_bytes,std::string * expected_settings)100   void CreateSessionMonitor(int max_bytes, std::string* expected_settings) {
101     EXPECT_CALL(*this, Send(::testing::_)).Times(::testing::AtLeast(1));
102     mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory;
103     auto test_url_loader_factory =
104         std::make_unique<network::TestURLLoaderFactory>();
105     url_loader_factory_ = test_url_loader_factory.get();
106     mojo::MakeSelfOwnedReceiver(
107         std::move(test_url_loader_factory),
108         url_loader_factory.InitWithNewPipeAndPassReceiver());
109     MirrorSettings mirror_settings;
110     base::Value session_tags(base::Value::Type::DICTIONARY);
111     base::Value settings = mirror_settings.ToDictionaryValue();
112     if (expected_settings)
113       EXPECT_TRUE(base::JSONWriter::Write(settings, expected_settings));
114     session_tags.SetKey("mirrorSettings", std::move(settings));
115     session_tags.SetKey("receiverProductName", base::Value("ChromeCast"));
116     session_tags.SetKey("shouldCaptureAudio", base::Value(true));
117     session_tags.SetKey("shouldCaptureVideo", base::Value(true));
118     session_monitor_ = std::make_unique<SessionMonitor>(
119         max_bytes, receiver_address_, std::move(session_tags),
120         std::move(url_loader_factory));
121   }
122 
123   // Generates and sends |num_of_responses| WiFi status.
SendWifiStatus(double starting_snr,int starting_speed,int num_of_responses)124   void SendWifiStatus(double starting_snr,
125                       int starting_speed,
126                       int num_of_responses) {
127     for (int i = 0; i < num_of_responses; ++i) {
128       CastMessage message;
129       message.message_namespace = mojom::kWebRtcNamespace;
130       message.json_format_data =
131           "{\"seqNum\":" +
132           std::to_string(message_dispatcher_.GetNextSeqNumber()) +
133           ","
134           "\"type\": \"STATUS_RESPONSE\","
135           "\"result\": \"ok\","
136           "\"status\": {"
137           "\"wifiSnr\":" +
138           std::to_string(starting_snr + i) +
139           ","
140           "\"wifiSpeed\": [1234, 5678, 3000, " +
141           std::to_string(starting_speed + i) +
142           "],"
143           "\"wifiFcsError\": [12, 13, 12, 12]}"  // This will be ignored.
144           "}";
145       inbound_channel_->Send(message.Clone());
146       task_environment_.RunUntilIdle();
147     }
148   }
149 
StartStreamingSession()150   void StartStreamingSession() {
151     cast_environment_ = new media::cast::CastEnvironment(
152         base::DefaultTickClock::GetInstance(),
153         task_environment_.GetMainThreadTaskRunner(),
154         task_environment_.GetMainThreadTaskRunner(),
155         task_environment_.GetMainThreadTaskRunner());
156     EXPECT_TRUE(session_monitor_);
157     auto wifi_status_monitor =
158         std::make_unique<WifiStatusMonitor>(&message_dispatcher_);
159     session_monitor_->StartStreamingSession(
160         cast_environment_, std::move(wifi_status_monitor),
161         SessionMonitor::AUDIO_AND_VIDEO, false /* is_remoting */);
162     task_environment_.RunUntilIdle();
163   }
164 
StopStreamingSession()165   void StopStreamingSession() {
166     EXPECT_TRUE(session_monitor_);
167     session_monitor_->StopStreamingSession();
168     cast_environment_ = nullptr;
169     task_environment_.RunUntilIdle();
170   }
171 
AssembleBundleAndVerify(const std::vector<int32_t> & bundle_sizes)172   std::vector<SessionMonitor::EventsAndStats> AssembleBundleAndVerify(
173       const std::vector<int32_t>& bundle_sizes) {
174     std::vector<SessionMonitor::EventsAndStats> bundles =
175         session_monitor_->AssembleBundlesAndClear(bundle_sizes);
176     task_environment_.RunUntilIdle();
177     EXPECT_EQ(bundle_sizes.size(), bundles.size());
178     for (size_t i = 0; i < bundles.size(); ++i) {
179       EXPECT_FALSE(bundles[i].first.empty());
180       EXPECT_FALSE(bundles[i].second.empty());
181       EXPECT_LE(
182           static_cast<int>(bundles[i].first.size() + bundles[i].second.size()),
183           bundle_sizes[i]);
184     }
185     return bundles;
186   }
187 
ReadStats(const std::string & stats_string)188   base::Value ReadStats(const std::string& stats_string) {
189     std::unique_ptr<base::Value> stats_ptr =
190         base::JSONReader::ReadDeprecated(stats_string);
191     EXPECT_TRUE(stats_ptr);
192     base::Value stats = base::Value::FromUniquePtrValue(std::move(stats_ptr));
193     EXPECT_TRUE(stats.is_list());
194     return stats;
195   }
196 
SendReceiverSetupInfo(const std::string & setup_info)197   void SendReceiverSetupInfo(const std::string& setup_info) {
198     url_loader_factory_->AddResponse(
199         "http://" + receiver_address_.ToString() + ":8008/setup/eureka_info",
200         setup_info);
201     task_environment_.RunUntilIdle();
202   }
203 
TakeSnapshot()204   void TakeSnapshot() {
205     ASSERT_TRUE(session_monitor_);
206     session_monitor_->TakeSnapshot();
207     task_environment_.RunUntilIdle();
208   }
209 
ReportError(SessionError error)210   void ReportError(SessionError error) {
211     ASSERT_TRUE(session_monitor_);
212     session_monitor_->OnStreamingError(error);
213     task_environment_.RunUntilIdle();
214   }
215 
216  private:
217   base::test::TaskEnvironment task_environment_;
218   const net::IPAddress receiver_address_;
219   mojo::Receiver<mojom::CastMessageChannel> receiver_{this};
220   mojo::Remote<mojom::CastMessageChannel> inbound_channel_;
221   base::MockCallback<MessageDispatcher::ErrorCallback> error_callback_;
222   MessageDispatcher message_dispatcher_;
223   network::TestURLLoaderFactory* url_loader_factory_ = nullptr;
224   std::unique_ptr<SessionMonitor> session_monitor_;
225   scoped_refptr<media::cast::CastEnvironment> cast_environment_ = nullptr;
226 
227   DISALLOW_COPY_AND_ASSIGN(SessionMonitorTest);
228 };
229 
TEST_F(SessionMonitorTest,ProvidesExpectedTags)230 TEST_F(SessionMonitorTest, ProvidesExpectedTags) {
231   std::string expected_settings;
232   CreateSessionMonitor(kRetentionBytes, &expected_settings);
233   StartStreamingSession();
234   SendWifiStatus(34, 2000, 5);
235   std::vector<int32_t> bundle_sizes({kRetentionBytes});
236   std::vector<SessionMonitor::EventsAndStats> bundles =
237       AssembleBundleAndVerify(bundle_sizes);
238 
239   base::Value stats = ReadStats(bundles[0].second);
240   base::Value::ConstListView stats_list = stats.GetList();
241   ASSERT_EQ(1u, stats_list.size());
242   // Verify tags.
243   EXPECT_TRUE(stats_list[0].is_dict());
244   auto* found = stats_list[0].FindKey("video");
245   EXPECT_TRUE(found && found->is_dict());
246   found = stats_list[0].FindKey("audio");
247   EXPECT_TRUE(found && found->is_dict());
248   found = stats_list[0].FindKey("tags");
249   EXPECT_TRUE(found && found->is_dict());
250   // Verify session tags.
251   VerifyStringValue(*found, "activity", "audio+video streaming");
252   VerifyStringValue(*found, "receiverProductName", "ChromeCast");
253   VerifyBoolValue(*found, "shouldCaptureAudio", true);
254   VerifyBoolValue(*found, "shouldCaptureVideo", true);
255   auto* settings = found->FindKey("mirrorSettings");
256   EXPECT_TRUE(settings && settings->is_dict());
257   std::string settings_string;
258   EXPECT_TRUE(base::JSONWriter::Write(*settings, &settings_string));
259   EXPECT_EQ(expected_settings, settings_string);
260   VerifyWifiStatus(stats_list[0], 34, 2000, 5);
261 }
262 
263 // Test for multiple streaming sessions.
TEST_F(SessionMonitorTest,MultipleSessions)264 TEST_F(SessionMonitorTest, MultipleSessions) {
265   CreateSessionMonitor(kRetentionBytes, nullptr);
266   StartStreamingSession();
267   StopStreamingSession();
268   // Starts the second streaming session.
269   StartStreamingSession();
270   StopStreamingSession();
271   std::vector<int32_t> bundle_sizes({kRetentionBytes});
272   std::vector<SessionMonitor::EventsAndStats> bundles =
273       AssembleBundleAndVerify(bundle_sizes);
274   base::Value stats = ReadStats(bundles[0].second);
275   base::Value::ConstListView stats_list = stats.GetList();
276   // There should be two sessions in the recorded stats.
277   EXPECT_EQ(2u, stats_list.size());
278 }
279 
TEST_F(SessionMonitorTest,ConfigureMaxRetentionBytes)280 TEST_F(SessionMonitorTest, ConfigureMaxRetentionBytes) {
281   // 2500 is an estimate number of bytes for a snapshot that includes tags and
282   // five WiFi status records.
283   CreateSessionMonitor(2500, nullptr);
284   StartStreamingSession();
285   SendWifiStatus(34, 2000, 5);
286   StopStreamingSession();
287   StartStreamingSession();
288   SendWifiStatus(54, 3000, 5);
289   StopStreamingSession();
290   std::vector<int32_t> bundle_sizes({kRetentionBytes});
291   std::vector<SessionMonitor::EventsAndStats> bundles =
292       AssembleBundleAndVerify(bundle_sizes);
293   base::Value stats = ReadStats(bundles[0].second);
294   base::Value::ConstListView stats_list = stats.GetList();
295   // Expect to only record the second session.
296   ASSERT_EQ(1u, stats_list.size());
297   VerifyWifiStatus(stats_list[0], 54, 3000, 5);
298 }
299 
TEST_F(SessionMonitorTest,AssembleBundlesWithVaryingSizes)300 TEST_F(SessionMonitorTest, AssembleBundlesWithVaryingSizes) {
301   CreateSessionMonitor(kRetentionBytes, nullptr);
302   StartStreamingSession();
303   SendWifiStatus(34, 2000, 5);
304   StopStreamingSession();
305   StartStreamingSession();
306   SendWifiStatus(54, 3000, 5);
307   StopStreamingSession();
308   std::vector<int32_t> bundle_sizes({2500, kRetentionBytes});
309   std::vector<SessionMonitor::EventsAndStats> bundles =
310       AssembleBundleAndVerify(bundle_sizes);
311 
312   // Expect the first bundle has only one session.
313   base::Value stats = ReadStats(bundles[0].second);
314   base::Value::ConstListView stats_list = stats.GetList();
315   // Expect to only record the second session.
316   ASSERT_EQ(1u, stats_list.size());
317   VerifyWifiStatus(stats_list[0], 54, 3000, 5);
318 
319   // Expect the second bundle has both sessions.
320   stats = ReadStats(bundles[1].second);
321   base::Value::ConstListView stats_list2 = stats.GetList();
322   ASSERT_EQ(2u, stats_list2.size());
323   VerifyWifiStatus(stats_list2[0], 34, 2000, 5);
324   VerifyWifiStatus(stats_list2[1], 54, 3000, 5);
325 }
326 
TEST_F(SessionMonitorTest,ErrorTags)327 TEST_F(SessionMonitorTest, ErrorTags) {
328   CreateSessionMonitor(kRetentionBytes, nullptr);
329   StartStreamingSession();
330   TakeSnapshot();  // Take the first snapshot.
331   ReportError(SessionError::VIDEO_CAPTURE_ERROR);
332   ReportError(SessionError::RTP_STREAM_ERROR);
333   TakeSnapshot();          // Take the second snapshot.
334   StopStreamingSession();  // Take the third snapshot.
335 
336   std::vector<int32_t> bundle_sizes({kRetentionBytes});
337   std::vector<SessionMonitor::EventsAndStats> bundles =
338       AssembleBundleAndVerify(bundle_sizes);
339   base::Value stats = ReadStats(bundles[0].second);
340   base::Value::ConstListView stats_list = stats.GetList();
341   // There should be three snapshots in the bundle.
342   ASSERT_EQ(3u, stats_list.size());
343 
344   // The first and the third snapshots should have no error tags.
345   auto* tags = stats_list[0].FindKey("tags");
346   ASSERT_TRUE(tags);
347   EXPECT_FALSE(tags->FindKey("streamingErrorTime"));
348   EXPECT_FALSE(tags->FindKey("streamingErrorMessage"));
349   tags = stats_list[2].FindKey("tags");
350   ASSERT_TRUE(tags);
351   EXPECT_FALSE(tags->FindKey("streamingErrorTime"));
352   EXPECT_FALSE(tags->FindKey("streamingErrorMessage"));
353 
354   // The second snapshot should have the error tags. Only the first error is
355   // recorded.
356   tags = stats_list[1].FindKey("tags");
357   ASSERT_TRUE(tags && tags->FindKey("streamingErrorTime"));
358   VerifyStringValue(*tags, "streamingErrorMessage", "Video capture error");
359 }
360 
TEST_F(SessionMonitorTest,ReceiverSetupInfo)361 TEST_F(SessionMonitorTest, ReceiverSetupInfo) {
362   CreateSessionMonitor(kRetentionBytes, nullptr);
363   StartStreamingSession();
364   // This snapshot should have no receiver setup info tags.
365   TakeSnapshot();
366 
367   const std::string receiver_setup_info =
368       "{"
369       "\"cast_build_revision\": \"1.26.0.1\","
370       "\"connected\": true,"
371       "\"ethernet_connected\": false,"
372       "\"has_update\": false,"
373       "\"uptime\": 13253.6 }";
374 
375   SendReceiverSetupInfo(receiver_setup_info);
376 
377   // A final snapshot is taken and should have receiver setup info tags.
378   StopStreamingSession();
379 
380   std::vector<int32_t> bundle_sizes({kRetentionBytes});
381   std::vector<SessionMonitor::EventsAndStats> bundles =
382       AssembleBundleAndVerify(bundle_sizes);
383   base::Value stats = ReadStats(bundles[0].second);
384   base::Value::ConstListView stats_list = stats.GetList();
385   // There should be two snapshots in the bundle.
386   EXPECT_EQ(2u, stats_list.size());
387 
388   // The first snapshot should have no receiver setup info tags.
389   auto* tags = stats_list[0].FindKey("tags");
390   ASSERT_TRUE(tags);
391   EXPECT_FALSE(tags->FindKey("receiverVersion"));
392   EXPECT_FALSE(tags->FindKey("receiverConnected"));
393   EXPECT_FALSE(tags->FindKey("receiverOnEthernet"));
394   EXPECT_FALSE(tags->FindKey("receiverHasUpdatePending"));
395   EXPECT_FALSE(tags->FindKey("receiverUptimeSeconds"));
396 
397   // The second snapshot should have the receiver setup info tags.
398   tags = stats_list[1].FindKey("tags");
399   ASSERT_TRUE(tags);
400   VerifyStringValue(*tags, "receiverVersion", "1.26.0.1");
401   VerifyBoolValue(*tags, "receiverConnected", true);
402   VerifyBoolValue(*tags, "receiverOnEthernet", false);
403   VerifyBoolValue(*tags, "receiverHasUpdatePending", false);
404   VerifyDoubleValue(*tags, "receiverUptimeSeconds", 13253.6);
405 }
406 
407 }  // namespace mirroring
408