# 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)
