# 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 _.') 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)