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