Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(231)

Side by Side Diff: Tools/Scripts/webkitpy/thirdparty/webpagereplay/trafficshaper_test.py

Issue 18418010: Check in the thirdparty libs needed for webkitpy. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright 2011 Google Inc. All Rights Reserved.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 """System integration test for traffic shaping.
17
18 Usage:
19 $ sudo ./trafficshaper_test.py
20 """
21
22 import daemonserver
23 import logging
24 import multiprocessing
25 import platformsettings
26 import socket
27 import SocketServer
28 import trafficshaper
29 import unittest
30
31
32 RESPONSE_SIZE_KEY = 'response-size:'
33 TEST_DNS_PORT = 5555
34 TEST_HTTP_PORT = 8888
35 TIMER = platformsettings.get_platform_settings().timer
36
37
38 def GetElapsedMs(start_time, end_time):
39 """Return milliseconds elapsed between |start_time| and |end_time|.
40
41 Args:
42 start_time: seconds as a float (or string representation of float).
43 end_time: seconds as a float (or string representation of float).
44 Return:
45 milliseconds elapsed as integer.
46 """
47 return int((float(end_time) - float(start_time)) * 1000)
48
49
50 class TrafficShaperTest(unittest.TestCase):
51
52 def testBadBandwidthRaises(self):
53 self.assertRaises(trafficshaper.BandwidthValueError,
54 trafficshaper.TrafficShaper,
55 down_bandwidth='1KBit/s')
56
57
58 class TimedUdpHandler(SocketServer.DatagramRequestHandler):
59 """UDP handler that returns the time when the request was handled."""
60
61 def handle(self):
62 data = self.rfile.read()
63 read_time = self.server.timer()
64 self.wfile.write(str(read_time))
65
66
67 class TimedTcpHandler(SocketServer.StreamRequestHandler):
68 """Tcp handler that returns the time when the request was read.
69
70 It can respond with the number of bytes specified in the request.
71 The request looks like:
72 request_data -> RESPONSE_SIZE_KEY num_reponse_bytes '\n' ANY_DATA
73 """
74
75 def handle(self):
76 data = self.rfile.read()
77 read_time = self.server.timer()
78 contents = str(read_time)
79 if data.startswith(RESPONSE_SIZE_KEY):
80 num_response_bytes = int(data[len(RESPONSE_SIZE_KEY):data.index('\n')])
81 contents = '%s\n%s' % (contents,
82 '\x00' * (num_response_bytes - len(contents) - 1))
83 self.wfile.write(contents)
84
85
86 class TimedUdpServer(SocketServer.ThreadingUDPServer,
87 daemonserver.DaemonServer):
88 """A simple UDP server similar to dnsproxy."""
89
90 # Override SocketServer.TcpServer setting to avoid intermittent errors.
91 allow_reuse_address = True
92
93 def __init__(self, host, port, timer=TIMER):
94 SocketServer.ThreadingUDPServer.__init__(
95 self, (host, port), TimedUdpHandler)
96 self.timer = timer
97
98 def cleanup(self):
99 pass
100
101
102 class TimedTcpServer(SocketServer.ThreadingTCPServer,
103 daemonserver.DaemonServer):
104 """A simple TCP server similar to httpproxy."""
105
106 # Override SocketServer.TcpServer setting to avoid intermittent errors.
107 allow_reuse_address = True
108
109 def __init__(self, host, port, timer=TIMER):
110 SocketServer.ThreadingTCPServer.__init__(
111 self, (host, port), TimedTcpHandler)
112 self.timer = timer
113
114 def cleanup(self):
115 try:
116 self.shutdown()
117 except KeyboardInterrupt, e:
118 pass
119
120
121 class TcpTestSocketCreator:
122 """A TCP socket creator suitable for with-statement."""
123
124 def __init__(self, host, port, timeout=1.0):
125 self.address = (host, port)
126 self.timeout = timeout
127
128 def __enter__(self):
129 self.socket = socket.create_connection(self.address, timeout=self.timeout)
130 return self.socket
131
132 def __exit__(self, *args):
133 self.socket.close()
134
135
136 class TimedTestCase(unittest.TestCase):
137 def assertAlmostEqual(self, expected, actual, tolerance=0.05):
138 """Like the following with nicer default message:
139 assertTrue(expected <= actual + tolerance &&
140 expected >= actual - tolerance)
141 """
142 delta = tolerance * expected
143 if actual > expected + delta or actual < expected - delta:
144 self.fail('%s is not equal to expected %s +/- %s%%' % (
145 actual, expected, 100 * tolerance))
146
147
148 class TcpTrafficShaperTest(TimedTestCase):
149
150 def setUp(self):
151 platform_settings = platformsettings.get_platform_settings()
152 self.host = platform_settings.get_server_ip_address()
153 self.port = TEST_HTTP_PORT
154 self.tcp_socket_creator = TcpTestSocketCreator(self.host, self.port)
155 self.timer = TIMER
156
157 def TrafficShaper(self, **kwargs):
158 return trafficshaper.TrafficShaper(
159 host=self.host, port=self.port, dns_port=None, **kwargs)
160
161 def GetTcpSendTimeMs(self, num_bytes):
162 """Return time in milliseconds to send |num_bytes|."""
163
164 with self.tcp_socket_creator as s:
165 start_time = self.timer()
166 request_data = '\x00' * num_bytes
167
168 s.sendall(request_data)
169 # TODO(slamm): Figure out why partial is shutdown needed to make it work.
170 s.shutdown(socket.SHUT_WR)
171 read_time = s.recv(1024)
172 return GetElapsedMs(start_time, read_time)
173
174 def GetTcpReceiveTimeMs(self, num_bytes):
175 """Return time in milliseconds to receive |num_bytes|."""
176
177 with self.tcp_socket_creator as s:
178 s.sendall('%s%s\n' % (RESPONSE_SIZE_KEY, num_bytes))
179 # TODO(slamm): Figure out why partial is shutdown needed to make it work.
180 s.shutdown(socket.SHUT_WR)
181 num_remaining_bytes = num_bytes
182 read_time = None
183 while num_remaining_bytes > 0:
184 response_data = s.recv(4096)
185 num_remaining_bytes -= len(response_data)
186 if not read_time:
187 read_time, padding = response_data.split('\n')
188 return GetElapsedMs(read_time, self.timer())
189
190 def testTcpConnectToIp(self):
191 """Verify that it takes |delay_ms| to establish a TCP connection."""
192 with TimedTcpServer(self.host, self.port):
193 for delay_ms in (100, 175):
194 with self.TrafficShaper(delay_ms=delay_ms):
195 start_time = self.timer()
196 with self.tcp_socket_creator:
197 connect_time = GetElapsedMs(start_time, self.timer())
198 self.assertAlmostEqual(delay_ms, connect_time, tolerance=0.12)
199
200 def testTcpUploadShaping(self):
201 """Verify that 'up' bandwidth is shaped on TCP connections."""
202 num_bytes = 1024 * 100
203 bandwidth_kbits = 2000
204 expected_ms = 8.0 * num_bytes / bandwidth_kbits
205 with TimedTcpServer(self.host, self.port):
206 with self.TrafficShaper(up_bandwidth='%sKbit/s' % bandwidth_kbits):
207 self.assertAlmostEqual(expected_ms, self.GetTcpSendTimeMs(num_bytes))
208
209 def testTcpDownloadShaping(self):
210 """Verify that 'down' bandwidth is shaped on TCP connections."""
211 num_bytes = 1024 * 100
212 bandwidth_kbits = 2000
213 expected_ms = 8.0 * num_bytes / bandwidth_kbits
214 with TimedTcpServer(self.host, self.port):
215 with self.TrafficShaper(down_bandwidth='%sKbit/s' % bandwidth_kbits):
216 self.assertAlmostEqual(expected_ms, self.GetTcpReceiveTimeMs(num_bytes))
217
218 def testTcpInterleavedDownloads(self):
219 # TODO(slamm): write tcp interleaved downloads test
220 pass
221
222
223 class UdpTrafficShaperTest(TimedTestCase):
224
225 def setUp(self):
226 platform_settings = platformsettings.get_platform_settings()
227 self.host = platform_settings.get_server_ip_address()
228 self.dns_port = TEST_DNS_PORT
229 self.timer = TIMER
230
231 def TrafficShaper(self, **kwargs):
232 return trafficshaper.TrafficShaper(
233 host=self.host, port=None, dns_port=self.dns_port, **kwargs)
234
235 def GetUdpSendReceiveTimesMs(self):
236 """Return time in milliseconds to send |num_bytes|."""
237 start_time = self.timer()
238 udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
239 udp_socket.sendto('test data\n', (self.host, self.dns_port))
240 read_time = udp_socket.recv(1024)
241 return (GetElapsedMs(start_time, read_time),
242 GetElapsedMs(read_time, self.timer()))
243
244 def testUdpDelay(self):
245 for delay_ms in (100, 170):
246 expected_ms = delay_ms / 2
247 with TimedUdpServer(self.host, self.dns_port):
248 with self.TrafficShaper(delay_ms=delay_ms):
249 send_ms, receive_ms = self.GetUdpSendReceiveTimesMs()
250 self.assertAlmostEqual(expected_ms, send_ms, tolerance=0.10)
251 self.assertAlmostEqual(expected_ms, receive_ms, tolerance=0.10)
252
253
254 def testUdpInterleavedDelay(self):
255 # TODO(slamm): write udp interleaved udp delay test
256 pass
257
258
259 class TcpAndUdpTrafficShaperTest(TimedTestCase):
260 # TODO(slamm): Test concurrent TCP and UDP traffic
261 pass
262
263
264 # TODO(slamm): Packet loss rate (try different ports)
265
266
267 if __name__ == '__main__':
268 #logging.getLogger().setLevel(logging.DEBUG)
269 unittest.main()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698