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.
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 "net/test/embedded_test_server/embedded_test_server.h"
21 string
GetSsrcAttributeString() const {
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
;
31 string
GetAsJSON() const {
34 std::map
<string
, string
>::const_iterator iter
;
35 for (iter
= properties
.begin(); iter
!= properties
.end(); ++iter
) {
36 if (iter
!= properties
.begin())
38 ss
<< "\"" << iter
->first
<< "\":\"" << iter
->second
<< "\"";
45 std::map
<string
, string
> properties
;
54 string
GetString() const {
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
<< "',";
66 std::map
<string
, string
> values
;
75 typedef std::map
<string
, std::vector
<string
> > StatsMap
;
77 class PeerConnectionEntry
{
79 PeerConnectionEntry(int pid
, int lid
) : pid_(pid
), lid_(lid
) {}
81 void AddEvent(const string
& type
, const string
& value
) {
82 EventEntry entry
= {type
, value
};
83 events_
.push_back(entry
);
86 string
getIdString() const {
88 ss
<< pid_
<< "-" << lid_
;
92 string
getLogIdString() const {
94 ss
<< pid_
<< "-" << lid_
<< "-update-log";
98 string
getAllUpdateString() const {
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
<< "'},";
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_
;
119 class UserMediaRequestEntry
{
121 UserMediaRequestEntry(int pid
,
123 const std::string
& origin
,
124 const std::string
& audio_constraints
,
125 const std::string
& video_constraints
)
129 audio_constraints(audio_constraints
),
130 video_constraints(video_constraints
) {}
135 std::string audio_constraints
;
136 std::string video_constraints
;
139 static const int64 FAKE_TIME_STAMP
= 3600000;
142 // All tests are flaky on Windows: crbug.com/277322.
143 #define MAYBE_WebRtcInternalsBrowserTest DISABLED_WebRtcInternalsBrowserTest
145 #define MAYBE_WebRtcInternalsBrowserTest WebRtcInternalsBrowserTest
148 class MAYBE_WebRtcInternalsBrowserTest
: public ContentBrowserTest
{
150 MAYBE_WebRtcInternalsBrowserTest() {}
151 virtual ~MAYBE_WebRtcInternalsBrowserTest() {}
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
));
163 bool ExecuteJavascript(const string
& javascript
) {
164 return ExecuteScript(shell()->web_contents(), javascript
);
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());
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() + ");"));
181 // Execute the javascript of removePeerConnection.
182 void ExecuteRemovePeerConnectionJs(const PeerConnectionEntry
& pc
) {
183 std::stringstream ss
;
184 ss
<< "{pid:" << pc
.pid_
<<", lid:" << pc
.lid_
<< "}";
186 ASSERT_TRUE(ExecuteJavascript("removePeerConnection(" + ss
.str() + ");"));
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
<< "'}";
196 ASSERT_TRUE(ExecuteJavascript("addGetUserMedia(" + ss
.str() + ");"));
199 // Execute the javascript of removeGetUserMediaForRenderer.
200 void ExecuteRemoveGetUserMediaForRendererJs(int rid
) {
201 std::stringstream ss
;
202 ss
<< "{rid:" << rid
<< "}";
204 ExecuteJavascript("removeGetUserMediaForRenderer(" + ss
.str() + ");"));
207 // Verifies that the DOM element with id |id| exists.
208 void VerifyElementWithId(const string
& id
) {
210 ASSERT_TRUE(ExecuteScriptAndExtractBool(
211 shell()->web_contents(),
212 "window.domAutomationController.send($('" + id
+ "') != null);",
217 // Verifies that the DOM element with id |id| does not exist.
218 void VerifyNoElementWithId(const string
& id
) {
220 ASSERT_TRUE(ExecuteScriptAndExtractBool(
221 shell()->web_contents(),
222 "window.domAutomationController.send($('" + id
+ "') == null);",
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));",
236 scoped_ptr
<base::Value
> value_requests
;
237 value_requests
.reset(base::JSONReader::Read(json_requests
));
239 EXPECT_EQ(base::Value::TYPE_LIST
, value_requests
->GetType());
241 base::ListValue
* list_request
=
242 static_cast<base::ListValue
*>(value_requests
.get());
243 EXPECT_EQ(requests
.size(), list_request
->GetSize());
245 for (size_t i
= 0; i
< requests
.size(); ++i
) {
246 base::DictionaryValue
* dict
= NULL
;
247 ASSERT_TRUE(list_request
->GetDictionary(i
, &dict
));
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
);
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)
269 string log_id
= pc
.getLogIdString();
270 VerifyElementWithId(log_id
);
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
);
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
);
288 std::stringstream ss
;
289 ss
<< "{pid:" << pc
.pid_
<<", lid:" << pc
.lid_
<<
290 ", type:'" << type
<< "', value:'" << value
<< "'}";
291 ASSERT_TRUE(ExecuteJavascript("updatePeerConnection(" + ss
.str() + ")"));
293 VerifyPeerConnectionEntry(pc
);
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
,
300 StatsEntry entry
= {type
, id
, stats
};
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
);
307 std::stringstream ss
;
308 ss
<< "{pid:" << pc
.pid_
<< ", lid:" << pc
.lid_
<< ","
309 "reports:[" << "{id:'" << id
<< "', type:'" << type
<< "', "
310 "stats:" << stats
.GetString() << "}]}";
312 ASSERT_TRUE(ExecuteJavascript("addStats(" + ss
.str() + ")"));
313 VerifyStatsTable(pc
, entry
);
317 // Verifies that the stats table has the right content.
318 void VerifyStatsTable(const PeerConnectionEntry
& pc
,
319 const StatsEntry
& report
) {
321 pc
.getIdString() + "-table-" + report
.id
;
322 VerifyElementWithId(table_id
);
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
);
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
,
335 const string
& value
) {
336 VerifyElementWithId(table_id
+ "-" + name
);
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)",
346 EXPECT_EQ(name
+ ":" + value
, result
);
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();
358 string graph_id
= stream_iter
->first
+ "-" + stats_iter
->first
;
359 for (size_t i
= 0; i
< stats_iter
->second
.size(); ++i
) {
361 std::stringstream
stream(stats_iter
->second
[i
]);
365 VerifyGraphDataPoint(
366 pc
.getIdString(), graph_id
, i
, stats_iter
->second
[i
]);
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
) {
376 ASSERT_TRUE(ExecuteScriptAndExtractBool(
377 shell()->web_contents(),
378 "window.domAutomationController.send("
379 "graphViews['" + pc_id
+ "-" + graph_id
+ "'] != null)",
383 std::stringstream ss
;
384 ss
<< "var dp = peerConnectionDataStore['" << pc_id
<< "']"
385 ".getDataSeries('" << graph_id
<< "').dataPoints_[" << index
<< "];"
386 "window.domAutomationController.send(dp.value.toString())";
388 ASSERT_TRUE(ExecuteScriptAndExtractString(
389 shell()->web_contents(), ss
.str(), &actual_value
));
390 EXPECT_EQ(value
, actual_value
);
393 // Get the JSON string of the ssrc info from the page.
394 string
GetSsrcInfo(const string
& ssrc_id
) {
396 EXPECT_TRUE(ExecuteScriptAndExtractString(
397 shell()->web_contents(),
398 "window.domAutomationController.send(JSON.stringify("
399 "ssrcInfoManager.streamInfoContainer_['" + ssrc_id
+ "']))",
404 int GetSsrcInfoBlockCount(Shell
* shell
) {
406 EXPECT_TRUE(ExecuteScriptAndExtractInt(
407 shell
->web_contents(),
408 "window.domAutomationController.send("
409 "document.getElementsByClassName("
410 "ssrcInfoManager.SSRC_INFO_BLOCK_CLASS).length);",
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
,
421 EXPECT_NE((base::Value
*)NULL
, dump
);
422 EXPECT_EQ(base::Value::TYPE_DICTIONARY
, dump
->GetType());
424 base::DictionaryValue
* dict_dump
=
425 static_cast<base::DictionaryValue
*>(dump
);
426 EXPECT_EQ((size_t) peer_connection_number
, dict_dump
->size());
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"));
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());
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());
452 // Verifies |dump| contains the correct statsTable and statsDataSeries for
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());
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
);
468 // Verifies there is one data series per stats name.
470 pc_dump
->Get("stats", &value
);
471 EXPECT_EQ(base::Value::TYPE_DICTIONARY
, value
->GetType());
473 base::DictionaryValue
* dataSeries
=
474 static_cast<base::DictionaryValue
*>(value
);
475 EXPECT_EQ(stats
.values
.size(), dataSeries
->size());
479 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest
,
480 AddAndRemovePeerConnection
) {
481 GURL
url("chrome://webrtc-internals");
482 NavigateToURL(shell(), url
);
484 // Add two PeerConnections and then remove them.
485 PeerConnectionEntry
pc_1(1, 0);
486 ExecuteAddPeerConnectionJs(pc_1
);
487 VerifyPeerConnectionEntry(pc_1
);
489 PeerConnectionEntry
pc_2(2, 1);
490 ExecuteAddPeerConnectionJs(pc_2
);
491 VerifyPeerConnectionEntry(pc_2
);
493 ExecuteRemovePeerConnectionJs(pc_1
);
494 VerifyNoElementWithId(pc_1
.getIdString());
495 VerifyPeerConnectionEntry(pc_2
);
497 ExecuteRemovePeerConnectionJs(pc_2
);
498 VerifyNoElementWithId(pc_2
.getIdString());
501 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest
,
502 UpdateAllPeerConnections
) {
503 GURL
url("chrome://webrtc-internals");
504 NavigateToURL(shell(), url
);
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
);
519 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest
, UpdatePeerConnection
) {
520 GURL
url("chrome://webrtc-internals");
521 NavigateToURL(shell(), url
);
523 // Add one PeerConnection and send one update.
524 PeerConnectionEntry
pc_1(1, 0);
525 ExecuteAddPeerConnectionJs(pc_1
);
527 ExecuteAndVerifyUpdatePeerConnection(pc_1
, "e1", "v1");
529 // Add another PeerConnection and send two updates.
530 PeerConnectionEntry
pc_2(1, 1);
531 ExecuteAddPeerConnectionJs(pc_2
);
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";
540 ExecuteAndVerifyUpdatePeerConnection(pc_2
, "setRemoteDescription",
541 ssrc1
.GetSsrcAttributeString());
543 ExecuteAndVerifyUpdatePeerConnection(pc_2
, "setLocalDescription",
544 ssrc2
.GetSsrcAttributeString());
546 EXPECT_EQ(ssrc1
.GetAsJSON(), GetSsrcInfo(ssrc1
.id
));
547 EXPECT_EQ(ssrc2
.GetAsJSON(), GetSsrcInfo(ssrc2
.id
));
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);
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
);
560 PeerConnectionEntry
pc(1, 0);
561 ExecuteAddPeerConnectionJs(pc
);
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";
570 // Add new stats and verify the stats table and graphs.
571 ExecuteAndVerifyAddStats(pc
, type
, id
, stats
);
572 VerifyStatsGraph(pc
);
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
);
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
);
586 PeerConnectionEntry
pc(1, 0);
587 ExecuteAddPeerConnectionJs(pc
);
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
);
600 pc
.getIdString() + "-" + stats_id
+ "-bweCompound";
602 // Verify that the bweCompound graph exists.
603 ASSERT_TRUE(ExecuteScriptAndExtractBool(
604 shell()->web_contents(),
605 "window.domAutomationController.send("
606 " graphViews['" + graph_id
+ "'] != null)",
610 // Verify that the bweCompound graph contains multiple dataSeries.
612 ASSERT_TRUE(ExecuteScriptAndExtractInt(
613 shell()->web_contents(),
614 "window.domAutomationController.send("
615 " graphViews['" + graph_id
+ "'].getDataSeriesCount())",
617 EXPECT_EQ((int)stats
.values
.size(), count
);
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
);
626 PeerConnectionEntry
pc(1, 0);
627 ExecuteAddPeerConnectionJs(pc
);
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"};
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
;
646 ExecuteAndVerifyAddStats(pc
, stats_type
, stats_id
, stats
);
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
);
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
]);
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});"));
673 // Open webrtc-internals in the second window.
674 GURL
url2("chrome://webrtc-internals");
675 Shell
* shell2
= CreateBrowser();
676 NavigateToURL(shell2
, url2
);
678 const int NUMBER_OF_PEER_CONNECTIONS
= 2;
680 // Verifies the number of peerconnections.
682 ASSERT_TRUE(ExecuteScriptAndExtractInt(
683 shell2
->web_contents(),
684 "window.domAutomationController.send("
685 "$('peer-connections-list').getElementsByTagName('li').length);",
687 EXPECT_EQ(NUMBER_OF_PEER_CONNECTIONS
, count
);
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);",
695 EXPECT_EQ(NUMBER_OF_PEER_CONNECTIONS
, count
);
697 ASSERT_TRUE(ExecuteScriptAndExtractInt(
698 shell2
->web_contents(),
699 "window.domAutomationController.send($('peer-connections-list')"
700 ".getElementsByClassName('update-log-table')[0].rows.length);",
704 ASSERT_TRUE(ExecuteScriptAndExtractInt(
705 shell2
->web_contents(),
706 "window.domAutomationController.send($('peer-connections-list')"
707 ".getElementsByClassName('update-log-table')[1].rows.length);",
711 // Wait until the stats table containers are created.
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);",
722 // Verifies each stats table having more than one rows.
724 ASSERT_TRUE(ExecuteScriptAndExtractBool(
725 shell2
->web_contents(),
726 "var tableContainers = $('peer-connections-list')"
727 ".getElementsByClassName('stats-table-container');"
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);"
735 "console.log(tableContainers[i].innerHTML);"
738 "window.domAutomationController.send(result);",
743 count
= GetSsrcInfoBlockCount(shell2
);
747 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest
, CreatePageDump
) {
748 GURL
url("chrome://webrtc-internals");
749 NavigateToURL(shell(), url
);
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");
758 "[" + pc_0
.getAllUpdateString() + ", " + pc_1
.getAllUpdateString() + "]";
759 EXPECT_TRUE(ExecuteJavascript("updateAllPeerConnections(" + pc_array
+ ");"));
761 // Verifies the peer connection data store can be created without stats.
763 ASSERT_TRUE(ExecuteScriptAndExtractString(
764 shell()->web_contents(),
765 "window.domAutomationController.send("
766 "JSON.stringify(peerConnectionDataStore));",
768 scoped_ptr
<base::Value
> dump
;
769 dump
.reset(base::JSONReader::Read(dump_json
));
770 VerifyPageDumpStructure(dump
.get(),
771 2 /*peer_connection_number*/,
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
);
783 ASSERT_TRUE(ExecuteScriptAndExtractString(
784 shell()->web_contents(),
785 "window.domAutomationController.send("
786 "JSON.stringify(peerConnectionDataStore));",
788 dump
.reset(base::JSONReader::Read(dump_json
));
789 VerifyStatsDump(dump
.get(), pc_0
, type
, id
, stats
);
792 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest
, UpdateGetUserMedia
) {
793 GURL
url("chrome://webrtc-internals");
794 NavigateToURL(shell(), url
);
796 UserMediaRequestEntry
request1(1, 1, "origin", "ac", "vc");
797 UserMediaRequestEntry
request2(2, 2, "origin2", "ac2", "vc2");
798 ExecuteAddGetUserMediaJs(request1
);
799 ExecuteAddGetUserMediaJs(request2
);
801 std::vector
<UserMediaRequestEntry
> list
;
802 list
.push_back(request1
);
803 list
.push_back(request2
);
804 VerifyUserMediaRequest(list
);
806 ExecuteRemoveGetUserMediaForRendererJs(1);
807 list
.erase(list
.begin());
808 VerifyUserMediaRequest(list
);
810 ExecuteRemoveGetUserMediaForRendererJs(2);
811 list
.erase(list
.begin());
812 VerifyUserMediaRequest(list
);
815 // Tests that the received propagation delta values are converted and drawn
817 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest
,
818 ReceivedPropagationDelta
) {
819 GURL
url("chrome://webrtc-internals");
820 NavigateToURL(shell(), url
);
822 PeerConnectionEntry
pc(1, 0);
823 ExecuteAddPeerConnectionJs(pc
);
825 StatsUnit stats
= {FAKE_TIME_STAMP
};
826 stats
.values
["googReceivedPacketGroupArrivalTimeDebug"] =
827 "[1000, 1100, 1200]";
828 stats
.values
["googReceivedPacketGroupPropagationDeltaDebug"] =
830 const string stats_type
= "bwe";
831 const string stats_id
= "videobwe";
832 ExecuteAndVerifyAddStats(pc
, stats_type
, stats_id
, stats
);
834 string graph_id
= pc
.getIdString() + "-" + stats_id
+
835 "-googReceivedPacketGroupPropagationDeltaDebug";
836 string data_series_id
=
837 stats_id
+ "-googReceivedPacketGroupPropagationDeltaDebug";
839 // Verify that the graph exists.
840 ASSERT_TRUE(ExecuteScriptAndExtractBool(
841 shell()->web_contents(),
842 "window.domAutomationController.send("
843 " graphViews['" + graph_id
+ "'] != null)",
847 // Verify that the graph contains multiple data points.
849 ASSERT_TRUE(ExecuteScriptAndExtractInt(
850 shell()->web_contents(),
851 "window.domAutomationController.send("
852 " graphViews['" + graph_id
+ "'].getDataSeriesCount())",
855 ASSERT_TRUE(ExecuteScriptAndExtractInt(
856 shell()->web_contents(),
857 "window.domAutomationController.send("
858 " peerConnectionDataStore['" + pc
.getIdString() + "']" +
859 " .getDataSeries('" + data_series_id
+ "').getCount())",
864 } // namespace content