| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include "base/command_line.h" |
| #include "base/json/json_reader.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/time/time.h" |
| #include "base/values.h" |
| #include "build/build_config.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "content/public/test/content_browser_test.h" |
| #include "content/public/test/content_browser_test_utils.h" |
| #include "content/shell/browser/shell.h" |
| #include "media/base/media_switches.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| |
| using std::string; |
| namespace content { |
| |
| struct SsrcEntry { |
| string GetSsrcAttributeString() const { |
| std::stringstream ss; |
| ss << "a=ssrc:" << id; |
| std::map<string, string>::const_iterator iter; |
| for (iter = properties.begin(); iter != properties.end(); ++iter) { |
| ss << " " << iter->first << ":" << iter->second; |
| } |
| return ss.str(); |
| } |
| |
| string GetAsJSON() const { |
| std::stringstream ss; |
| ss << "{"; |
| std::map<string, string>::const_iterator iter; |
| for (iter = properties.begin(); iter != properties.end(); ++iter) { |
| if (iter != properties.begin()) |
| ss << ","; |
| ss << "\"" << iter->first << "\":\"" << iter->second << "\""; |
| } |
| ss << "}"; |
| return ss.str(); |
| } |
| |
| string id; |
| std::map<string, string> properties; |
| }; |
| |
| struct EventEntry { |
| string type; |
| string value; |
| }; |
| |
| struct StatsUnit { |
| string GetString() const { |
| std::stringstream ss; |
| ss << "{timestamp:" << timestamp << ", values:["; |
| std::map<string, string>::const_iterator iter; |
| for (iter = values.begin(); iter != values.end(); ++iter) { |
| ss << "'" << iter->first << "','" << iter->second << "',"; |
| } |
| ss << "]}"; |
| return ss.str(); |
| } |
| |
| int64_t timestamp; |
| std::map<string, string> values; |
| }; |
| |
| struct StatsEntry { |
| string type; |
| string id; |
| StatsUnit stats; |
| }; |
| |
| typedef std::map<string, std::vector<string> > StatsMap; |
| |
| class PeerConnectionEntry { |
| public: |
| PeerConnectionEntry(int pid, int lid) : pid_(pid), lid_(lid) {} |
| |
| void AddEvent(const string& type, const string& value) { |
| EventEntry entry = {type, value}; |
| events_.push_back(entry); |
| } |
| |
| string getIdString() const { |
| std::stringstream ss; |
| ss << pid_ << "-" << lid_; |
| return ss.str(); |
| } |
| |
| string getLogIdString() const { |
| std::stringstream ss; |
| ss << pid_ << "-" << lid_ << "-update-log"; |
| return ss.str(); |
| } |
| |
| string getAllUpdateString() const { |
| std::stringstream ss; |
| ss << "{pid:" << pid_ << ", lid:" << lid_ << ", log:["; |
| for (size_t i = 0; i < events_.size(); ++i) { |
| ss << "{type:'" << events_[i].type << |
| "', value:'" << events_[i].value << "'},"; |
| } |
| ss << "]}"; |
| return ss.str(); |
| } |
| |
| int pid_; |
| int lid_; |
| std::vector<EventEntry> events_; |
| // This is a record of the history of stats value reported for each stats |
| // report id (e.g. ssrc-1234) for each stats name (e.g. framerate). |
| // It a 2-D map with each map entry is a vector of reported values. |
| // It is used to verify the graph data series. |
| std::map<string, StatsMap> stats_; |
| }; |
| |
| class UserMediaRequestEntry { |
| public: |
| UserMediaRequestEntry(int pid, |
| int rid, |
| const std::string& origin, |
| const std::string& audio_constraints, |
| const std::string& video_constraints) |
| : pid(pid), |
| rid(rid), |
| origin(origin), |
| audio_constraints(audio_constraints), |
| video_constraints(video_constraints) {} |
| |
| int pid; |
| int rid; |
| std::string origin; |
| std::string audio_constraints; |
| std::string video_constraints; |
| }; |
| |
| static const int64_t FAKE_TIME_STAMP = 3600000; |
| |
| #if defined(OS_WIN) |
| // All tests are flaky on Windows: crbug.com/277322. |
| #define MAYBE_WebRtcInternalsBrowserTest DISABLED_WebRtcInternalsBrowserTest |
| #else |
| #define MAYBE_WebRtcInternalsBrowserTest WebRtcInternalsBrowserTest |
| #endif |
| |
| class MAYBE_WebRtcInternalsBrowserTest: public ContentBrowserTest { |
| public: |
| MAYBE_WebRtcInternalsBrowserTest() {} |
| ~MAYBE_WebRtcInternalsBrowserTest() override {} |
| |
| void SetUpOnMainThread() override { |
| base::CommandLine::ForCurrentProcess()->AppendSwitch( |
| switches::kUseFakeUIForMediaStream); |
| ASSERT_TRUE(base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kUseFakeDeviceForMediaStream)); |
| } |
| |
| protected: |
| bool ExecuteJavascript(const string& javascript) { |
| return ExecuteScript(shell()->web_contents(), javascript); |
| } |
| |
| void ExpectTitle(const std::string& expected_title) const { |
| base::string16 expected_title16(base::ASCIIToUTF16(expected_title)); |
| TitleWatcher title_watcher(shell()->web_contents(), expected_title16); |
| EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle()); |
| } |
| |
| // Execute the javascript of addPeerConnection. |
| void ExecuteAddPeerConnectionJs(const PeerConnectionEntry& pc) { |
| std::stringstream ss; |
| ss << "{pid:" << pc.pid_ <<", lid:" << pc.lid_ << ", " << |
| "url:'u', rtcConfiguration:'s', constraints:'c'}"; |
| ASSERT_TRUE(ExecuteJavascript("addPeerConnection(" + ss.str() + ");")); |
| } |
| |
| // Execute the javascript of removePeerConnection. |
| void ExecuteRemovePeerConnectionJs(const PeerConnectionEntry& pc) { |
| std::stringstream ss; |
| ss << "{pid:" << pc.pid_ <<", lid:" << pc.lid_ << "}"; |
| |
| ASSERT_TRUE(ExecuteJavascript("removePeerConnection(" + ss.str() + ");")); |
| } |
| |
| // Execute the javascript of addGetUserMedia. |
| void ExecuteAddGetUserMediaJs(const UserMediaRequestEntry& request) { |
| std::stringstream ss; |
| ss << "{pid:" << request.pid << ", rid:" << request.rid << ", origin:'" |
| << request.origin << "', audio:'" << request.audio_constraints |
| << "', video:'" << request.video_constraints << "'}"; |
| |
| ASSERT_TRUE(ExecuteJavascript("addGetUserMedia(" + ss.str() + ");")); |
| } |
| |
| // Execute the javascript of removeGetUserMediaForRenderer. |
| void ExecuteRemoveGetUserMediaForRendererJs(int rid) { |
| std::stringstream ss; |
| ss << "{rid:" << rid << "}"; |
| ASSERT_TRUE( |
| ExecuteJavascript("removeGetUserMediaForRenderer(" + ss.str() + ");")); |
| } |
| |
| // Verifies that the DOM element with id |id| exists. |
| void VerifyElementWithId(const string& id) { |
| bool result = false; |
| ASSERT_TRUE(ExecuteScriptAndExtractBool( |
| shell()->web_contents(), |
| "window.domAutomationController.send($('" + id + "') != null);", |
| &result)); |
| EXPECT_TRUE(result); |
| } |
| |
| // Verifies that the DOM element with id |id| does not exist. |
| void VerifyNoElementWithId(const string& id) { |
| bool result = false; |
| ASSERT_TRUE(ExecuteScriptAndExtractBool( |
| shell()->web_contents(), |
| "window.domAutomationController.send($('" + id + "') == null);", |
| &result)); |
| EXPECT_TRUE(result); |
| } |
| |
| // Verifies the JS Array of userMediaRequests matches |requests|. |
| void VerifyUserMediaRequest( |
| const std::vector<UserMediaRequestEntry>& requests) { |
| string json_requests; |
| ASSERT_TRUE(ExecuteScriptAndExtractString( |
| shell()->web_contents(), |
| "window.domAutomationController.send(" |
| "JSON.stringify(userMediaRequests));", |
| &json_requests)); |
| scoped_ptr<base::Value> value_requests = |
| base::JSONReader::Read(json_requests); |
| |
| EXPECT_EQ(base::Value::TYPE_LIST, value_requests->GetType()); |
| |
| base::ListValue* list_request = |
| static_cast<base::ListValue*>(value_requests.get()); |
| EXPECT_EQ(requests.size(), list_request->GetSize()); |
| |
| for (size_t i = 0; i < requests.size(); ++i) { |
| base::DictionaryValue* dict = NULL; |
| ASSERT_TRUE(list_request->GetDictionary(i, &dict)); |
| int pid, rid; |
| std::string origin, audio, video; |
| ASSERT_TRUE(dict->GetInteger("pid", &pid)); |
| ASSERT_TRUE(dict->GetInteger("rid", &rid)); |
| ASSERT_TRUE(dict->GetString("origin", &origin)); |
| ASSERT_TRUE(dict->GetString("audio", &audio)); |
| ASSERT_TRUE(dict->GetString("video", &video)); |
| EXPECT_EQ(requests[i].pid, pid); |
| EXPECT_EQ(requests[i].rid, rid); |
| EXPECT_EQ(requests[i].origin, origin); |
| EXPECT_EQ(requests[i].audio_constraints, audio); |
| EXPECT_EQ(requests[i].video_constraints, video); |
| } |
| |
| bool user_media_tab_existed = false; |
| ASSERT_TRUE(ExecuteScriptAndExtractBool( |
| shell()->web_contents(), |
| "window.domAutomationController.send(" |
| "$('user-media-tab-id') != null);", |
| &user_media_tab_existed)); |
| EXPECT_EQ(!requests.empty(), user_media_tab_existed); |
| |
| if (user_media_tab_existed) { |
| int user_media_request_count = -1; |
| ASSERT_TRUE(ExecuteScriptAndExtractInt( |
| shell()->web_contents(), |
| "window.domAutomationController.send(" |
| "$('user-media-tab-id').childNodes.length);", |
| &user_media_request_count)); |
| ASSERT_EQ(requests.size(), static_cast<size_t>(user_media_request_count)); |
| } |
| } |
| |
| // Verifies that DOM for |pc| is correctly created with the right content. |
| void VerifyPeerConnectionEntry(const PeerConnectionEntry& pc) { |
| VerifyElementWithId(pc.getIdString()); |
| if (pc.events_.size() == 0) |
| return; |
| |
| string log_id = pc.getLogIdString(); |
| VerifyElementWithId(log_id); |
| string result; |
| for (size_t i = 0; i < pc.events_.size(); ++i) { |
| std::stringstream ss; |
| ss << "var row = $('" << log_id << "').rows[" << (i + 1) << "];" |
| "var cell = row.lastChild;" |
| "window.domAutomationController.send(cell.firstChild.textContent);"; |
| ASSERT_TRUE(ExecuteScriptAndExtractString( |
| shell()->web_contents(), ss.str(), &result)); |
| EXPECT_EQ(pc.events_[i].type + pc.events_[i].value, result); |
| } |
| } |
| |
| // Executes the javascript of updatePeerConnection and verifies the result. |
| void ExecuteAndVerifyUpdatePeerConnection( |
| PeerConnectionEntry& pc, const string& type, const string& value) { |
| pc.AddEvent(type, value); |
| |
| std::stringstream ss; |
| ss << "{pid:" << pc.pid_ <<", lid:" << pc.lid_ << |
| ", type:'" << type << "', value:'" << value << "'}"; |
| ASSERT_TRUE(ExecuteJavascript("updatePeerConnection(" + ss.str() + ")")); |
| |
| VerifyPeerConnectionEntry(pc); |
| } |
| |
| // Execute addStats and verifies that the stats table has the right content. |
| void ExecuteAndVerifyAddStats( |
| PeerConnectionEntry& pc, const string& type, const string& id, |
| StatsUnit& stats) { |
| StatsEntry entry = {type, id, stats}; |
| |
| // Adds each new value to the map of stats history. |
| std::map<string, string>::iterator iter; |
| for (iter = stats.values.begin(); iter != stats.values.end(); iter++) { |
| pc.stats_[id][iter->first].push_back(iter->second); |
| } |
| std::stringstream ss; |
| ss << "{pid:" << pc.pid_ << ", lid:" << pc.lid_ << "," |
| "reports:[" << "{id:'" << id << "', type:'" << type << "', " |
| "stats:" << stats.GetString() << "}]}"; |
| |
| ASSERT_TRUE(ExecuteJavascript("addStats(" + ss.str() + ")")); |
| VerifyStatsTable(pc, entry); |
| } |
| |
| |
| // Verifies that the stats table has the right content. |
| void VerifyStatsTable(const PeerConnectionEntry& pc, |
| const StatsEntry& report) { |
| string table_id = |
| pc.getIdString() + "-table-" + report.id; |
| VerifyElementWithId(table_id); |
| |
| std::map<string, string>::const_iterator iter; |
| for (iter = report.stats.values.begin(); |
| iter != report.stats.values.end(); iter++) { |
| VerifyStatsTableRow(table_id, iter->first, iter->second); |
| } |
| } |
| |
| // Verifies that the row named as |name| of the stats table |table_id| has |
| // the correct content as |name| : |value|. |
| void VerifyStatsTableRow(const string& table_id, |
| const string& name, |
| const string& value) { |
| VerifyElementWithId(table_id + "-" + name); |
| |
| string result; |
| ASSERT_TRUE(ExecuteScriptAndExtractString( |
| shell()->web_contents(), |
| "var row = $('" + table_id + "-" + name + "');" |
| "var name = row.cells[0].textContent;" |
| "var value = row.cells[1].textContent;" |
| "window.domAutomationController.send(name + ':' + value)", |
| &result)); |
| EXPECT_EQ(name + ":" + value, result); |
| } |
| |
| // Verifies that the graph data series consistent with pc.stats_. |
| void VerifyStatsGraph(const PeerConnectionEntry& pc) { |
| std::map<string, StatsMap>::const_iterator stream_iter; |
| for (stream_iter = pc.stats_.begin(); |
| stream_iter != pc.stats_.end(); stream_iter++) { |
| StatsMap::const_iterator stats_iter; |
| for (stats_iter = stream_iter->second.begin(); |
| stats_iter != stream_iter->second.end(); |
| stats_iter++) { |
| string graph_id = stream_iter->first + "-" + stats_iter->first; |
| for (size_t i = 0; i < stats_iter->second.size(); ++i) { |
| float number; |
| std::stringstream stream(stats_iter->second[i]); |
| stream >> number; |
| if (stream.fail()) |
| continue; |
| VerifyGraphDataPoint( |
| pc.getIdString(), graph_id, i, stats_iter->second[i]); |
| } |
| } |
| } |
| } |
| |
| // Verifies that the graph data point at index |index| has value |value|. |
| void VerifyGraphDataPoint(const string& pc_id, const string& graph_id, |
| int index, const string& value) { |
| bool result = false; |
| ASSERT_TRUE(ExecuteScriptAndExtractBool( |
| shell()->web_contents(), |
| "window.domAutomationController.send(" |
| "graphViews['" + pc_id + "-" + graph_id + "'] != null)", |
| &result)); |
| EXPECT_TRUE(result); |
| |
| std::stringstream ss; |
| ss << "var dp = peerConnectionDataStore['" << pc_id << "']" |
| ".getDataSeries('" << graph_id << "').dataPoints_[" << index << "];" |
| "window.domAutomationController.send(dp.value.toString())"; |
| string actual_value; |
| ASSERT_TRUE(ExecuteScriptAndExtractString( |
| shell()->web_contents(), ss.str(), &actual_value)); |
| EXPECT_EQ(value, actual_value); |
| } |
| |
| // Get the JSON string of the ssrc info from the page. |
| string GetSsrcInfo(const string& ssrc_id) { |
| string result; |
| EXPECT_TRUE(ExecuteScriptAndExtractString( |
| shell()->web_contents(), |
| "window.domAutomationController.send(JSON.stringify(" |
| "ssrcInfoManager.streamInfoContainer_['" + ssrc_id + "']))", |
| &result)); |
| return result; |
| } |
| |
| int GetSsrcInfoBlockCount(Shell* shell) { |
| int count = 0; |
| EXPECT_TRUE(ExecuteScriptAndExtractInt( |
| shell->web_contents(), |
| "window.domAutomationController.send(" |
| "document.getElementsByClassName(" |
| "ssrcInfoManager.SSRC_INFO_BLOCK_CLASS).length);", |
| &count)); |
| return count; |
| } |
| |
| // Verifies |dump| contains |peer_connection_number| peer connection dumps, |
| // each containing |update_number| updates and |stats_number| stats tables. |
| void VerifyPageDumpStructure(base::Value* dump, |
| int peer_connection_number, |
| int update_number, |
| int stats_number) { |
| EXPECT_NE((base::Value*)NULL, dump); |
| EXPECT_EQ(base::Value::TYPE_DICTIONARY, dump->GetType()); |
| |
| base::DictionaryValue* dict_dump = |
| static_cast<base::DictionaryValue*>(dump); |
| EXPECT_EQ((size_t) peer_connection_number, dict_dump->size()); |
| |
| base::DictionaryValue::Iterator it(*dict_dump); |
| for (; !it.IsAtEnd(); it.Advance()) { |
| base::Value* value = NULL; |
| dict_dump->Get(it.key(), &value); |
| EXPECT_EQ(base::Value::TYPE_DICTIONARY, value->GetType()); |
| base::DictionaryValue* pc_dump = |
| static_cast<base::DictionaryValue*>(value); |
| EXPECT_TRUE(pc_dump->HasKey("updateLog")); |
| EXPECT_TRUE(pc_dump->HasKey("stats")); |
| |
| // Verifies the number of updates. |
| pc_dump->Get("updateLog", &value); |
| EXPECT_EQ(base::Value::TYPE_LIST, value->GetType()); |
| base::ListValue* list = static_cast<base::ListValue*>(value); |
| EXPECT_EQ((size_t) update_number, list->GetSize()); |
| |
| // Verifies the number of stats tables. |
| pc_dump->Get("stats", &value); |
| EXPECT_EQ(base::Value::TYPE_DICTIONARY, value->GetType()); |
| base::DictionaryValue* dict = static_cast<base::DictionaryValue*>(value); |
| EXPECT_EQ((size_t) stats_number, dict->size()); |
| } |
| } |
| |
| // Verifies |dump| contains the correct statsTable and statsDataSeries for |
| // |pc|. |
| void VerifyStatsDump(base::Value* dump, |
| const PeerConnectionEntry& pc, |
| const string& report_type, |
| const string& report_id, |
| const StatsUnit& stats) { |
| EXPECT_NE((base::Value*)NULL, dump); |
| EXPECT_EQ(base::Value::TYPE_DICTIONARY, dump->GetType()); |
| |
| base::DictionaryValue* dict_dump = |
| static_cast<base::DictionaryValue*>(dump); |
| base::Value* value = NULL; |
| dict_dump->Get(pc.getIdString(), &value); |
| base::DictionaryValue* pc_dump = static_cast<base::DictionaryValue*>(value); |
| |
| // Verifies there is one data series per stats name. |
| value = NULL; |
| pc_dump->Get("stats", &value); |
| EXPECT_EQ(base::Value::TYPE_DICTIONARY, value->GetType()); |
| |
| base::DictionaryValue* dataSeries = |
| static_cast<base::DictionaryValue*>(value); |
| EXPECT_EQ(stats.values.size(), dataSeries->size()); |
| } |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest, |
| AddAndRemovePeerConnection) { |
| GURL url("chrome://webrtc-internals"); |
| NavigateToURL(shell(), url); |
| |
| // Add two PeerConnections and then remove them. |
| PeerConnectionEntry pc_1(1, 0); |
| ExecuteAddPeerConnectionJs(pc_1); |
| VerifyPeerConnectionEntry(pc_1); |
| |
| PeerConnectionEntry pc_2(2, 1); |
| ExecuteAddPeerConnectionJs(pc_2); |
| VerifyPeerConnectionEntry(pc_2); |
| |
| ExecuteRemovePeerConnectionJs(pc_1); |
| VerifyNoElementWithId(pc_1.getIdString()); |
| VerifyPeerConnectionEntry(pc_2); |
| |
| ExecuteRemovePeerConnectionJs(pc_2); |
| VerifyNoElementWithId(pc_2.getIdString()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest, |
| UpdateAllPeerConnections) { |
| GURL url("chrome://webrtc-internals"); |
| NavigateToURL(shell(), url); |
| |
| PeerConnectionEntry pc_0(1, 0); |
| pc_0.AddEvent("e1", "v1"); |
| pc_0.AddEvent("e2", "v2"); |
| PeerConnectionEntry pc_1(1, 1); |
| pc_1.AddEvent("e3", "v3"); |
| pc_1.AddEvent("e4", "v4"); |
| string pc_array = "[" + pc_0.getAllUpdateString() + ", " + |
| pc_1.getAllUpdateString() + "]"; |
| EXPECT_TRUE(ExecuteJavascript("updateAllPeerConnections(" + pc_array + ");")); |
| VerifyPeerConnectionEntry(pc_0); |
| VerifyPeerConnectionEntry(pc_1); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest, UpdatePeerConnection) { |
| GURL url("chrome://webrtc-internals"); |
| NavigateToURL(shell(), url); |
| |
| // Add one PeerConnection and send one update. |
| PeerConnectionEntry pc_1(1, 0); |
| ExecuteAddPeerConnectionJs(pc_1); |
| |
| ExecuteAndVerifyUpdatePeerConnection(pc_1, "e1", "v1"); |
| |
| // Add another PeerConnection and send two updates. |
| PeerConnectionEntry pc_2(1, 1); |
| ExecuteAddPeerConnectionJs(pc_2); |
| |
| SsrcEntry ssrc1, ssrc2; |
| ssrc1.id = "ssrcid1"; |
| ssrc1.properties["msid"] = "mymsid"; |
| ssrc2.id = "ssrcid2"; |
| ssrc2.properties["label"] = "mylabel"; |
| ssrc2.properties["cname"] = "mycname"; |
| |
| ExecuteAndVerifyUpdatePeerConnection(pc_2, "setRemoteDescription", |
| ssrc1.GetSsrcAttributeString()); |
| |
| ExecuteAndVerifyUpdatePeerConnection(pc_2, "setLocalDescription", |
| ssrc2.GetSsrcAttributeString()); |
| |
| EXPECT_EQ(ssrc1.GetAsJSON(), GetSsrcInfo(ssrc1.id)); |
| EXPECT_EQ(ssrc2.GetAsJSON(), GetSsrcInfo(ssrc2.id)); |
| |
| StatsUnit stats = {FAKE_TIME_STAMP}; |
| stats.values["ssrc"] = ssrc1.id; |
| ExecuteAndVerifyAddStats(pc_2, "ssrc", "dummyId", stats); |
| EXPECT_GT(GetSsrcInfoBlockCount(shell()), 0); |
| } |
| |
| // Tests that adding random named stats updates the dataSeries and graphs. |
| IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest, AddStats) { |
| GURL url("chrome://webrtc-internals"); |
| NavigateToURL(shell(), url); |
| |
| PeerConnectionEntry pc(1, 0); |
| ExecuteAddPeerConnectionJs(pc); |
| |
| const string type = "ssrc"; |
| const string id = "ssrc-1234"; |
| StatsUnit stats = {FAKE_TIME_STAMP}; |
| stats.values["trackId"] = "abcd"; |
| stats.values["bitrate"] = "2000"; |
| stats.values["framerate"] = "30"; |
| |
| // Add new stats and verify the stats table and graphs. |
| ExecuteAndVerifyAddStats(pc, type, id, stats); |
| VerifyStatsGraph(pc); |
| |
| // Update existing stats and verify the stats table and graphs. |
| stats.values["bitrate"] = "2001"; |
| stats.values["framerate"] = "31"; |
| ExecuteAndVerifyAddStats(pc, type, id, stats); |
| VerifyStatsGraph(pc); |
| } |
| |
| // Tests that the bandwidth estimation values are drawn on a single graph. |
| IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest, BweCompoundGraph) { |
| GURL url("chrome://webrtc-internals"); |
| NavigateToURL(shell(), url); |
| |
| PeerConnectionEntry pc(1, 0); |
| ExecuteAddPeerConnectionJs(pc); |
| |
| StatsUnit stats = {FAKE_TIME_STAMP}; |
| stats.values["googAvailableSendBandwidth"] = "1000000"; |
| stats.values["googTargetEncBitrate"] = "1000"; |
| stats.values["googActualEncBitrate"] = "1000000"; |
| stats.values["googRetransmitBitrate"] = "10"; |
| stats.values["googTransmitBitrate"] = "1000000"; |
| const string stats_type = "bwe"; |
| const string stats_id = "videobwe"; |
| ExecuteAndVerifyAddStats(pc, stats_type, stats_id, stats); |
| |
| string graph_id = |
| pc.getIdString() + "-" + stats_id + "-bweCompound"; |
| bool result = false; |
| // Verify that the bweCompound graph exists. |
| ASSERT_TRUE(ExecuteScriptAndExtractBool( |
| shell()->web_contents(), |
| "window.domAutomationController.send(" |
| " graphViews['" + graph_id + "'] != null)", |
| &result)); |
| EXPECT_TRUE(result); |
| |
| // Verify that the bweCompound graph contains multiple dataSeries. |
| int count = 0; |
| ASSERT_TRUE(ExecuteScriptAndExtractInt( |
| shell()->web_contents(), |
| "window.domAutomationController.send(" |
| " graphViews['" + graph_id + "'].getDataSeriesCount())", |
| &count)); |
| EXPECT_EQ((int)stats.values.size(), count); |
| } |
| |
| // Tests that the total packet/byte count is converted to count per second, |
| // and the converted data is drawn. |
| IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest, ConvertedGraphs) { |
| GURL url("chrome://webrtc-internals"); |
| NavigateToURL(shell(), url); |
| |
| PeerConnectionEntry pc(1, 0); |
| ExecuteAddPeerConnectionJs(pc); |
| |
| const string stats_type = "s"; |
| const string stats_id = "1"; |
| const int num_converted_stats = 4; |
| const string stats_names[] = |
| {"packetsSent", "bytesSent", "packetsReceived", "bytesReceived"}; |
| const string converted_names[] = |
| {"packetsSentPerSecond", "bitsSentPerSecond", |
| "packetsReceivedPerSecond", "bitsReceivedPerSecond"}; |
| const string first_value = "1000"; |
| const string second_value = "2000"; |
| const string converted_values[] = {"1000", "8000", "1000", "8000"}; |
| |
| // Send the first data point. |
| StatsUnit stats = {FAKE_TIME_STAMP}; |
| for (int i = 0; i < num_converted_stats; ++i) |
| stats.values[stats_names[i]] = first_value; |
| |
| ExecuteAndVerifyAddStats(pc, stats_type, stats_id, stats); |
| |
| // Send the second data point at 1000ms after the first data point. |
| stats.timestamp += 1000; |
| for (int i = 0; i < num_converted_stats; ++i) |
| stats.values[stats_names[i]] = second_value; |
| ExecuteAndVerifyAddStats(pc, stats_type, stats_id, stats); |
| |
| // Verifies the graph data matches converted_values. |
| for (int i = 0; i < num_converted_stats; ++i) { |
| VerifyGraphDataPoint(pc.getIdString(), stats_id + "-" + converted_names[i], |
| 1, converted_values[i]); |
| } |
| } |
| |
| // Timing out on ARM linux bot: http://crbug.com/238490 |
| // Disabling due to failure on Linux, Mac, Win: http://crbug.com/272413 |
| // Sanity check of the page content under a real PeerConnection call. |
| IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest, |
| DISABLED_WithRealPeerConnectionCall) { |
| // Start a peerconnection call in the first window. |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| GURL url(embedded_test_server()->GetURL("/media/peerconnection-call.html")); |
| NavigateToURL(shell(), url); |
| ASSERT_TRUE(ExecuteJavascript("call({video:true});")); |
| ExpectTitle("OK"); |
| |
| // Open webrtc-internals in the second window. |
| GURL url2("chrome://webrtc-internals"); |
| Shell* shell2 = CreateBrowser(); |
| NavigateToURL(shell2, url2); |
| |
| const int NUMBER_OF_PEER_CONNECTIONS = 2; |
| |
| // Verifies the number of peerconnections. |
| int count = 0; |
| ASSERT_TRUE(ExecuteScriptAndExtractInt( |
| shell2->web_contents(), |
| "window.domAutomationController.send(" |
| "$('peer-connections-list').getElementsByTagName('li').length);", |
| &count)); |
| EXPECT_EQ(NUMBER_OF_PEER_CONNECTIONS, count); |
| |
| // Verifies the the event tables. |
| ASSERT_TRUE(ExecuteScriptAndExtractInt( |
| shell2->web_contents(), |
| "window.domAutomationController.send($('peer-connections-list')" |
| ".getElementsByClassName('update-log-table').length);", |
| &count)); |
| EXPECT_EQ(NUMBER_OF_PEER_CONNECTIONS, count); |
| |
| ASSERT_TRUE(ExecuteScriptAndExtractInt( |
| shell2->web_contents(), |
| "window.domAutomationController.send($('peer-connections-list')" |
| ".getElementsByClassName('update-log-table')[0].rows.length);", |
| &count)); |
| EXPECT_GT(count, 1); |
| |
| ASSERT_TRUE(ExecuteScriptAndExtractInt( |
| shell2->web_contents(), |
| "window.domAutomationController.send($('peer-connections-list')" |
| ".getElementsByClassName('update-log-table')[1].rows.length);", |
| &count)); |
| EXPECT_GT(count, 1); |
| |
| // Wait until the stats table containers are created. |
| count = 0; |
| while (count != NUMBER_OF_PEER_CONNECTIONS) { |
| ASSERT_TRUE(ExecuteScriptAndExtractInt( |
| shell2->web_contents(), |
| "window.domAutomationController.send(" |
| "$('peer-connections-list').getElementsByClassName(" |
| "'stats-table-container').length);", |
| &count)); |
| } |
| |
| // Verifies each stats table having more than one rows. |
| bool result = false; |
| ASSERT_TRUE(ExecuteScriptAndExtractBool( |
| shell2->web_contents(), |
| "var tableContainers = $('peer-connections-list')" |
| ".getElementsByClassName('stats-table-container');" |
| "var result = true;" |
| "for (var i = 0; i < tableContainers.length && result; ++i) {" |
| "var tables = tableContainers[i].getElementsByTagName('table');" |
| "for (var j = 0; j < tables.length && result; ++j) {" |
| "result = (tables[j].rows.length > 1);" |
| "}" |
| "if (!result) {" |
| "console.log(tableContainers[i].innerHTML);" |
| "}" |
| "}" |
| "window.domAutomationController.send(result);", |
| &result)); |
| |
| EXPECT_TRUE(result); |
| |
| count = GetSsrcInfoBlockCount(shell2); |
| EXPECT_GT(count, 0); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest, CreatePageDump) { |
| GURL url("chrome://webrtc-internals"); |
| NavigateToURL(shell(), url); |
| |
| PeerConnectionEntry pc_0(1, 0); |
| pc_0.AddEvent("e1", "v1"); |
| pc_0.AddEvent("e2", "v2"); |
| PeerConnectionEntry pc_1(1, 1); |
| pc_1.AddEvent("e3", "v3"); |
| pc_1.AddEvent("e4", "v4"); |
| string pc_array = |
| "[" + pc_0.getAllUpdateString() + ", " + pc_1.getAllUpdateString() + "]"; |
| EXPECT_TRUE(ExecuteJavascript("updateAllPeerConnections(" + pc_array + ");")); |
| |
| // Verifies the peer connection data store can be created without stats. |
| string dump_json; |
| ASSERT_TRUE(ExecuteScriptAndExtractString( |
| shell()->web_contents(), |
| "window.domAutomationController.send(" |
| "JSON.stringify(peerConnectionDataStore));", |
| &dump_json)); |
| scoped_ptr<base::Value> dump = base::JSONReader::Read(dump_json); |
| VerifyPageDumpStructure(dump.get(), |
| 2 /*peer_connection_number*/, |
| 2 /*update_number*/, |
| 0 /*stats_number*/); |
| |
| // Adds a stats report. |
| const string type = "dummy"; |
| const string id = "1234"; |
| StatsUnit stats = { FAKE_TIME_STAMP }; |
| stats.values["bitrate"] = "2000"; |
| stats.values["framerate"] = "30"; |
| ExecuteAndVerifyAddStats(pc_0, type, id, stats); |
| |
| ASSERT_TRUE(ExecuteScriptAndExtractString( |
| shell()->web_contents(), |
| "window.domAutomationController.send(" |
| "JSON.stringify(peerConnectionDataStore));", |
| &dump_json)); |
| dump = base::JSONReader::Read(dump_json); |
| VerifyStatsDump(dump.get(), pc_0, type, id, stats); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest, UpdateGetUserMedia) { |
| GURL url("chrome://webrtc-internals"); |
| NavigateToURL(shell(), url); |
| |
| UserMediaRequestEntry request1(1, 1, "origin", "ac", "vc"); |
| UserMediaRequestEntry request2(2, 2, "origin2", "ac2", "vc2"); |
| ExecuteAddGetUserMediaJs(request1); |
| ExecuteAddGetUserMediaJs(request2); |
| |
| std::vector<UserMediaRequestEntry> list; |
| list.push_back(request1); |
| list.push_back(request2); |
| VerifyUserMediaRequest(list); |
| |
| ExecuteRemoveGetUserMediaForRendererJs(1); |
| list.erase(list.begin()); |
| VerifyUserMediaRequest(list); |
| |
| ExecuteRemoveGetUserMediaForRendererJs(2); |
| list.erase(list.begin()); |
| VerifyUserMediaRequest(list); |
| } |
| |
| // Tests that the received propagation delta values are converted and drawn |
| // correctly. |
| IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest, |
| ReceivedPropagationDelta) { |
| GURL url("chrome://webrtc-internals"); |
| NavigateToURL(shell(), url); |
| |
| PeerConnectionEntry pc(1, 0); |
| ExecuteAddPeerConnectionJs(pc); |
| |
| StatsUnit stats = {FAKE_TIME_STAMP}; |
| stats.values["googReceivedPacketGroupArrivalTimeDebug"] = |
| "[1000, 1100, 1200]"; |
| stats.values["googReceivedPacketGroupPropagationDeltaDebug"] = |
| "[10, 20, 30]"; |
| const string stats_type = "bwe"; |
| const string stats_id = "videobwe"; |
| ExecuteAndVerifyAddStats(pc, stats_type, stats_id, stats); |
| |
| string graph_id = pc.getIdString() + "-" + stats_id + |
| "-googReceivedPacketGroupPropagationDeltaDebug"; |
| string data_series_id = |
| stats_id + "-googReceivedPacketGroupPropagationDeltaDebug"; |
| bool result = false; |
| // Verify that the graph exists. |
| ASSERT_TRUE(ExecuteScriptAndExtractBool( |
| shell()->web_contents(), |
| "window.domAutomationController.send(" |
| " graphViews['" + graph_id + "'] != null)", |
| &result)); |
| EXPECT_TRUE(result); |
| |
| // Verify that the graph contains multiple data points. |
| int count = 0; |
| ASSERT_TRUE(ExecuteScriptAndExtractInt( |
| shell()->web_contents(), |
| "window.domAutomationController.send(" |
| " graphViews['" + graph_id + "'].getDataSeriesCount())", |
| &count)); |
| EXPECT_EQ(1, count); |
| ASSERT_TRUE(ExecuteScriptAndExtractInt( |
| shell()->web_contents(), |
| "window.domAutomationController.send(" |
| " peerConnectionDataStore['" + pc.getIdString() + "']" + |
| " .getDataSeries('" + data_series_id + "').getCount())", |
| &count)); |
| EXPECT_EQ(3, count); |
| } |
| |
| } // namespace content |