- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / test / functional / media / cns_test_base.py
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 """Constrained network server (CNS) test base."""
6
7 import logging
8 import os
9 import Queue
10 import subprocess
11 import sys
12 import threading
13 import urllib2
14
15 import pyauto
16 import pyauto_paths
17
18
19 # List of commonly used network constraints settings.
20 # Each setting is a tuppe of the form:
21 #    ('TEST_NAME', [BANDWIDTH_Kbps, LATENCY_ms, PACKET_LOSS_%])
22 #
23 # Note: The test name should satisfy the regex [\w\.-]+ (check
24 # tools/perf_expectations/tests/perf_expectations_unittest.py for details). It
25 # is used to name the result graphs on the dashboards.
26 #
27 # The WiFi, DSL, and Cable settings were taken from webpagetest.org as
28 # approximations of their respective real world networks. The settings were
29 # based on 2011 FCC Broadband Data report (http://www.fcc.gov/document/
30 # measuring-broadband-america-report-consumer-broadband-performance-us).
31 DialUp = ('DialUp', [56, 120, 5])
32 Slow = ('Slow', [256, 105, 1])
33 Wifi = ('Wifi', [1024, 60, 0])
34 DSL = ('DSL', [1541, 50, 0])
35 Cable = ('Cable', [5120, 28, 0])
36 NoConstraints = ('NoConstraints', [0, 0, 0])
37
38 # Path to CNS executable relative to source root.
39 _CNS_PATH = os.path.join(
40     'media', 'tools', 'constrained_network_server', 'cns.py')
41
42 # Port to start the CNS on.
43 _CNS_PORT = 9000
44
45 # A flag to determine whether to launch a local CNS instance or to connect
46 # to the external CNS server.  Default to False since all current bots use an
47 # external instance.
48 # If not on Windows, set USE_LOCAL_CNS=1 env variable to switch the flag.
49 USE_LOCAL_CNS = ('win' not in sys.platform and 'USE_LOCAL_CNS' in os.environ and
50                  os.environ['USE_LOCAL_CNS'] == '1')
51
52 # Base CNS URL, only requires & separated parameter names appended.
53 if USE_LOCAL_CNS:
54   CNS_BASE_URL = 'http://127.0.0.1:%d/ServeConstrained?' % _CNS_PORT
55 else:
56   CNS_BASE_URL = 'http://chromeperf34:%d/ServeConstrained?' % _CNS_PORT
57   CNS_CLEANUP_URL = 'http://chromeperf34:%d/Cleanup' % _CNS_PORT
58
59 # Used for server sanity check.
60 _TEST_VIDEO = 'roller.webm'
61
62 # Directory root to serve files from.
63 _ROOT_PATH = os.path.join(pyauto.PyUITest.DataDir(), 'pyauto_private', 'media')
64
65
66 class CNSTestBase(pyauto.PyUITest):
67   """CNS test base hadles startup and teardown of CNS server."""
68
69   def __init__(self, *args, **kwargs):
70     """Initialize CNSTestBase by setting the arguments for CNS server.
71
72     Args:
73         Check cns.py command line argument list for details.
74     """
75     self._port = kwargs.get('port', _CNS_PORT)
76     self._interface = kwargs.get('interface', 'lo')
77     self._www_root = kwargs.get('www_root', _ROOT_PATH)
78     self._verbose = kwargs.get('verbose', True)
79     self._expiry_time = kwargs.get('expiry_time', 0)
80     self._socket_timeout = kwargs.get('socket_timeout')
81     pyauto.PyUITest.__init__(self, *args, **kwargs)
82
83   def setUp(self):
84     """Ensures the Constrained Network Server (CNS) server is up and running."""
85     if USE_LOCAL_CNS:
86       self._SetUpLocal()
87     else:
88       self._SetUpExternal()
89
90   def _SetUpExternal(self):
91     """Ensures the test can connect to the external CNS server."""
92     if self.WaitUntil(self._CanAccessServer, retry_sleep=3, timeout=30,
93                       debug=False):
94       pyauto.PyUITest.setUp(self)
95     else:
96       self.fail('Failed to connect to CNS.')
97
98   def _SetUpLocal(self):
99     """Starts the CNS server locally."""
100     cmd = [sys.executable, os.path.join(pyauto_paths.GetSourceDir(), _CNS_PATH),
101            '--port', str(self._port),
102            '--interface', self._interface,
103            '--www-root', self._www_root,
104            '--expiry-time', str(self._expiry_time)]
105
106     if self._socket_timeout:
107       cmd.extend(['--socket-timeout', str(self._socket_timeout)])
108     if self._verbose:
109       cmd.append('-v')
110     logging.debug('Starting CNS server: %s ', ' '.join(cmd))
111
112     self._cns_process = subprocess.Popen(cmd, stderr=subprocess.PIPE)
113     ProcessLogger(self._cns_process)
114
115     if self.WaitUntil(self._CanAccessServer, retry_sleep=3, timeout=30,
116                       debug=False):
117       pyauto.PyUITest.setUp(self)
118     else:
119       self.tearDown()
120       self.fail('Failed to start CNS.')
121
122   def _CanAccessServer(self):
123     """Checks if the CNS server can serve a file with no network constraints."""
124     test_url = ''.join([CNS_BASE_URL, 'f=', _TEST_VIDEO])
125     try:
126       return urllib2.urlopen(test_url) is not None
127     except Exception:
128       return False
129
130   def tearDown(self):
131     """Stops the Constrained Network Server (CNS)."""
132     if USE_LOCAL_CNS:
133       logging.debug('Stopping CNS server.')
134       # Do not use process.kill(), it will not clean up cns.
135       self.Kill(self._cns_process.pid)
136       # Need to wait since the process logger has a lock on the process stderr.
137       self._cns_process.wait()
138       self.assertFalse(self._cns_process.returncode is None)
139       logging.debug('CNS server stopped.')
140     else:
141       # Call CNS Cleanup to remove all ports created by this client.
142       self.NavigateToURL(CNS_CLEANUP_URL)
143     pyauto.PyUITest.tearDown(self)
144
145
146 class ProcessLogger(threading.Thread):
147   """A thread to log a process's stderr output."""
148
149   def __init__(self, process):
150     """Starts the process logger thread.
151
152     Args:
153       process: The process to log.
154     """
155     threading.Thread.__init__(self)
156     self._process = process
157     self.start()
158
159   def run(self):
160     """Adds debug statements for the process's stderr output."""
161     line = True
162     while line:
163       line = self._process.stderr.readline()
164       logging.debug(line.strip())
165
166
167 def GetFileURL(file_name, bandwidth=0, latency=0, loss=0, new_port=False):
168   """Returns CNS URL for the file with specified constraints.
169
170   Args:
171     Check cns.ServeConstrained() args for more details.
172   """
173   video_url = [CNS_BASE_URL, 'f=' + file_name]
174   if bandwidth > 0:
175     video_url.append('bandwidth=%d' % bandwidth)
176   if latency > 0:
177     video_url.append('latency=%d' % latency)
178   if loss > 0:
179     video_url.append('loss=%d' % loss)
180   if new_port:
181     video_url.append('new_port=%s' % new_port)
182   return '&'.join(video_url)
183
184
185 def CreateCNSPerfTasks(network_constraints_settings, test_media_files):
186   """Returns a queue of tasks combinining network constrains with media files.
187
188   Args:
189     network_constraints_settings: List of (setting_name, setting_values)
190         tupples.
191     test_media_files: List of media files to run the tests on.
192   """
193   # Convert relative test path into an absolute path.
194   tasks = Queue.Queue()
195   for file_name in test_media_files:
196     for series_name, settings in network_constraints_settings:
197       logging.debug('Add test: %s\tSettings: %s\tMedia: %s', series_name,
198                     settings, file_name)
199       tasks.put((series_name, settings, file_name))
200
201   return tasks