Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / browser / media / webrtc_internals_browsertest.cc
1 // Copyright (c) 2013 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 "base/command_line.h"
6 #include "base/json/json_reader.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "base/time/time.h"
9 #include "base/values.h"
10 #include "content/public/common/content_switches.h"
11 #include "content/public/test/browser_test_utils.h"
12 #include "content/public/test/content_browser_test.h"
13 #include "content/public/test/content_browser_test_utils.h"
14 #include "content/shell/browser/shell.h"
15 #include "media/base/media_switches.h"
16 #include "net/test/embedded_test_server/embedded_test_server.h"
17
18 using std::string;
19 namespace content {
20
21 struct SsrcEntry {
22   string GetSsrcAttributeString() const {
23     std::stringstream ss;
24     ss << "a=ssrc:" << id;
25     std::map<string, string>::const_iterator iter;
26     for (iter = properties.begin(); iter != properties.end(); ++iter) {
27       ss << " " << iter->first << ":" << iter->second;
28     }
29     return ss.str();
30   }
31
32   string GetAsJSON() const {
33     std::stringstream ss;
34     ss << "{";
35     std::map<string, string>::const_iterator iter;
36     for (iter = properties.begin(); iter != properties.end(); ++iter) {
37       if (iter != properties.begin())
38         ss << ",";
39       ss << "\"" << iter->first << "\":\"" << iter->second << "\"";
40     }
41     ss << "}";
42     return ss.str();
43   }
44
45   string id;
46   std::map<string, string> properties;
47 };
48
49 struct EventEntry {
50   string type;
51   string value;
52 };
53
54 struct StatsUnit {
55   string GetString() const {
56     std::stringstream ss;
57     ss << "{timestamp:" << timestamp << ", values:[";
58     std::map<string, string>::const_iterator iter;
59     for (iter = values.begin(); iter != values.end(); ++iter) {
60       ss << "'" << iter->first << "','" << iter->second << "',";
61     }
62     ss << "]}";
63     return ss.str();
64   }
65
66   int64 timestamp;
67   std::map<string, string> values;
68 };
69
70 struct StatsEntry {
71   string type;
72   string id;
73   StatsUnit stats;
74 };
75
76 typedef std::map<string, std::vector<string> > StatsMap;
77
78 class PeerConnectionEntry {
79  public:
80   PeerConnectionEntry(int pid, int lid) : pid_(pid), lid_(lid) {}
81
82   void AddEvent(const string& type, const string& value) {
83     EventEntry entry = {type, value};
84     events_.push_back(entry);
85   }
86
87   string getIdString() const {
88     std::stringstream ss;
89     ss << pid_ << "-" << lid_;
90     return ss.str();
91   }
92
93   string getLogIdString() const {
94     std::stringstream ss;
95     ss << pid_ << "-" << lid_ << "-update-log";
96     return ss.str();
97   }
98
99   string getAllUpdateString() const {
100     std::stringstream ss;
101     ss << "{pid:" << pid_ << ", lid:" << lid_ << ", log:[";
102     for (size_t i = 0; i < events_.size(); ++i) {
103       ss << "{type:'" << events_[i].type <<
104           "', value:'" << events_[i].value << "'},";
105     }
106     ss << "]}";
107     return ss.str();
108   }
109
110   int pid_;
111   int lid_;
112   std::vector<EventEntry> events_;
113   // This is a record of the history of stats value reported for each stats
114   // report id (e.g. ssrc-1234) for each stats name (e.g. framerate).
115   // It a 2-D map with each map entry is a vector of reported values.
116   // It is used to verify the graph data series.
117   std::map<string, StatsMap> stats_;
118 };
119
120 class UserMediaRequestEntry {
121  public:
122   UserMediaRequestEntry(int pid,
123                         int rid,
124                         const std::string& origin,
125                         const std::string& audio_constraints,
126                         const std::string& video_constraints)
127       : pid(pid),
128         rid(rid),
129         origin(origin),
130         audio_constraints(audio_constraints),
131         video_constraints(video_constraints) {}
132
133   int pid;
134   int rid;
135   std::string origin;
136   std::string audio_constraints;
137   std::string video_constraints;
138 };
139
140 static const int64 FAKE_TIME_STAMP = 3600000;
141
142 #if defined(OS_WIN)
143 // All tests are flaky on Windows: crbug.com/277322.
144 #define MAYBE_WebRtcInternalsBrowserTest DISABLED_WebRtcInternalsBrowserTest
145 #else
146 #define MAYBE_WebRtcInternalsBrowserTest WebRtcInternalsBrowserTest
147 #endif
148
149 class MAYBE_WebRtcInternalsBrowserTest: public ContentBrowserTest {
150  public:
151   MAYBE_WebRtcInternalsBrowserTest() {}
152   ~MAYBE_WebRtcInternalsBrowserTest() override {}
153
154   void SetUpOnMainThread() override {
155     // Assume this is set by the content test launcher.
156     ASSERT_TRUE(CommandLine::ForCurrentProcess()->HasSwitch(
157         switches::kUseFakeUIForMediaStream));
158     ASSERT_TRUE(CommandLine::ForCurrentProcess()->HasSwitch(
159         switches::kUseFakeDeviceForMediaStream));
160   }
161
162  protected:
163   bool ExecuteJavascript(const string& javascript) {
164     return ExecuteScript(shell()->web_contents(), javascript);
165   }
166
167   void ExpectTitle(const std::string& expected_title) const {
168     base::string16 expected_title16(base::ASCIIToUTF16(expected_title));
169     TitleWatcher title_watcher(shell()->web_contents(), expected_title16);
170     EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle());
171   }
172
173   // Execute the javascript of addPeerConnection.
174   void ExecuteAddPeerConnectionJs(const PeerConnectionEntry& pc) {
175     std::stringstream ss;
176     ss << "{pid:" << pc.pid_ <<", lid:" << pc.lid_ << ", " <<
177            "url:'u', rtcConfiguration:'s', constraints:'c'}";
178     ASSERT_TRUE(ExecuteJavascript("addPeerConnection(" + ss.str() + ");"));
179   }
180
181   // Execute the javascript of removePeerConnection.
182   void ExecuteRemovePeerConnectionJs(const PeerConnectionEntry& pc) {
183     std::stringstream ss;
184     ss << "{pid:" << pc.pid_ <<", lid:" << pc.lid_ << "}";
185
186     ASSERT_TRUE(ExecuteJavascript("removePeerConnection(" + ss.str() + ");"));
187   }
188
189   // Execute the javascript of addGetUserMedia.
190   void ExecuteAddGetUserMediaJs(const UserMediaRequestEntry& request) {
191     std::stringstream ss;
192     ss << "{pid:" << request.pid << ", rid:" << request.rid << ", origin:'"
193        << request.origin << "', audio:'" << request.audio_constraints
194        << "', video:'" << request.video_constraints << "'}";
195
196     ASSERT_TRUE(ExecuteJavascript("addGetUserMedia(" + ss.str() + ");"));
197   }
198
199   // Execute the javascript of removeGetUserMediaForRenderer.
200   void ExecuteRemoveGetUserMediaForRendererJs(int rid) {
201     std::stringstream ss;
202     ss << "{rid:" << rid << "}";
203     ASSERT_TRUE(
204         ExecuteJavascript("removeGetUserMediaForRenderer(" + ss.str() + ");"));
205   }
206
207   // Verifies that the DOM element with id |id| exists.
208   void VerifyElementWithId(const string& id) {
209     bool result = false;
210     ASSERT_TRUE(ExecuteScriptAndExtractBool(
211         shell()->web_contents(),
212         "window.domAutomationController.send($('" + id + "') != null);",
213         &result));
214     EXPECT_TRUE(result);
215   }
216
217   // Verifies that the DOM element with id |id| does not exist.
218   void VerifyNoElementWithId(const string& id) {
219     bool result = false;
220     ASSERT_TRUE(ExecuteScriptAndExtractBool(
221         shell()->web_contents(),
222         "window.domAutomationController.send($('" + id + "') == null);",
223         &result));
224     EXPECT_TRUE(result);
225   }
226
227   // Verifies the JS Array of userMediaRequests matches |requests|.
228   void VerifyUserMediaRequest(
229       const std::vector<UserMediaRequestEntry>& requests) {
230     string json_requests;
231     ASSERT_TRUE(ExecuteScriptAndExtractString(
232         shell()->web_contents(),
233         "window.domAutomationController.send("
234             "JSON.stringify(userMediaRequests));",
235         &json_requests));
236     scoped_ptr<base::Value> value_requests;
237     value_requests.reset(base::JSONReader::Read(json_requests));
238
239     EXPECT_EQ(base::Value::TYPE_LIST, value_requests->GetType());
240
241     base::ListValue* list_request =
242         static_cast<base::ListValue*>(value_requests.get());
243     EXPECT_EQ(requests.size(), list_request->GetSize());
244
245     for (size_t i = 0; i < requests.size(); ++i) {
246       base::DictionaryValue* dict = NULL;
247       ASSERT_TRUE(list_request->GetDictionary(i, &dict));
248       int pid, rid;
249       std::string origin, audio, video;
250       ASSERT_TRUE(dict->GetInteger("pid", &pid));
251       ASSERT_TRUE(dict->GetInteger("rid", &rid));
252       ASSERT_TRUE(dict->GetString("origin", &origin));
253       ASSERT_TRUE(dict->GetString("audio", &audio));
254       ASSERT_TRUE(dict->GetString("video", &video));
255       EXPECT_EQ(requests[i].pid, pid);
256       EXPECT_EQ(requests[i].rid, rid);
257       EXPECT_EQ(requests[i].origin, origin);
258       EXPECT_EQ(requests[i].audio_constraints, audio);
259       EXPECT_EQ(requests[i].video_constraints, video);
260     }
261
262     bool user_media_tab_existed = false;
263     ASSERT_TRUE(ExecuteScriptAndExtractBool(
264         shell()->web_contents(),
265         "window.domAutomationController.send("
266             "$('user-media-tab-id') != null);",
267         &user_media_tab_existed));
268     EXPECT_EQ(!requests.empty(), user_media_tab_existed);
269
270     if (user_media_tab_existed) {
271       int user_media_request_count = -1;
272       ASSERT_TRUE(ExecuteScriptAndExtractInt(
273           shell()->web_contents(),
274           "window.domAutomationController.send("
275               "$('user-media-tab-id').childNodes.length);",
276           &user_media_request_count));
277       ASSERT_EQ(requests.size(), static_cast<size_t>(user_media_request_count));
278     }
279   }
280
281   // Verifies that DOM for |pc| is correctly created with the right content.
282   void VerifyPeerConnectionEntry(const PeerConnectionEntry& pc) {
283     VerifyElementWithId(pc.getIdString());
284     if (pc.events_.size() == 0)
285       return;
286
287     string log_id = pc.getLogIdString();
288     VerifyElementWithId(log_id);
289     string result;
290     for (size_t i = 0; i < pc.events_.size(); ++i) {
291       std::stringstream ss;
292       ss << "var row = $('" << log_id << "').rows[" << (i + 1) << "];"
293             "var cell = row.lastChild;"
294             "window.domAutomationController.send(cell.firstChild.textContent);";
295       ASSERT_TRUE(ExecuteScriptAndExtractString(
296           shell()->web_contents(), ss.str(), &result));
297       EXPECT_EQ(pc.events_[i].type + pc.events_[i].value, result);
298     }
299   }
300
301   // Executes the javascript of updatePeerConnection and verifies the result.
302   void ExecuteAndVerifyUpdatePeerConnection(
303       PeerConnectionEntry& pc, const string& type, const string& value) {
304     pc.AddEvent(type, value);
305
306     std::stringstream ss;
307     ss << "{pid:" << pc.pid_ <<", lid:" << pc.lid_ <<
308          ", type:'" << type << "', value:'" << value << "'}";
309     ASSERT_TRUE(ExecuteJavascript("updatePeerConnection(" + ss.str() + ")"));
310
311     VerifyPeerConnectionEntry(pc);
312   }
313
314   // Execute addStats and verifies that the stats table has the right content.
315   void ExecuteAndVerifyAddStats(
316       PeerConnectionEntry& pc, const string& type, const string& id,
317       StatsUnit& stats) {
318     StatsEntry entry = {type, id, stats};
319
320     // Adds each new value to the map of stats history.
321     std::map<string, string>::iterator iter;
322     for (iter = stats.values.begin(); iter != stats.values.end(); iter++) {
323       pc.stats_[id][iter->first].push_back(iter->second);
324     }
325     std::stringstream ss;
326     ss << "{pid:" << pc.pid_ << ", lid:" << pc.lid_ << ","
327            "reports:[" << "{id:'" << id << "', type:'" << type << "', "
328                            "stats:" << stats.GetString() << "}]}";
329
330     ASSERT_TRUE(ExecuteJavascript("addStats(" + ss.str() + ")"));
331     VerifyStatsTable(pc, entry);
332   }
333
334
335   // Verifies that the stats table has the right content.
336   void VerifyStatsTable(const PeerConnectionEntry& pc,
337                         const StatsEntry& report) {
338     string table_id =
339         pc.getIdString() + "-table-" + report.id;
340     VerifyElementWithId(table_id);
341
342     std::map<string, string>::const_iterator iter;
343     for (iter = report.stats.values.begin();
344          iter != report.stats.values.end(); iter++) {
345       VerifyStatsTableRow(table_id, iter->first, iter->second);
346     }
347   }
348
349   // Verifies that the row named as |name| of the stats table |table_id| has
350   // the correct content as |name| : |value|.
351   void VerifyStatsTableRow(const string& table_id,
352                            const string& name,
353                            const string& value) {
354     VerifyElementWithId(table_id + "-" + name);
355
356     string result;
357     ASSERT_TRUE(ExecuteScriptAndExtractString(
358         shell()->web_contents(),
359         "var row = $('" + table_id + "-" + name + "');"
360         "var name = row.cells[0].textContent;"
361         "var value = row.cells[1].textContent;"
362         "window.domAutomationController.send(name + ':' + value)",
363         &result));
364     EXPECT_EQ(name + ":" + value, result);
365   }
366
367   // Verifies that the graph data series consistent with pc.stats_.
368   void VerifyStatsGraph(const PeerConnectionEntry& pc) {
369     std::map<string, StatsMap>::const_iterator stream_iter;
370     for (stream_iter = pc.stats_.begin();
371          stream_iter != pc.stats_.end(); stream_iter++) {
372       StatsMap::const_iterator stats_iter;
373       for (stats_iter = stream_iter->second.begin();
374            stats_iter != stream_iter->second.end();
375            stats_iter++) {
376         string graph_id = stream_iter->first + "-" + stats_iter->first;
377         for (size_t i = 0; i < stats_iter->second.size(); ++i) {
378           float number;
379           std::stringstream stream(stats_iter->second[i]);
380           stream >> number;
381           if (stream.fail())
382             continue;
383           VerifyGraphDataPoint(
384               pc.getIdString(), graph_id, i, stats_iter->second[i]);
385         }
386       }
387     }
388   }
389
390   // Verifies that the graph data point at index |index| has value |value|.
391   void VerifyGraphDataPoint(const string& pc_id, const string& graph_id,
392                             int index, const string& value) {
393     bool result = false;
394     ASSERT_TRUE(ExecuteScriptAndExtractBool(
395         shell()->web_contents(),
396         "window.domAutomationController.send("
397            "graphViews['" + pc_id + "-" + graph_id + "'] != null)",
398         &result));
399     EXPECT_TRUE(result);
400
401     std::stringstream ss;
402     ss << "var dp = peerConnectionDataStore['" << pc_id << "']"
403           ".getDataSeries('" << graph_id << "').dataPoints_[" << index << "];"
404           "window.domAutomationController.send(dp.value.toString())";
405     string actual_value;
406     ASSERT_TRUE(ExecuteScriptAndExtractString(
407         shell()->web_contents(), ss.str(), &actual_value));
408     EXPECT_EQ(value, actual_value);
409   }
410
411   // Get the JSON string of the ssrc info from the page.
412   string GetSsrcInfo(const string& ssrc_id) {
413     string result;
414     EXPECT_TRUE(ExecuteScriptAndExtractString(
415         shell()->web_contents(),
416         "window.domAutomationController.send(JSON.stringify("
417            "ssrcInfoManager.streamInfoContainer_['" + ssrc_id + "']))",
418         &result));
419     return result;
420   }
421
422   int GetSsrcInfoBlockCount(Shell* shell) {
423     int count = 0;
424     EXPECT_TRUE(ExecuteScriptAndExtractInt(
425         shell->web_contents(),
426         "window.domAutomationController.send("
427             "document.getElementsByClassName("
428                 "ssrcInfoManager.SSRC_INFO_BLOCK_CLASS).length);",
429         &count));
430     return count;
431   }
432
433   // Verifies |dump| contains |peer_connection_number| peer connection dumps,
434   // each containing |update_number| updates and |stats_number| stats tables.
435   void VerifyPageDumpStructure(base::Value* dump,
436                                int peer_connection_number,
437                                int update_number,
438                                int stats_number) {
439     EXPECT_NE((base::Value*)NULL, dump);
440     EXPECT_EQ(base::Value::TYPE_DICTIONARY, dump->GetType());
441
442     base::DictionaryValue* dict_dump =
443         static_cast<base::DictionaryValue*>(dump);
444     EXPECT_EQ((size_t) peer_connection_number, dict_dump->size());
445
446     base::DictionaryValue::Iterator it(*dict_dump);
447     for (; !it.IsAtEnd(); it.Advance()) {
448       base::Value* value = NULL;
449       dict_dump->Get(it.key(), &value);
450       EXPECT_EQ(base::Value::TYPE_DICTIONARY, value->GetType());
451       base::DictionaryValue* pc_dump =
452           static_cast<base::DictionaryValue*>(value);
453       EXPECT_TRUE(pc_dump->HasKey("updateLog"));
454       EXPECT_TRUE(pc_dump->HasKey("stats"));
455
456       // Verifies the number of updates.
457       pc_dump->Get("updateLog", &value);
458       EXPECT_EQ(base::Value::TYPE_LIST, value->GetType());
459       base::ListValue* list = static_cast<base::ListValue*>(value);
460       EXPECT_EQ((size_t) update_number, list->GetSize());
461
462       // Verifies the number of stats tables.
463       pc_dump->Get("stats", &value);
464       EXPECT_EQ(base::Value::TYPE_DICTIONARY, value->GetType());
465       base::DictionaryValue* dict = static_cast<base::DictionaryValue*>(value);
466       EXPECT_EQ((size_t) stats_number, dict->size());
467     }
468   }
469
470   // Verifies |dump| contains the correct statsTable and statsDataSeries for
471   // |pc|.
472   void VerifyStatsDump(base::Value* dump,
473                        const PeerConnectionEntry& pc,
474                        const string& report_type,
475                        const string& report_id,
476                        const StatsUnit& stats) {
477     EXPECT_NE((base::Value*)NULL, dump);
478     EXPECT_EQ(base::Value::TYPE_DICTIONARY, dump->GetType());
479
480     base::DictionaryValue* dict_dump =
481         static_cast<base::DictionaryValue*>(dump);
482     base::Value* value = NULL;
483     dict_dump->Get(pc.getIdString(), &value);
484     base::DictionaryValue* pc_dump = static_cast<base::DictionaryValue*>(value);
485
486     // Verifies there is one data series per stats name.
487     value = NULL;
488     pc_dump->Get("stats", &value);
489     EXPECT_EQ(base::Value::TYPE_DICTIONARY, value->GetType());
490
491     base::DictionaryValue* dataSeries =
492         static_cast<base::DictionaryValue*>(value);
493     EXPECT_EQ(stats.values.size(), dataSeries->size());
494   }
495 };
496
497 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest,
498                        AddAndRemovePeerConnection) {
499   GURL url("chrome://webrtc-internals");
500   NavigateToURL(shell(), url);
501
502   // Add two PeerConnections and then remove them.
503   PeerConnectionEntry pc_1(1, 0);
504   ExecuteAddPeerConnectionJs(pc_1);
505   VerifyPeerConnectionEntry(pc_1);
506
507   PeerConnectionEntry pc_2(2, 1);
508   ExecuteAddPeerConnectionJs(pc_2);
509   VerifyPeerConnectionEntry(pc_2);
510
511   ExecuteRemovePeerConnectionJs(pc_1);
512   VerifyNoElementWithId(pc_1.getIdString());
513   VerifyPeerConnectionEntry(pc_2);
514
515   ExecuteRemovePeerConnectionJs(pc_2);
516   VerifyNoElementWithId(pc_2.getIdString());
517 }
518
519 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest,
520                        UpdateAllPeerConnections) {
521   GURL url("chrome://webrtc-internals");
522   NavigateToURL(shell(), url);
523
524   PeerConnectionEntry pc_0(1, 0);
525   pc_0.AddEvent("e1", "v1");
526   pc_0.AddEvent("e2", "v2");
527   PeerConnectionEntry pc_1(1, 1);
528   pc_1.AddEvent("e3", "v3");
529   pc_1.AddEvent("e4", "v4");
530   string pc_array = "[" + pc_0.getAllUpdateString() + ", " +
531                           pc_1.getAllUpdateString() + "]";
532   EXPECT_TRUE(ExecuteJavascript("updateAllPeerConnections(" + pc_array + ");"));
533   VerifyPeerConnectionEntry(pc_0);
534   VerifyPeerConnectionEntry(pc_1);
535 }
536
537 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest, UpdatePeerConnection) {
538   GURL url("chrome://webrtc-internals");
539   NavigateToURL(shell(), url);
540
541   // Add one PeerConnection and send one update.
542   PeerConnectionEntry pc_1(1, 0);
543   ExecuteAddPeerConnectionJs(pc_1);
544
545   ExecuteAndVerifyUpdatePeerConnection(pc_1, "e1", "v1");
546
547   // Add another PeerConnection and send two updates.
548   PeerConnectionEntry pc_2(1, 1);
549   ExecuteAddPeerConnectionJs(pc_2);
550
551   SsrcEntry ssrc1, ssrc2;
552   ssrc1.id = "ssrcid1";
553   ssrc1.properties["msid"] = "mymsid";
554   ssrc2.id = "ssrcid2";
555   ssrc2.properties["label"] = "mylabel";
556   ssrc2.properties["cname"] = "mycname";
557
558   ExecuteAndVerifyUpdatePeerConnection(pc_2, "setRemoteDescription",
559       ssrc1.GetSsrcAttributeString());
560
561   ExecuteAndVerifyUpdatePeerConnection(pc_2, "setLocalDescription",
562       ssrc2.GetSsrcAttributeString());
563
564   EXPECT_EQ(ssrc1.GetAsJSON(), GetSsrcInfo(ssrc1.id));
565   EXPECT_EQ(ssrc2.GetAsJSON(), GetSsrcInfo(ssrc2.id));
566
567   StatsUnit stats = {FAKE_TIME_STAMP};
568   stats.values["ssrc"] = ssrc1.id;
569   ExecuteAndVerifyAddStats(pc_2, "ssrc", "dummyId", stats);
570   EXPECT_GT(GetSsrcInfoBlockCount(shell()), 0);
571 }
572
573 // Tests that adding random named stats updates the dataSeries and graphs.
574 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest, AddStats) {
575   GURL url("chrome://webrtc-internals");
576   NavigateToURL(shell(), url);
577
578   PeerConnectionEntry pc(1, 0);
579   ExecuteAddPeerConnectionJs(pc);
580
581   const string type = "ssrc";
582   const string id = "ssrc-1234";
583   StatsUnit stats = {FAKE_TIME_STAMP};
584   stats.values["trackId"] = "abcd";
585   stats.values["bitrate"] = "2000";
586   stats.values["framerate"] = "30";
587
588   // Add new stats and verify the stats table and graphs.
589   ExecuteAndVerifyAddStats(pc, type, id, stats);
590   VerifyStatsGraph(pc);
591
592   // Update existing stats and verify the stats table and graphs.
593   stats.values["bitrate"] = "2001";
594   stats.values["framerate"] = "31";
595   ExecuteAndVerifyAddStats(pc, type, id, stats);
596   VerifyStatsGraph(pc);
597 }
598
599 // Tests that the bandwidth estimation values are drawn on a single graph.
600 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest, BweCompoundGraph) {
601   GURL url("chrome://webrtc-internals");
602   NavigateToURL(shell(), url);
603
604   PeerConnectionEntry pc(1, 0);
605   ExecuteAddPeerConnectionJs(pc);
606
607   StatsUnit stats = {FAKE_TIME_STAMP};
608   stats.values["googAvailableSendBandwidth"] = "1000000";
609   stats.values["googTargetEncBitrate"] = "1000";
610   stats.values["googActualEncBitrate"] = "1000000";
611   stats.values["googRetransmitBitrate"] = "10";
612   stats.values["googTransmitBitrate"] = "1000000";
613   const string stats_type = "bwe";
614   const string stats_id = "videobwe";
615   ExecuteAndVerifyAddStats(pc, stats_type, stats_id, stats);
616
617   string graph_id =
618       pc.getIdString() + "-" + stats_id + "-bweCompound";
619   bool result = false;
620   // Verify that the bweCompound graph exists.
621   ASSERT_TRUE(ExecuteScriptAndExtractBool(
622         shell()->web_contents(),
623         "window.domAutomationController.send("
624         "   graphViews['" + graph_id + "'] != null)",
625         &result));
626   EXPECT_TRUE(result);
627
628   // Verify that the bweCompound graph contains multiple dataSeries.
629   int count = 0;
630   ASSERT_TRUE(ExecuteScriptAndExtractInt(
631         shell()->web_contents(),
632         "window.domAutomationController.send("
633         "   graphViews['" + graph_id + "'].getDataSeriesCount())",
634         &count));
635   EXPECT_EQ((int)stats.values.size(), count);
636 }
637
638 // Tests that the total packet/byte count is converted to count per second,
639 // and the converted data is drawn.
640 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest, ConvertedGraphs) {
641   GURL url("chrome://webrtc-internals");
642   NavigateToURL(shell(), url);
643
644   PeerConnectionEntry pc(1, 0);
645   ExecuteAddPeerConnectionJs(pc);
646
647   const string stats_type = "s";
648   const string stats_id = "1";
649   const int num_converted_stats = 4;
650   const string stats_names[] =
651       {"packetsSent", "bytesSent", "packetsReceived", "bytesReceived"};
652   const string converted_names[] =
653       {"packetsSentPerSecond", "bitsSentPerSecond",
654        "packetsReceivedPerSecond", "bitsReceivedPerSecond"};
655   const string first_value = "1000";
656   const string second_value = "2000";
657   const string converted_values[] = {"1000", "8000", "1000", "8000"};
658
659   // Send the first data point.
660   StatsUnit stats = {FAKE_TIME_STAMP};
661   for (int i = 0; i < num_converted_stats; ++i)
662     stats.values[stats_names[i]] = first_value;
663
664   ExecuteAndVerifyAddStats(pc, stats_type, stats_id, stats);
665
666   // Send the second data point at 1000ms after the first data point.
667   stats.timestamp += 1000;
668   for (int i = 0; i < num_converted_stats; ++i)
669     stats.values[stats_names[i]] = second_value;
670   ExecuteAndVerifyAddStats(pc, stats_type, stats_id, stats);
671
672   // Verifies the graph data matches converted_values.
673   for (int i = 0; i < num_converted_stats; ++i) {
674     VerifyGraphDataPoint(pc.getIdString(), stats_id + "-" + converted_names[i],
675                          1, converted_values[i]);
676   }
677 }
678
679 // Timing out on ARM linux bot: http://crbug.com/238490
680 // Disabling due to failure on Linux, Mac, Win: http://crbug.com/272413
681 // Sanity check of the page content under a real PeerConnection call.
682 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest,
683                        DISABLED_WithRealPeerConnectionCall) {
684   // Start a peerconnection call in the first window.
685   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
686   GURL url(embedded_test_server()->GetURL("/media/peerconnection-call.html"));
687   NavigateToURL(shell(), url);
688   ASSERT_TRUE(ExecuteJavascript("call({video:true});"));
689   ExpectTitle("OK");
690
691   // Open webrtc-internals in the second window.
692   GURL url2("chrome://webrtc-internals");
693   Shell* shell2 = CreateBrowser();
694   NavigateToURL(shell2, url2);
695
696   const int NUMBER_OF_PEER_CONNECTIONS = 2;
697
698   // Verifies the number of peerconnections.
699   int count = 0;
700   ASSERT_TRUE(ExecuteScriptAndExtractInt(
701       shell2->web_contents(),
702       "window.domAutomationController.send("
703           "$('peer-connections-list').getElementsByTagName('li').length);",
704       &count));
705   EXPECT_EQ(NUMBER_OF_PEER_CONNECTIONS, count);
706
707   // Verifies the the event tables.
708   ASSERT_TRUE(ExecuteScriptAndExtractInt(
709       shell2->web_contents(),
710       "window.domAutomationController.send($('peer-connections-list')"
711           ".getElementsByClassName('update-log-table').length);",
712       &count));
713   EXPECT_EQ(NUMBER_OF_PEER_CONNECTIONS, count);
714
715   ASSERT_TRUE(ExecuteScriptAndExtractInt(
716       shell2->web_contents(),
717       "window.domAutomationController.send($('peer-connections-list')"
718           ".getElementsByClassName('update-log-table')[0].rows.length);",
719       &count));
720   EXPECT_GT(count, 1);
721
722   ASSERT_TRUE(ExecuteScriptAndExtractInt(
723       shell2->web_contents(),
724       "window.domAutomationController.send($('peer-connections-list')"
725           ".getElementsByClassName('update-log-table')[1].rows.length);",
726       &count));
727   EXPECT_GT(count, 1);
728
729   // Wait until the stats table containers are created.
730   count = 0;
731   while (count != NUMBER_OF_PEER_CONNECTIONS) {
732     ASSERT_TRUE(ExecuteScriptAndExtractInt(
733         shell2->web_contents(),
734         "window.domAutomationController.send("
735             "$('peer-connections-list').getElementsByClassName("
736                 "'stats-table-container').length);",
737         &count));
738   }
739
740   // Verifies each stats table having more than one rows.
741   bool result = false;
742   ASSERT_TRUE(ExecuteScriptAndExtractBool(
743       shell2->web_contents(),
744       "var tableContainers = $('peer-connections-list')"
745           ".getElementsByClassName('stats-table-container');"
746       "var result = true;"
747       "for (var i = 0; i < tableContainers.length && result; ++i) {"
748         "var tables = tableContainers[i].getElementsByTagName('table');"
749         "for (var j = 0; j < tables.length && result; ++j) {"
750           "result = (tables[j].rows.length > 1);"
751         "}"
752         "if (!result) {"
753           "console.log(tableContainers[i].innerHTML);"
754         "}"
755       "}"
756       "window.domAutomationController.send(result);",
757       &result));
758
759   EXPECT_TRUE(result);
760
761   count = GetSsrcInfoBlockCount(shell2);
762   EXPECT_GT(count, 0);
763 }
764
765 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest, CreatePageDump) {
766   GURL url("chrome://webrtc-internals");
767   NavigateToURL(shell(), url);
768
769   PeerConnectionEntry pc_0(1, 0);
770   pc_0.AddEvent("e1", "v1");
771   pc_0.AddEvent("e2", "v2");
772   PeerConnectionEntry pc_1(1, 1);
773   pc_1.AddEvent("e3", "v3");
774   pc_1.AddEvent("e4", "v4");
775   string pc_array =
776       "[" + pc_0.getAllUpdateString() + ", " + pc_1.getAllUpdateString() + "]";
777   EXPECT_TRUE(ExecuteJavascript("updateAllPeerConnections(" + pc_array + ");"));
778
779   // Verifies the peer connection data store can be created without stats.
780   string dump_json;
781   ASSERT_TRUE(ExecuteScriptAndExtractString(
782       shell()->web_contents(),
783       "window.domAutomationController.send("
784       "JSON.stringify(peerConnectionDataStore));",
785       &dump_json));
786   scoped_ptr<base::Value> dump;
787   dump.reset(base::JSONReader::Read(dump_json));
788   VerifyPageDumpStructure(dump.get(),
789                           2 /*peer_connection_number*/,
790                           2 /*update_number*/,
791                           0 /*stats_number*/);
792
793   // Adds a stats report.
794   const string type = "dummy";
795   const string id = "1234";
796   StatsUnit stats = { FAKE_TIME_STAMP };
797   stats.values["bitrate"] = "2000";
798   stats.values["framerate"] = "30";
799   ExecuteAndVerifyAddStats(pc_0, type, id, stats);
800
801   ASSERT_TRUE(ExecuteScriptAndExtractString(
802       shell()->web_contents(),
803       "window.domAutomationController.send("
804       "JSON.stringify(peerConnectionDataStore));",
805       &dump_json));
806   dump.reset(base::JSONReader::Read(dump_json));
807   VerifyStatsDump(dump.get(), pc_0, type, id, stats);
808 }
809
810 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest, UpdateGetUserMedia) {
811   GURL url("chrome://webrtc-internals");
812   NavigateToURL(shell(), url);
813
814   UserMediaRequestEntry request1(1, 1, "origin", "ac", "vc");
815   UserMediaRequestEntry request2(2, 2, "origin2", "ac2", "vc2");
816   ExecuteAddGetUserMediaJs(request1);
817   ExecuteAddGetUserMediaJs(request2);
818
819   std::vector<UserMediaRequestEntry> list;
820   list.push_back(request1);
821   list.push_back(request2);
822   VerifyUserMediaRequest(list);
823
824   ExecuteRemoveGetUserMediaForRendererJs(1);
825   list.erase(list.begin());
826   VerifyUserMediaRequest(list);
827
828   ExecuteRemoveGetUserMediaForRendererJs(2);
829   list.erase(list.begin());
830   VerifyUserMediaRequest(list);
831 }
832
833 // Tests that the received propagation delta values are converted and drawn
834 // correctly.
835 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest,
836                        ReceivedPropagationDelta) {
837   GURL url("chrome://webrtc-internals");
838   NavigateToURL(shell(), url);
839
840   PeerConnectionEntry pc(1, 0);
841   ExecuteAddPeerConnectionJs(pc);
842
843   StatsUnit stats = {FAKE_TIME_STAMP};
844   stats.values["googReceivedPacketGroupArrivalTimeDebug"] =
845       "[1000, 1100, 1200]";
846   stats.values["googReceivedPacketGroupPropagationDeltaDebug"] =
847       "[10, 20, 30]";
848   const string stats_type = "bwe";
849   const string stats_id = "videobwe";
850   ExecuteAndVerifyAddStats(pc, stats_type, stats_id, stats);
851
852   string graph_id = pc.getIdString() + "-" + stats_id +
853       "-googReceivedPacketGroupPropagationDeltaDebug";
854   string data_series_id =
855       stats_id + "-googReceivedPacketGroupPropagationDeltaDebug";
856   bool result = false;
857   // Verify that the graph exists.
858   ASSERT_TRUE(ExecuteScriptAndExtractBool(
859       shell()->web_contents(),
860       "window.domAutomationController.send("
861       "   graphViews['" + graph_id + "'] != null)",
862       &result));
863   EXPECT_TRUE(result);
864
865   // Verify that the graph contains multiple data points.
866   int count = 0;
867   ASSERT_TRUE(ExecuteScriptAndExtractInt(
868       shell()->web_contents(),
869       "window.domAutomationController.send("
870       "   graphViews['" + graph_id + "'].getDataSeriesCount())",
871       &count));
872   EXPECT_EQ(1, count);
873   ASSERT_TRUE(ExecuteScriptAndExtractInt(
874       shell()->web_contents(),
875       "window.domAutomationController.send("
876       "   peerConnectionDataStore['" + pc.getIdString() + "']" +
877       "       .getDataSeries('" + data_series_id + "').getCount())",
878       &count));
879   EXPECT_EQ(3, count);
880 }
881
882 }  // namespace content