PageRenderTime 42ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/media/tools/constrained_network_server/cns_test.py

https://gitlab.com/jonnialva90/iridium-browser
Python | 265 lines | 141 code | 66 blank | 58 comment | 3 complexity | 738fc3c33b0e61f9a3fefd9f3b544632 MD5 | raw file
  1. #!/usr/bin/env python
  2. # Copyright (c) 2012 The Chromium Authors. All rights reserved.
  3. # Use of this source code is governed by a BSD-style license that can be
  4. # found in the LICENSE file.
  5. """Tests for Constrained Network Server."""
  6. import os
  7. import signal
  8. import subprocess
  9. import tempfile
  10. import time
  11. import unittest
  12. import urllib2
  13. import cherrypy
  14. import cns
  15. import traffic_control
  16. # The local interface to test on.
  17. _INTERFACE = 'lo'
  18. class PortAllocatorTest(unittest.TestCase):
  19. """Unit tests for the Port Allocator class."""
  20. # Expiration time for ports. In mock time.
  21. _EXPIRY_TIME = 6
  22. def setUp(self):
  23. # Mock out time.time() to accelerate port expiration testing.
  24. self._old_time = time.time
  25. self._current_time = 0
  26. time.time = lambda: self._current_time
  27. # TODO(dalecurtis): Mock out actual calls to shadi's port setup.
  28. self._pa = cns.PortAllocator(cns._DEFAULT_CNS_PORT_RANGE, self._EXPIRY_TIME)
  29. self._MockTrafficControl()
  30. def tearDown(self):
  31. self._pa.Cleanup(all_ports=True)
  32. # Ensure ports are cleaned properly.
  33. self.assertEquals(self._pa._ports, {})
  34. time.time = self._old_time
  35. self._RestoreTrafficControl()
  36. def _MockTrafficControl(self):
  37. self.old_CreateConstrainedPort = traffic_control.CreateConstrainedPort
  38. self.old_DeleteConstrainedPort = traffic_control.DeleteConstrainedPort
  39. self.old_TearDown = traffic_control.TearDown
  40. traffic_control.CreateConstrainedPort = lambda config: True
  41. traffic_control.DeleteConstrainedPort = lambda config: True
  42. traffic_control.TearDown = lambda config: True
  43. def _RestoreTrafficControl(self):
  44. traffic_control.CreateConstrainedPort = self.old_CreateConstrainedPort
  45. traffic_control.DeleteConstrainedPort = self.old_DeleteConstrainedPort
  46. traffic_control.TearDown = self.old_TearDown
  47. def testPortAllocator(self):
  48. # Ensure Get() succeeds and returns the correct port.
  49. self.assertEquals(self._pa.Get('test'), cns._DEFAULT_CNS_PORT_RANGE[0])
  50. # Call again with the same key and make sure we get the same port.
  51. self.assertEquals(self._pa.Get('test'), cns._DEFAULT_CNS_PORT_RANGE[0])
  52. # Call with a different key and make sure we get a different port.
  53. self.assertEquals(self._pa.Get('test2'), cns._DEFAULT_CNS_PORT_RANGE[0] + 1)
  54. # Update fake time so that ports should expire.
  55. self._current_time += self._EXPIRY_TIME + 1
  56. # Test to make sure cache is checked before expiring ports.
  57. self.assertEquals(self._pa.Get('test2'), cns._DEFAULT_CNS_PORT_RANGE[0] + 1)
  58. # Update fake time so that ports should expire.
  59. self._current_time += self._EXPIRY_TIME + 1
  60. # Request a new port, old ports should be expired, so we should get the
  61. # first port in the range. Make sure this is the only allocated port.
  62. self.assertEquals(self._pa.Get('test3'), cns._DEFAULT_CNS_PORT_RANGE[0])
  63. self.assertEquals(self._pa._ports.keys(), [cns._DEFAULT_CNS_PORT_RANGE[0]])
  64. def testPortAllocatorExpiresOnlyCorrectPorts(self):
  65. # Ensure Get() succeeds and returns the correct port.
  66. self.assertEquals(self._pa.Get('test'), cns._DEFAULT_CNS_PORT_RANGE[0])
  67. # Stagger port allocation and so we can ensure only ports older than the
  68. # expiry time are actually expired.
  69. self._current_time += self._EXPIRY_TIME / 2 + 1
  70. # Call with a different key and make sure we get a different port.
  71. self.assertEquals(self._pa.Get('test2'), cns._DEFAULT_CNS_PORT_RANGE[0] + 1)
  72. # After this sleep the port with key 'test' should expire on the next Get().
  73. self._current_time += self._EXPIRY_TIME / 2 + 1
  74. # Call with a different key and make sure we get the first port.
  75. self.assertEquals(self._pa.Get('test3'), cns._DEFAULT_CNS_PORT_RANGE[0])
  76. self.assertEquals(set(self._pa._ports.keys()), set([
  77. cns._DEFAULT_CNS_PORT_RANGE[0], cns._DEFAULT_CNS_PORT_RANGE[0] + 1]))
  78. def testPortAllocatorNoExpiration(self):
  79. # Setup PortAllocator w/o port expiration.
  80. self._pa = cns.PortAllocator(cns._DEFAULT_CNS_PORT_RANGE, 0)
  81. # Ensure Get() succeeds and returns the correct port.
  82. self.assertEquals(self._pa.Get('test'), cns._DEFAULT_CNS_PORT_RANGE[0])
  83. # Update fake time to see if ports expire.
  84. self._current_time += self._EXPIRY_TIME
  85. # Send second Get() which would normally cause ports to expire. Ensure that
  86. # the ports did not expire.
  87. self.assertEquals(self._pa.Get('test2'), cns._DEFAULT_CNS_PORT_RANGE[0] + 1)
  88. self.assertEquals(set(self._pa._ports.keys()), set([
  89. cns._DEFAULT_CNS_PORT_RANGE[0], cns._DEFAULT_CNS_PORT_RANGE[0] + 1]))
  90. def testPortAllocatorCleanMatchingIP(self):
  91. # Setup PortAllocator w/o port expiration.
  92. self._pa = cns.PortAllocator(cns._DEFAULT_CNS_PORT_RANGE, 0)
  93. # Ensure Get() succeeds and returns the correct port.
  94. self.assertEquals(self._pa.Get('ip1', t=1), cns._DEFAULT_CNS_PORT_RANGE[0])
  95. self.assertEquals(self._pa.Get('ip1', t=2),
  96. cns._DEFAULT_CNS_PORT_RANGE[0] + 1)
  97. self.assertEquals(self._pa.Get('ip1', t=3),
  98. cns._DEFAULT_CNS_PORT_RANGE[0] + 2)
  99. self.assertEquals(self._pa.Get('ip2', t=1),
  100. cns._DEFAULT_CNS_PORT_RANGE[0] + 3)
  101. self._pa.Cleanup(all_ports=False, request_ip='ip1')
  102. self.assertEquals(self._pa._ports.keys(),
  103. [cns._DEFAULT_CNS_PORT_RANGE[0] + 3])
  104. self.assertEquals(self._pa.Get('ip2'), cns._DEFAULT_CNS_PORT_RANGE[0])
  105. self.assertEquals(self._pa.Get('ip1'), cns._DEFAULT_CNS_PORT_RANGE[0] + 1)
  106. self._pa.Cleanup(all_ports=False, request_ip='ip2')
  107. self.assertEquals(self._pa._ports.keys(),
  108. [cns._DEFAULT_CNS_PORT_RANGE[0] + 1])
  109. self._pa.Cleanup(all_ports=False, request_ip='abc')
  110. self.assertEquals(self._pa._ports.keys(),
  111. [cns._DEFAULT_CNS_PORT_RANGE[0] + 1])
  112. self._pa.Cleanup(all_ports=False, request_ip='ip1')
  113. self.assertEquals(self._pa._ports.keys(), [])
  114. class ConstrainedNetworkServerTest(unittest.TestCase):
  115. """End to end tests for ConstrainedNetworkServer system.
  116. These tests require root access and run the cherrypy server along with
  117. tc/iptables commands.
  118. """
  119. # Amount of time to wait for the CNS to start up.
  120. _SERVER_START_SLEEP_SECS = 1
  121. # Sample data used to verify file serving.
  122. _TEST_DATA = 'The quick brown fox jumps over the lazy dog'
  123. # Server information.
  124. _SERVER_URL = ('http://127.0.0.1:%d/ServeConstrained?' %
  125. cns._DEFAULT_SERVING_PORT)
  126. # Setting for latency testing.
  127. _LATENCY_TEST_SECS = 1
  128. def _StartServer(self):
  129. """Starts the CNS, returns pid."""
  130. cmd = ['python', 'cns.py', '--interface=%s' % _INTERFACE]
  131. process = subprocess.Popen(cmd, stderr=subprocess.PIPE)
  132. # Wait for server to startup.
  133. line = True
  134. while line:
  135. line = process.stderr.readline()
  136. if 'STARTED' in line:
  137. return process.pid
  138. self.fail('Failed to start CNS.')
  139. def setUp(self):
  140. # Start the CNS.
  141. self._server_pid = self._StartServer()
  142. # Create temp file for serving. Run after server start so if a failure
  143. # during setUp() occurs we don't leave junk files around.
  144. f, self._file = tempfile.mkstemp(dir=os.getcwd())
  145. os.write(f, self._TEST_DATA)
  146. os.close(f)
  147. # Strip cwd off so we have a proper relative path.
  148. self._relative_fn = self._file[len(os.getcwd()) + 1:]
  149. def tearDown(self):
  150. os.unlink(self._file)
  151. os.kill(self._server_pid, signal.SIGTERM)
  152. def testServerServesFiles(self):
  153. now = time.time()
  154. f = urllib2.urlopen('%sf=%s' % (self._SERVER_URL, self._relative_fn))
  155. # Verify file data is served correctly.
  156. self.assertEqual(self._TEST_DATA, f.read())
  157. # For completeness ensure an unconstrained call takes less time than our
  158. # artificial constraints checked in the tests below.
  159. self.assertTrue(time.time() - now < self._LATENCY_TEST_SECS)
  160. def testServerLatencyConstraint(self):
  161. """Tests serving a file with a latency network constraint."""
  162. # Abort if does not have root access.
  163. self.assertEqual(os.geteuid(), 0, 'You need root access to run this test.')
  164. now = time.time()
  165. base_url = '%sf=%s' % (self._SERVER_URL, self._relative_fn)
  166. url = '%s&latency=%d' % (base_url, self._LATENCY_TEST_SECS * 1000)
  167. f = urllib2.urlopen(url)
  168. # Verify file data is served correctly.
  169. self.assertEqual(self._TEST_DATA, f.read())
  170. # Verify the request took longer than the requested latency.
  171. self.assertTrue(time.time() - now > self._LATENCY_TEST_SECS)
  172. # Verify the server properly redirected the URL.
  173. self.assertTrue(f.geturl().startswith(base_url.replace(
  174. str(cns._DEFAULT_SERVING_PORT), str(cns._DEFAULT_CNS_PORT_RANGE[0]))))
  175. class ConstrainedNetworkServerUnitTests(unittest.TestCase):
  176. """ConstrainedNetworkServer class unit tests."""
  177. def testGetServerURL(self):
  178. """Test server URL is correct when using Cherrypy port."""
  179. cns_obj = cns.ConstrainedNetworkServer(self.DummyOptions(), None)
  180. self.assertEqual(cns_obj._GetServerURL('ab/xz.webm', port=1234, t=1),
  181. 'http://127.0.0.1:1234/ServeConstrained?f=ab/xz.webm&t=1')
  182. def testGetServerURLWithLocalServer(self):
  183. """Test server URL is correct when using --local-server-port port."""
  184. cns_obj = cns.ConstrainedNetworkServer(self.DummyOptionsWithServer(), None)
  185. self.assertEqual(cns_obj._GetServerURL('ab/xz.webm', port=1234, t=1),
  186. 'http://127.0.0.1:1234/media/ab/xz.webm?t=1')
  187. class DummyOptions(object):
  188. www_root = 'media'
  189. port = 9000
  190. cherrypy.url = lambda: 'http://127.0.0.1:9000/ServeConstrained'
  191. local_server_port = None
  192. class DummyOptionsWithServer(object):
  193. www_root = 'media'
  194. port = 9000
  195. cherrypy.url = lambda: 'http://127.0.0.1:9000/ServeConstrained'
  196. local_server_port = 8080
  197. if __name__ == '__main__':
  198. unittest.main()