blob: 517a5b0fe573f6e2077d1d1581078bb284584bc4 [file] [log] [blame]
# Copyright 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.
import unittest
from telemetry.testing import simple_mock
from metrics import webrtc_stats
SAMPLE_JSON = '''
[[
[
{
"googFrameHeightInput":"480",
"googFrameWidthInput":"640",
"googFrameRateSent": "23",
"packetsLost":"-1",
"googRtt":"19",
"packetsSent":"1",
"bytesSent":"0"
},
{
"audioInputLevel":"2048",
"googRtt":"20",
"googCodecName":"opus",
"packetsSent":"4",
"bytesSent":"0"
}
],
[
{
"googFrameHeightInput":"480",
"googFrameWidthInput":"640",
"googFrameRateSent": "21",
"packetsLost":"-1",
"googRtt":"18",
"packetsSent":"8",
"bytesSent":"6291"
},
{
"audioInputLevel":"1878",
"googRtt":"17",
"googCodecName":"opus",
"packetsSent":"16",
"bytesSent":"634"
}
],
[
{
"googAvailableSendBandwidth":"30000",
"googAvailableRecvBandwidth":"12345",
"googTargetEncBitrate":"10000"
}
]
],
[
[
{
"googFrameRateReceived": "23",
"googDecodeMs":"0",
"packetsReceived":"8",
"googRenderDelayMs":"10",
"googMaxDecodeMs":"0",
"googRtt":"100"
}
],
[
{
"googFrameRateReceived": "23",
"googDecodeMs":"14",
"packetsReceived":"1234",
"googRenderDelayMs":"102",
"googMaxDecodeMs":"150",
"googRtt":"101"
}
],
[
{
"googAvailableSendBandwidth":"40000",
"googAvailableRecvBandwidth":"22345",
"googTargetEncBitrate":"20000"
}
]
]]
'''
class FakeResults(object):
def __init__(self, current_page):
self._received_values = []
self._current_page = current_page
@property
def received_values(self):
return self._received_values
@property
def current_page(self):
return self._current_page
def AddValue(self, value):
self._received_values.append(value)
class WebRtcStatsUnittest(unittest.TestCase):
def _RunMetricOnJson(self, json_to_return):
stats_metric = webrtc_stats.WebRtcStatisticsMetric()
tab = simple_mock.MockObject()
page = simple_mock.MockObject()
stats_metric.Start(page, tab)
tab.ExpectCall('EvaluateJavaScript',
simple_mock.DONT_CARE).WillReturn(json_to_return)
stats_metric.Stop(page, tab)
page.url = simple_mock.MockObject()
results = FakeResults(page)
stats_metric.AddResults(tab, results)
return results
def testExtractsValuesAsTimeSeries(self):
results = self._RunMetricOnJson(SAMPLE_JSON)
self.assertTrue(results.received_values,
'Expected values for googDecodeMs and others, got none.')
# This also ensures we're clever enough to tell video packetsSent from audio
# packetsSent.
self.assertEqual(results.received_values[3].values,
[4.0, 16.0])
self.assertEqual(results.received_values[5].values,
[1.0, 8.0])
def testExtractsInterestingMetricsOnly(self):
results = self._RunMetricOnJson(SAMPLE_JSON)
self.assertTrue(len(results.received_values) > 0)
self.assertIn('peer_connection_0', results.received_values[0].name,
'The result should be a ListOfScalarValues instance with '
'a name <peer connection id>_<statistic>.')
all_names = [value.name for value in results.received_values]
self.assertIn('peer_connection_0_video_packets_sent', all_names)
self.assertNotIn('peer_connection_1_video_packets_sent', all_names,
'Peer connection 1 does not have a video packets sent in '
'the JSON above, unlike peer connection 0 which does.')
self.assertIn('peer_connection_0_video_goog_rtt', all_names)
self.assertIn('peer_connection_1_video_goog_rtt', all_names)
# The audio_audio is intentional since the code distinguishes audio reports
# from video reports (even though audio_input_level is quite obvious).
self.assertNotIn('peer_connection_0_audio_audio_input_level', all_names,
'Input level is in the JSON for both connections but '
'should not be reported since it is not interesting.')
self.assertNotIn('peer_connection_1_audio_audio_input_level', all_names)
def testReturnsIfJsonIsEmpty(self):
results = self._RunMetricOnJson('[]')
self.assertFalse(results.received_values)