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 "media/base/media_switches.h"
16 #include "net/test/embedded_test_server/embedded_test_server.h"
22 string
GetSsrcAttributeString() const {
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
;
32 string
GetAsJSON() const {
35 std::map
<string
, string
>::const_iterator iter
;
36 for (iter
= properties
.begin(); iter
!= properties
.end(); ++iter
) {
37 if (iter
!= properties
.begin())
39 ss
<< "\"" << iter
->first
<< "\":\"" << iter
->second
<< "\"";
46 std::map
<string
, string
> properties
;
55 string
GetString() const {
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
<< "',";
67 std::map
<string
, string
> values
;
76 typedef std::map
<string
, std::vector
<string
> > StatsMap
;
78 class PeerConnectionEntry
{
80 PeerConnectionEntry(int pid
, int lid
) : pid_(pid
), lid_(lid
) {}
82 void AddEvent(const string
& type
, const string
& value
) {
83 EventEntry entry
= {type
, value
};
84 events_
.push_back(entry
);
87 string
getIdString() const {
89 ss
<< pid_
<< "-" << lid_
;
93 string
getLogIdString() const {
95 ss
<< pid_
<< "-" << lid_
<< "-update-log";
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
<< "'},";
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_
;
120 class UserMediaRequestEntry
{
122 UserMediaRequestEntry(int pid
,
124 const std::string
& origin
,
125 const std::string
& audio_constraints
,
126 const std::string
& video_constraints
)
130 audio_constraints(audio_constraints
),
131 video_constraints(video_constraints
) {}
136 std::string audio_constraints
;
137 std::string video_constraints
;
140 static const int64 FAKE_TIME_STAMP
= 3600000;
143 // All tests are flaky on Windows: crbug.com/277322.
144 #define MAYBE_WebRtcInternalsBrowserTest DISABLED_WebRtcInternalsBrowserTest
146 #define MAYBE_WebRtcInternalsBrowserTest WebRtcInternalsBrowserTest
149 class MAYBE_WebRtcInternalsBrowserTest
: public ContentBrowserTest
{
151 MAYBE_WebRtcInternalsBrowserTest() {}
152 virtual ~MAYBE_WebRtcInternalsBrowserTest() {}
154 virtual void SetUpOnMainThread() OVERRIDE
{
155 // We need fake devices in this test since we want to run on naked VMs. We
156 // assume these switches are set by default in content_browsertests.
157 ASSERT_TRUE(CommandLine::ForCurrentProcess()->HasSwitch(
158 switches::kUseFakeDeviceForMediaStream
));
159 ASSERT_TRUE(CommandLine::ForCurrentProcess()->HasSwitch(
160 switches::kUseFakeUIForMediaStream
));
164 bool ExecuteJavascript(const string
& javascript
) {
165 return ExecuteScript(shell()->web_contents(), javascript
);
168 void ExpectTitle(const std::string
& expected_title
) const {
169 base::string16
expected_title16(base::ASCIIToUTF16(expected_title
));
170 TitleWatcher
title_watcher(shell()->web_contents(), expected_title16
);
171 EXPECT_EQ(expected_title16
, title_watcher
.WaitAndGetTitle());
174 // Execute the javascript of addPeerConnection.
175 void ExecuteAddPeerConnectionJs(const PeerConnectionEntry
& pc
) {
176 std::stringstream ss
;
177 ss
<< "{pid:" << pc
.pid_
<<", lid:" << pc
.lid_
<< ", " <<
178 "url:'u', rtcConfiguration:'s', constraints:'c'}";
179 ASSERT_TRUE(ExecuteJavascript("addPeerConnection(" + ss
.str() + ");"));
182 // Execute the javascript of removePeerConnection.
183 void ExecuteRemovePeerConnectionJs(const PeerConnectionEntry
& pc
) {
184 std::stringstream ss
;
185 ss
<< "{pid:" << pc
.pid_
<<", lid:" << pc
.lid_
<< "}";
187 ASSERT_TRUE(ExecuteJavascript("removePeerConnection(" + ss
.str() + ");"));
190 // Execute the javascript of addGetUserMedia.
191 void ExecuteAddGetUserMediaJs(const UserMediaRequestEntry
& request
) {
192 std::stringstream ss
;
193 ss
<< "{pid:" << request
.pid
<< ", rid:" << request
.rid
<< ", origin:'"
194 << request
.origin
<< "', audio:'" << request
.audio_constraints
195 << "', video:'" << request
.video_constraints
<< "'}";
197 ASSERT_TRUE(ExecuteJavascript("addGetUserMedia(" + ss
.str() + ");"));
200 // Execute the javascript of removeGetUserMediaForRenderer.
201 void ExecuteRemoveGetUserMediaForRendererJs(int rid
) {
202 std::stringstream ss
;
203 ss
<< "{rid:" << rid
<< "}";
205 ExecuteJavascript("removeGetUserMediaForRenderer(" + ss
.str() + ");"));
208 // Verifies that the DOM element with id |id| exists.
209 void VerifyElementWithId(const string
& id
) {
211 ASSERT_TRUE(ExecuteScriptAndExtractBool(
212 shell()->web_contents(),
213 "window.domAutomationController.send($('" + id
+ "') != null);",
218 // Verifies that the DOM element with id |id| does not exist.
219 void VerifyNoElementWithId(const string
& id
) {
221 ASSERT_TRUE(ExecuteScriptAndExtractBool(
222 shell()->web_contents(),
223 "window.domAutomationController.send($('" + id
+ "') == null);",
228 // Verifies the JS Array of userMediaRequests matches |requests|.
229 void VerifyUserMediaRequest(
230 const std::vector
<UserMediaRequestEntry
>& requests
) {
231 string json_requests
;
232 ASSERT_TRUE(ExecuteScriptAndExtractString(
233 shell()->web_contents(),
234 "window.domAutomationController.send("
235 "JSON.stringify(userMediaRequests));",
237 scoped_ptr
<base::Value
> value_requests
;
238 value_requests
.reset(base::JSONReader::Read(json_requests
));
240 EXPECT_EQ(base::Value::TYPE_LIST
, value_requests
->GetType());
242 base::ListValue
* list_request
=
243 static_cast<base::ListValue
*>(value_requests
.get());
244 EXPECT_EQ(requests
.size(), list_request
->GetSize());
246 for (size_t i
= 0; i
< requests
.size(); ++i
) {
247 base::DictionaryValue
* dict
= NULL
;
248 ASSERT_TRUE(list_request
->GetDictionary(i
, &dict
));
250 std::string origin
, audio
, video
;
251 ASSERT_TRUE(dict
->GetInteger("pid", &pid
));
252 ASSERT_TRUE(dict
->GetInteger("rid", &rid
));
253 ASSERT_TRUE(dict
->GetString("origin", &origin
));
254 ASSERT_TRUE(dict
->GetString("audio", &audio
));
255 ASSERT_TRUE(dict
->GetString("video", &video
));
256 EXPECT_EQ(requests
[i
].pid
, pid
);
257 EXPECT_EQ(requests
[i
].rid
, rid
);
258 EXPECT_EQ(requests
[i
].origin
, origin
);
259 EXPECT_EQ(requests
[i
].audio_constraints
, audio
);
260 EXPECT_EQ(requests
[i
].video_constraints
, video
);
263 bool user_media_tab_existed
= false;
264 ASSERT_TRUE(ExecuteScriptAndExtractBool(
265 shell()->web_contents(),
266 "window.domAutomationController.send("
267 "$('user-media-tab-id') != null);",
268 &user_media_tab_existed
));
269 EXPECT_EQ(!requests
.empty(), user_media_tab_existed
);
271 if (user_media_tab_existed
) {
272 int user_media_request_count
= -1;
273 ASSERT_TRUE(ExecuteScriptAndExtractInt(
274 shell()->web_contents(),
275 "window.domAutomationController.send("
276 "$('user-media-tab-id').childNodes.length);",
277 &user_media_request_count
));
278 ASSERT_EQ(requests
.size(), static_cast<size_t>(user_media_request_count
));
282 // Verifies that DOM for |pc| is correctly created with the right content.
283 void VerifyPeerConnectionEntry(const PeerConnectionEntry
& pc
) {
284 VerifyElementWithId(pc
.getIdString());
285 if (pc
.events_
.size() == 0)
288 string log_id
= pc
.getLogIdString();
289 VerifyElementWithId(log_id
);
291 for (size_t i
= 0; i
< pc
.events_
.size(); ++i
) {
292 std::stringstream ss
;
293 ss
<< "var row = $('" << log_id
<< "').rows[" << (i
+ 1) << "];"
294 "var cell = row.lastChild;"
295 "window.domAutomationController.send(cell.firstChild.textContent);";
296 ASSERT_TRUE(ExecuteScriptAndExtractString(
297 shell()->web_contents(), ss
.str(), &result
));
298 EXPECT_EQ(pc
.events_
[i
].type
+ pc
.events_
[i
].value
, result
);
302 // Executes the javascript of updatePeerConnection and verifies the result.
303 void ExecuteAndVerifyUpdatePeerConnection(
304 PeerConnectionEntry
& pc
, const string
& type
, const string
& value
) {
305 pc
.AddEvent(type
, value
);
307 std::stringstream ss
;
308 ss
<< "{pid:" << pc
.pid_
<<", lid:" << pc
.lid_
<<
309 ", type:'" << type
<< "', value:'" << value
<< "'}";
310 ASSERT_TRUE(ExecuteJavascript("updatePeerConnection(" + ss
.str() + ")"));
312 VerifyPeerConnectionEntry(pc
);
315 // Execute addStats and verifies that the stats table has the right content.
316 void ExecuteAndVerifyAddStats(
317 PeerConnectionEntry
& pc
, const string
& type
, const string
& id
,
319 StatsEntry entry
= {type
, id
, stats
};
321 // Adds each new value to the map of stats history.
322 std::map
<string
, string
>::iterator iter
;
323 for (iter
= stats
.values
.begin(); iter
!= stats
.values
.end(); iter
++) {
324 pc
.stats_
[id
][iter
->first
].push_back(iter
->second
);
326 std::stringstream ss
;
327 ss
<< "{pid:" << pc
.pid_
<< ", lid:" << pc
.lid_
<< ","
328 "reports:[" << "{id:'" << id
<< "', type:'" << type
<< "', "
329 "stats:" << stats
.GetString() << "}]}";
331 ASSERT_TRUE(ExecuteJavascript("addStats(" + ss
.str() + ")"));
332 VerifyStatsTable(pc
, entry
);
336 // Verifies that the stats table has the right content.
337 void VerifyStatsTable(const PeerConnectionEntry
& pc
,
338 const StatsEntry
& report
) {
340 pc
.getIdString() + "-table-" + report
.id
;
341 VerifyElementWithId(table_id
);
343 std::map
<string
, string
>::const_iterator iter
;
344 for (iter
= report
.stats
.values
.begin();
345 iter
!= report
.stats
.values
.end(); iter
++) {
346 VerifyStatsTableRow(table_id
, iter
->first
, iter
->second
);
350 // Verifies that the row named as |name| of the stats table |table_id| has
351 // the correct content as |name| : |value|.
352 void VerifyStatsTableRow(const string
& table_id
,
354 const string
& value
) {
355 VerifyElementWithId(table_id
+ "-" + name
);
358 ASSERT_TRUE(ExecuteScriptAndExtractString(
359 shell()->web_contents(),
360 "var row = $('" + table_id
+ "-" + name
+ "');"
361 "var name = row.cells[0].textContent;"
362 "var value = row.cells[1].textContent;"
363 "window.domAutomationController.send(name + ':' + value)",
365 EXPECT_EQ(name
+ ":" + value
, result
);
368 // Verifies that the graph data series consistent with pc.stats_.
369 void VerifyStatsGraph(const PeerConnectionEntry
& pc
) {
370 std::map
<string
, StatsMap
>::const_iterator stream_iter
;
371 for (stream_iter
= pc
.stats_
.begin();
372 stream_iter
!= pc
.stats_
.end(); stream_iter
++) {
373 StatsMap::const_iterator stats_iter
;
374 for (stats_iter
= stream_iter
->second
.begin();
375 stats_iter
!= stream_iter
->second
.end();
377 string graph_id
= stream_iter
->first
+ "-" + stats_iter
->first
;
378 for (size_t i
= 0; i
< stats_iter
->second
.size(); ++i
) {
380 std::stringstream
stream(stats_iter
->second
[i
]);
384 VerifyGraphDataPoint(
385 pc
.getIdString(), graph_id
, i
, stats_iter
->second
[i
]);
391 // Verifies that the graph data point at index |index| has value |value|.
392 void VerifyGraphDataPoint(const string
& pc_id
, const string
& graph_id
,
393 int index
, const string
& value
) {
395 ASSERT_TRUE(ExecuteScriptAndExtractBool(
396 shell()->web_contents(),
397 "window.domAutomationController.send("
398 "graphViews['" + pc_id
+ "-" + graph_id
+ "'] != null)",
402 std::stringstream ss
;
403 ss
<< "var dp = peerConnectionDataStore['" << pc_id
<< "']"
404 ".getDataSeries('" << graph_id
<< "').dataPoints_[" << index
<< "];"
405 "window.domAutomationController.send(dp.value.toString())";
407 ASSERT_TRUE(ExecuteScriptAndExtractString(
408 shell()->web_contents(), ss
.str(), &actual_value
));
409 EXPECT_EQ(value
, actual_value
);
412 // Get the JSON string of the ssrc info from the page.
413 string
GetSsrcInfo(const string
& ssrc_id
) {
415 EXPECT_TRUE(ExecuteScriptAndExtractString(
416 shell()->web_contents(),
417 "window.domAutomationController.send(JSON.stringify("
418 "ssrcInfoManager.streamInfoContainer_['" + ssrc_id
+ "']))",
423 int GetSsrcInfoBlockCount(Shell
* shell
) {
425 EXPECT_TRUE(ExecuteScriptAndExtractInt(
426 shell
->web_contents(),
427 "window.domAutomationController.send("
428 "document.getElementsByClassName("
429 "ssrcInfoManager.SSRC_INFO_BLOCK_CLASS).length);",
434 // Verifies |dump| contains |peer_connection_number| peer connection dumps,
435 // each containing |update_number| updates and |stats_number| stats tables.
436 void VerifyPageDumpStructure(base::Value
* dump
,
437 int peer_connection_number
,
440 EXPECT_NE((base::Value
*)NULL
, dump
);
441 EXPECT_EQ(base::Value::TYPE_DICTIONARY
, dump
->GetType());
443 base::DictionaryValue
* dict_dump
=
444 static_cast<base::DictionaryValue
*>(dump
);
445 EXPECT_EQ((size_t) peer_connection_number
, dict_dump
->size());
447 base::DictionaryValue::Iterator
it(*dict_dump
);
448 for (; !it
.IsAtEnd(); it
.Advance()) {
449 base::Value
* value
= NULL
;
450 dict_dump
->Get(it
.key(), &value
);
451 EXPECT_EQ(base::Value::TYPE_DICTIONARY
, value
->GetType());
452 base::DictionaryValue
* pc_dump
=
453 static_cast<base::DictionaryValue
*>(value
);
454 EXPECT_TRUE(pc_dump
->HasKey("updateLog"));
455 EXPECT_TRUE(pc_dump
->HasKey("stats"));
457 // Verifies the number of updates.
458 pc_dump
->Get("updateLog", &value
);
459 EXPECT_EQ(base::Value::TYPE_LIST
, value
->GetType());
460 base::ListValue
* list
= static_cast<base::ListValue
*>(value
);
461 EXPECT_EQ((size_t) update_number
, list
->GetSize());
463 // Verifies the number of stats tables.
464 pc_dump
->Get("stats", &value
);
465 EXPECT_EQ(base::Value::TYPE_DICTIONARY
, value
->GetType());
466 base::DictionaryValue
* dict
= static_cast<base::DictionaryValue
*>(value
);
467 EXPECT_EQ((size_t) stats_number
, dict
->size());
471 // Verifies |dump| contains the correct statsTable and statsDataSeries for
473 void VerifyStatsDump(base::Value
* dump
,
474 const PeerConnectionEntry
& pc
,
475 const string
& report_type
,
476 const string
& report_id
,
477 const StatsUnit
& stats
) {
478 EXPECT_NE((base::Value
*)NULL
, dump
);
479 EXPECT_EQ(base::Value::TYPE_DICTIONARY
, dump
->GetType());
481 base::DictionaryValue
* dict_dump
=
482 static_cast<base::DictionaryValue
*>(dump
);
483 base::Value
* value
= NULL
;
484 dict_dump
->Get(pc
.getIdString(), &value
);
485 base::DictionaryValue
* pc_dump
= static_cast<base::DictionaryValue
*>(value
);
487 // Verifies there is one data series per stats name.
489 pc_dump
->Get("stats", &value
);
490 EXPECT_EQ(base::Value::TYPE_DICTIONARY
, value
->GetType());
492 base::DictionaryValue
* dataSeries
=
493 static_cast<base::DictionaryValue
*>(value
);
494 EXPECT_EQ(stats
.values
.size(), dataSeries
->size());
498 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest
,
499 AddAndRemovePeerConnection
) {
500 GURL
url("chrome://webrtc-internals");
501 NavigateToURL(shell(), url
);
503 // Add two PeerConnections and then remove them.
504 PeerConnectionEntry
pc_1(1, 0);
505 ExecuteAddPeerConnectionJs(pc_1
);
506 VerifyPeerConnectionEntry(pc_1
);
508 PeerConnectionEntry
pc_2(2, 1);
509 ExecuteAddPeerConnectionJs(pc_2
);
510 VerifyPeerConnectionEntry(pc_2
);
512 ExecuteRemovePeerConnectionJs(pc_1
);
513 VerifyNoElementWithId(pc_1
.getIdString());
514 VerifyPeerConnectionEntry(pc_2
);
516 ExecuteRemovePeerConnectionJs(pc_2
);
517 VerifyNoElementWithId(pc_2
.getIdString());
520 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest
,
521 UpdateAllPeerConnections
) {
522 GURL
url("chrome://webrtc-internals");
523 NavigateToURL(shell(), url
);
525 PeerConnectionEntry
pc_0(1, 0);
526 pc_0
.AddEvent("e1", "v1");
527 pc_0
.AddEvent("e2", "v2");
528 PeerConnectionEntry
pc_1(1, 1);
529 pc_1
.AddEvent("e3", "v3");
530 pc_1
.AddEvent("e4", "v4");
531 string pc_array
= "[" + pc_0
.getAllUpdateString() + ", " +
532 pc_1
.getAllUpdateString() + "]";
533 EXPECT_TRUE(ExecuteJavascript("updateAllPeerConnections(" + pc_array
+ ");"));
534 VerifyPeerConnectionEntry(pc_0
);
535 VerifyPeerConnectionEntry(pc_1
);
538 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest
, UpdatePeerConnection
) {
539 GURL
url("chrome://webrtc-internals");
540 NavigateToURL(shell(), url
);
542 // Add one PeerConnection and send one update.
543 PeerConnectionEntry
pc_1(1, 0);
544 ExecuteAddPeerConnectionJs(pc_1
);
546 ExecuteAndVerifyUpdatePeerConnection(pc_1
, "e1", "v1");
548 // Add another PeerConnection and send two updates.
549 PeerConnectionEntry
pc_2(1, 1);
550 ExecuteAddPeerConnectionJs(pc_2
);
552 SsrcEntry ssrc1
, ssrc2
;
553 ssrc1
.id
= "ssrcid1";
554 ssrc1
.properties
["msid"] = "mymsid";
555 ssrc2
.id
= "ssrcid2";
556 ssrc2
.properties
["label"] = "mylabel";
557 ssrc2
.properties
["cname"] = "mycname";
559 ExecuteAndVerifyUpdatePeerConnection(pc_2
, "setRemoteDescription",
560 ssrc1
.GetSsrcAttributeString());
562 ExecuteAndVerifyUpdatePeerConnection(pc_2
, "setLocalDescription",
563 ssrc2
.GetSsrcAttributeString());
565 EXPECT_EQ(ssrc1
.GetAsJSON(), GetSsrcInfo(ssrc1
.id
));
566 EXPECT_EQ(ssrc2
.GetAsJSON(), GetSsrcInfo(ssrc2
.id
));
568 StatsUnit stats
= {FAKE_TIME_STAMP
};
569 stats
.values
["ssrc"] = ssrc1
.id
;
570 ExecuteAndVerifyAddStats(pc_2
, "ssrc", "dummyId", stats
);
571 EXPECT_GT(GetSsrcInfoBlockCount(shell()), 0);
574 // Tests that adding random named stats updates the dataSeries and graphs.
575 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest
, AddStats
) {
576 GURL
url("chrome://webrtc-internals");
577 NavigateToURL(shell(), url
);
579 PeerConnectionEntry
pc(1, 0);
580 ExecuteAddPeerConnectionJs(pc
);
582 const string type
= "ssrc";
583 const string id
= "ssrc-1234";
584 StatsUnit stats
= {FAKE_TIME_STAMP
};
585 stats
.values
["trackId"] = "abcd";
586 stats
.values
["bitrate"] = "2000";
587 stats
.values
["framerate"] = "30";
589 // Add new stats and verify the stats table and graphs.
590 ExecuteAndVerifyAddStats(pc
, type
, id
, stats
);
591 VerifyStatsGraph(pc
);
593 // Update existing stats and verify the stats table and graphs.
594 stats
.values
["bitrate"] = "2001";
595 stats
.values
["framerate"] = "31";
596 ExecuteAndVerifyAddStats(pc
, type
, id
, stats
);
597 VerifyStatsGraph(pc
);
600 // Tests that the bandwidth estimation values are drawn on a single graph.
601 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest
, BweCompoundGraph
) {
602 GURL
url("chrome://webrtc-internals");
603 NavigateToURL(shell(), url
);
605 PeerConnectionEntry
pc(1, 0);
606 ExecuteAddPeerConnectionJs(pc
);
608 StatsUnit stats
= {FAKE_TIME_STAMP
};
609 stats
.values
["googAvailableSendBandwidth"] = "1000000";
610 stats
.values
["googTargetEncBitrate"] = "1000";
611 stats
.values
["googActualEncBitrate"] = "1000000";
612 stats
.values
["googRetransmitBitrate"] = "10";
613 stats
.values
["googTransmitBitrate"] = "1000000";
614 const string stats_type
= "bwe";
615 const string stats_id
= "videobwe";
616 ExecuteAndVerifyAddStats(pc
, stats_type
, stats_id
, stats
);
619 pc
.getIdString() + "-" + stats_id
+ "-bweCompound";
621 // Verify that the bweCompound graph exists.
622 ASSERT_TRUE(ExecuteScriptAndExtractBool(
623 shell()->web_contents(),
624 "window.domAutomationController.send("
625 " graphViews['" + graph_id
+ "'] != null)",
629 // Verify that the bweCompound graph contains multiple dataSeries.
631 ASSERT_TRUE(ExecuteScriptAndExtractInt(
632 shell()->web_contents(),
633 "window.domAutomationController.send("
634 " graphViews['" + graph_id
+ "'].getDataSeriesCount())",
636 EXPECT_EQ((int)stats
.values
.size(), count
);
639 // Tests that the total packet/byte count is converted to count per second,
640 // and the converted data is drawn.
641 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest
, ConvertedGraphs
) {
642 GURL
url("chrome://webrtc-internals");
643 NavigateToURL(shell(), url
);
645 PeerConnectionEntry
pc(1, 0);
646 ExecuteAddPeerConnectionJs(pc
);
648 const string stats_type
= "s";
649 const string stats_id
= "1";
650 const int num_converted_stats
= 4;
651 const string stats_names
[] =
652 {"packetsSent", "bytesSent", "packetsReceived", "bytesReceived"};
653 const string converted_names
[] =
654 {"packetsSentPerSecond", "bitsSentPerSecond",
655 "packetsReceivedPerSecond", "bitsReceivedPerSecond"};
656 const string first_value
= "1000";
657 const string second_value
= "2000";
658 const string converted_values
[] = {"1000", "8000", "1000", "8000"};
660 // Send the first data point.
661 StatsUnit stats
= {FAKE_TIME_STAMP
};
662 for (int i
= 0; i
< num_converted_stats
; ++i
)
663 stats
.values
[stats_names
[i
]] = first_value
;
665 ExecuteAndVerifyAddStats(pc
, stats_type
, stats_id
, stats
);
667 // Send the second data point at 1000ms after the first data point.
668 stats
.timestamp
+= 1000;
669 for (int i
= 0; i
< num_converted_stats
; ++i
)
670 stats
.values
[stats_names
[i
]] = second_value
;
671 ExecuteAndVerifyAddStats(pc
, stats_type
, stats_id
, stats
);
673 // Verifies the graph data matches converted_values.
674 for (int i
= 0; i
< num_converted_stats
; ++i
) {
675 VerifyGraphDataPoint(pc
.getIdString(), stats_id
+ "-" + converted_names
[i
],
676 1, converted_values
[i
]);
680 // Timing out on ARM linux bot: http://crbug.com/238490
681 // Disabling due to failure on Linux, Mac, Win: http://crbug.com/272413
682 // Sanity check of the page content under a real PeerConnection call.
683 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest
,
684 DISABLED_WithRealPeerConnectionCall
) {
685 // Start a peerconnection call in the first window.
686 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
687 GURL
url(embedded_test_server()->GetURL("/media/peerconnection-call.html"));
688 NavigateToURL(shell(), url
);
689 ASSERT_TRUE(ExecuteJavascript("call({video:true});"));
692 // Open webrtc-internals in the second window.
693 GURL
url2("chrome://webrtc-internals");
694 Shell
* shell2
= CreateBrowser();
695 NavigateToURL(shell2
, url2
);
697 const int NUMBER_OF_PEER_CONNECTIONS
= 2;
699 // Verifies the number of peerconnections.
701 ASSERT_TRUE(ExecuteScriptAndExtractInt(
702 shell2
->web_contents(),
703 "window.domAutomationController.send("
704 "$('peer-connections-list').getElementsByTagName('li').length);",
706 EXPECT_EQ(NUMBER_OF_PEER_CONNECTIONS
, count
);
708 // Verifies the the event tables.
709 ASSERT_TRUE(ExecuteScriptAndExtractInt(
710 shell2
->web_contents(),
711 "window.domAutomationController.send($('peer-connections-list')"
712 ".getElementsByClassName('update-log-table').length);",
714 EXPECT_EQ(NUMBER_OF_PEER_CONNECTIONS
, count
);
716 ASSERT_TRUE(ExecuteScriptAndExtractInt(
717 shell2
->web_contents(),
718 "window.domAutomationController.send($('peer-connections-list')"
719 ".getElementsByClassName('update-log-table')[0].rows.length);",
723 ASSERT_TRUE(ExecuteScriptAndExtractInt(
724 shell2
->web_contents(),
725 "window.domAutomationController.send($('peer-connections-list')"
726 ".getElementsByClassName('update-log-table')[1].rows.length);",
730 // Wait until the stats table containers are created.
732 while (count
!= NUMBER_OF_PEER_CONNECTIONS
) {
733 ASSERT_TRUE(ExecuteScriptAndExtractInt(
734 shell2
->web_contents(),
735 "window.domAutomationController.send("
736 "$('peer-connections-list').getElementsByClassName("
737 "'stats-table-container').length);",
741 // Verifies each stats table having more than one rows.
743 ASSERT_TRUE(ExecuteScriptAndExtractBool(
744 shell2
->web_contents(),
745 "var tableContainers = $('peer-connections-list')"
746 ".getElementsByClassName('stats-table-container');"
748 "for (var i = 0; i < tableContainers.length && result; ++i) {"
749 "var tables = tableContainers[i].getElementsByTagName('table');"
750 "for (var j = 0; j < tables.length && result; ++j) {"
751 "result = (tables[j].rows.length > 1);"
754 "console.log(tableContainers[i].innerHTML);"
757 "window.domAutomationController.send(result);",
762 count
= GetSsrcInfoBlockCount(shell2
);
766 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest
, CreatePageDump
) {
767 GURL
url("chrome://webrtc-internals");
768 NavigateToURL(shell(), url
);
770 PeerConnectionEntry
pc_0(1, 0);
771 pc_0
.AddEvent("e1", "v1");
772 pc_0
.AddEvent("e2", "v2");
773 PeerConnectionEntry
pc_1(1, 1);
774 pc_1
.AddEvent("e3", "v3");
775 pc_1
.AddEvent("e4", "v4");
777 "[" + pc_0
.getAllUpdateString() + ", " + pc_1
.getAllUpdateString() + "]";
778 EXPECT_TRUE(ExecuteJavascript("updateAllPeerConnections(" + pc_array
+ ");"));
780 // Verifies the peer connection data store can be created without stats.
782 ASSERT_TRUE(ExecuteScriptAndExtractString(
783 shell()->web_contents(),
784 "window.domAutomationController.send("
785 "JSON.stringify(peerConnectionDataStore));",
787 scoped_ptr
<base::Value
> dump
;
788 dump
.reset(base::JSONReader::Read(dump_json
));
789 VerifyPageDumpStructure(dump
.get(),
790 2 /*peer_connection_number*/,
794 // Adds a stats report.
795 const string type
= "dummy";
796 const string id
= "1234";
797 StatsUnit stats
= { FAKE_TIME_STAMP
};
798 stats
.values
["bitrate"] = "2000";
799 stats
.values
["framerate"] = "30";
800 ExecuteAndVerifyAddStats(pc_0
, type
, id
, stats
);
802 ASSERT_TRUE(ExecuteScriptAndExtractString(
803 shell()->web_contents(),
804 "window.domAutomationController.send("
805 "JSON.stringify(peerConnectionDataStore));",
807 dump
.reset(base::JSONReader::Read(dump_json
));
808 VerifyStatsDump(dump
.get(), pc_0
, type
, id
, stats
);
811 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest
, UpdateGetUserMedia
) {
812 GURL
url("chrome://webrtc-internals");
813 NavigateToURL(shell(), url
);
815 UserMediaRequestEntry
request1(1, 1, "origin", "ac", "vc");
816 UserMediaRequestEntry
request2(2, 2, "origin2", "ac2", "vc2");
817 ExecuteAddGetUserMediaJs(request1
);
818 ExecuteAddGetUserMediaJs(request2
);
820 std::vector
<UserMediaRequestEntry
> list
;
821 list
.push_back(request1
);
822 list
.push_back(request2
);
823 VerifyUserMediaRequest(list
);
825 ExecuteRemoveGetUserMediaForRendererJs(1);
826 list
.erase(list
.begin());
827 VerifyUserMediaRequest(list
);
829 ExecuteRemoveGetUserMediaForRendererJs(2);
830 list
.erase(list
.begin());
831 VerifyUserMediaRequest(list
);
834 // Tests that the received propagation delta values are converted and drawn
836 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest
,
837 ReceivedPropagationDelta
) {
838 GURL
url("chrome://webrtc-internals");
839 NavigateToURL(shell(), url
);
841 PeerConnectionEntry
pc(1, 0);
842 ExecuteAddPeerConnectionJs(pc
);
844 StatsUnit stats
= {FAKE_TIME_STAMP
};
845 stats
.values
["googReceivedPacketGroupArrivalTimeDebug"] =
846 "[1000, 1100, 1200]";
847 stats
.values
["googReceivedPacketGroupPropagationDeltaDebug"] =
849 const string stats_type
= "bwe";
850 const string stats_id
= "videobwe";
851 ExecuteAndVerifyAddStats(pc
, stats_type
, stats_id
, stats
);
853 string graph_id
= pc
.getIdString() + "-" + stats_id
+
854 "-googReceivedPacketGroupPropagationDeltaDebug";
855 string data_series_id
=
856 stats_id
+ "-googReceivedPacketGroupPropagationDeltaDebug";
858 // Verify that the graph exists.
859 ASSERT_TRUE(ExecuteScriptAndExtractBool(
860 shell()->web_contents(),
861 "window.domAutomationController.send("
862 " graphViews['" + graph_id
+ "'] != null)",
866 // Verify that the graph contains multiple data points.
868 ASSERT_TRUE(ExecuteScriptAndExtractInt(
869 shell()->web_contents(),
870 "window.domAutomationController.send("
871 " graphViews['" + graph_id
+ "'].getDataSeriesCount())",
874 ASSERT_TRUE(ExecuteScriptAndExtractInt(
875 shell()->web_contents(),
876 "window.domAutomationController.send("
877 " peerConnectionDataStore['" + pc
.getIdString() + "']" +
878 " .getDataSeries('" + data_series_id
+ "').getCount())",
883 } // namespace content