Merge lp:~david-goetz/swift/ratelimit_test_fix into lp:~hudson-openstack/swift/trunk

Proposed by David Goetz
Status: Merged
Approved by: gholt
Approved revision: 312
Merged at revision: 314
Proposed branch: lp:~david-goetz/swift/ratelimit_test_fix
Merge into: lp:~hudson-openstack/swift/trunk
Diff against target: 276 lines (+91/-51)
1 file modified
test/unit/common/middleware/test_ratelimit.py (+91/-51)
To merge this branch: bzr merge lp:~david-goetz/swift/ratelimit_test_fix
Reviewer Review Type Date Requested Status
Swift Core security contacts Pending
Review via email: mp+64876@code.launchpad.net

Description of the change

Fixing ratelimit tests

To post a comment you must log in.
312. By David Goetz

fixing ratelimit tests

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'test/unit/common/middleware/test_ratelimit.py'
2--- test/unit/common/middleware/test_ratelimit.py 2011-03-16 05:12:03 +0000
3+++ test/unit/common/middleware/test_ratelimit.py 2011-06-16 18:08:30 +0000
4@@ -15,6 +15,7 @@
5
6 import unittest
7 import time
8+import eventlet
9 from contextlib import contextmanager
10 from threading import Thread
11 from webob import Request
12@@ -30,6 +31,7 @@
13 def __init__(self):
14 self.store = {}
15 self.error_on_incr = False
16+ self.init_incr_return_neg = False
17
18 def get(self, key):
19 return self.store.get(key)
20@@ -41,6 +43,10 @@
21 def incr(self, key, delta=1, timeout=0):
22 if self.error_on_incr:
23 raise MemcacheConnectionError('Memcache restarting')
24+ if self.init_incr_return_neg:
25+ # simulate initial hit, force reset of memcache
26+ self.init_incr_return_neg = False
27+ return -10000000
28 self.store[key] = int(self.store.setdefault(key, 0)) + int(delta)
29 if self.store[key] < 0:
30 self.store[key] = 0
31@@ -109,23 +115,53 @@
32 return ratelimit.RateLimitMiddleware(app, conf, logger=FakeLogger())
33 return limit_filter
34
35+time_ticker = 0
36+time_override = []
37+
38+
39+def mock_sleep(x):
40+ global time_ticker
41+ time_ticker += x
42+
43+
44+def mock_time():
45+ global time_override
46+ global time_ticker
47+ if time_override:
48+ cur_time = time_override.pop(0)
49+ if cur_time is None:
50+ time_override = [None if i is None else i + time_ticker
51+ for i in time_override]
52+ return time_ticker
53+ return cur_time
54+ return time_ticker
55+
56
57 class TestRateLimit(unittest.TestCase):
58
59- def _run(self, callable_func, num, rate, extra_sleep=0,
60- total_time=None, check_time=True):
61+ def setUp(self):
62+ global time_ticker
63+ time_ticker = 0
64+ self.was_sleep = eventlet.sleep
65+ eventlet.sleep = mock_sleep
66+ self.was_time = time.time
67+ time.time = mock_time
68+
69+ def tearDown(self):
70+ eventlet.sleep = self.was_sleep
71+ time.time = self.was_time
72+
73+ def _run(self, callable_func, num, rate, check_time=True):
74+ global time_ticker
75 begin = time.time()
76 for x in range(0, num):
77 result = callable_func()
78- # Extra sleep is here to test with different call intervals.
79- time.sleep(extra_sleep)
80 end = time.time()
81- if total_time is None:
82- total_time = num / rate
83+ total_time = float(num) / rate - 1.0 / rate # 1st request isn't limited
84 # Allow for one second of variation in the total time.
85 time_diff = abs(total_time - (end - begin))
86 if check_time:
87- self.assertTrue(time_diff < 1)
88+ self.assertEquals(round(total_time, 1), round(time_ticker, 1))
89 return time_diff
90
91 def test_get_container_maxrate(self):
92@@ -163,8 +199,8 @@
93 'PUT', 'a', 'c', 'o')), 1)
94
95 def test_ratelimit(self):
96- current_rate = 13
97- num_calls = 5
98+ current_rate = 5
99+ num_calls = 50
100 conf_dict = {'account_ratelimit': current_rate}
101 self.test_ratelimit = ratelimit.filter_factory(conf_dict)(FakeApp())
102 ratelimit.http_connect = mock_http_connect(204)
103@@ -172,9 +208,27 @@
104 req.environ['swift.cache'] = FakeMemcache()
105 make_app_call = lambda: self.test_ratelimit(req.environ,
106 start_response)
107+ begin = time.time()
108 self._run(make_app_call, num_calls, current_rate)
109+ self.assertEquals(round(time.time() - begin, 1), 9.8)
110+
111+ def test_ratelimit_set_incr(self):
112+ current_rate = 5
113+ num_calls = 50
114+ conf_dict = {'account_ratelimit': current_rate}
115+ self.test_ratelimit = ratelimit.filter_factory(conf_dict)(FakeApp())
116+ ratelimit.http_connect = mock_http_connect(204)
117+ req = Request.blank('/v/a')
118+ req.environ['swift.cache'] = FakeMemcache()
119+ req.environ['swift.cache'].init_incr_return_neg = True
120+ make_app_call = lambda: self.test_ratelimit(req.environ,
121+ start_response)
122+ begin = time.time()
123+ self._run(make_app_call, num_calls, current_rate, check_time=False)
124+ self.assertEquals(round(time.time() - begin, 1), 9.8)
125
126 def test_ratelimit_whitelist(self):
127+ global time_ticker
128 current_rate = 2
129 conf_dict = {'account_ratelimit': current_rate,
130 'max_sleep_time_seconds': 2,
131@@ -195,7 +249,6 @@
132 self.result = self.parent.test_ratelimit(req.environ,
133 start_response)
134 nt = 5
135- begin = time.time()
136 threads = []
137 for i in range(nt):
138 rc = rate_caller(self)
139@@ -206,10 +259,10 @@
140 the_498s = [t for t in threads if \
141 ''.join(t.result).startswith('Slow down')]
142 self.assertEquals(len(the_498s), 0)
143- time_took = time.time() - begin
144- self.assert_(time_took < 1)
145+ self.assertEquals(time_ticker, 0)
146
147 def test_ratelimit_blacklist(self):
148+ global time_ticker
149 current_rate = 2
150 conf_dict = {'account_ratelimit': current_rate,
151 'max_sleep_time_seconds': 2,
152@@ -231,7 +284,6 @@
153 self.result = self.parent.test_ratelimit(req.environ,
154 start_response)
155 nt = 5
156- begin = time.time()
157 threads = []
158 for i in range(nt):
159 rc = rate_caller(self)
160@@ -242,49 +294,35 @@
161 the_497s = [t for t in threads if \
162 ''.join(t.result).startswith('Your account')]
163 self.assertEquals(len(the_497s), 5)
164- time_took = time.time() - begin
165- self.assert_(round(time_took, 1) == 0)
166+ self.assertEquals(time_ticker, 0)
167
168 def test_ratelimit_max_rate_double(self):
169+ global time_ticker
170+ global time_override
171 current_rate = 2
172 conf_dict = {'account_ratelimit': current_rate,
173 'clock_accuracy': 100,
174 'max_sleep_time_seconds': 1}
175- # making clock less accurate for nosetests running slow
176 self.test_ratelimit = dummy_filter_factory(conf_dict)(FakeApp())
177 ratelimit.http_connect = mock_http_connect(204)
178 self.test_ratelimit.log_sleep_time_seconds = .00001
179 req = Request.blank('/v/a')
180 req.environ['swift.cache'] = FakeMemcache()
181- begin = time.time()
182-
183- class rate_caller(Thread):
184-
185- def __init__(self, parent, name):
186- Thread.__init__(self)
187- self.parent = parent
188- self.name = name
189-
190- def run(self):
191- self.result1 = self.parent.test_ratelimit(req.environ,
192- start_response)
193- time.sleep(.1)
194- self.result2 = self.parent.test_ratelimit(req.environ,
195- start_response)
196- nt = 3
197- threads = []
198- for i in range(nt):
199- rc = rate_caller(self, "thread %s" % i)
200- rc.start()
201- threads.append(rc)
202- for thread in threads:
203- thread.join()
204- all_results = [''.join(t.result1) for t in threads]
205- all_results += [''.join(t.result2) for t in threads]
206- the_498s = [t for t in all_results if t.startswith('Slow down')]
207- self.assertEquals(len(the_498s), 2)
208- time_took = time.time() - begin
209- self.assert_(1.5 <= round(time_took, 1) < 1.7, time_took)
210+
211+ time_override = [0, 0, 0, 0, None]
212+ # simulates 4 requests coming in at same time, then sleeping
213+ r = self.test_ratelimit(req.environ, start_response)
214+ mock_sleep(.1)
215+ r = self.test_ratelimit(req.environ, start_response)
216+ mock_sleep(.1)
217+ r = self.test_ratelimit(req.environ, start_response)
218+ self.assertEquals(r[0], 'Slow down')
219+ mock_sleep(.1)
220+ r = self.test_ratelimit(req.environ, start_response)
221+ self.assertEquals(r[0], 'Slow down')
222+ mock_sleep(.1)
223+ r = self.test_ratelimit(req.environ, start_response)
224+ self.assertEquals(r[0], '204 No Content')
225
226 def test_ratelimit_max_rate_multiple_acc(self):
227 num_calls = 4
228@@ -319,9 +357,9 @@
229 threads.append(rc)
230 for thread in threads:
231 thread.join()
232+
233 time_took = time.time() - begin
234- # the all 15 threads still take 1.5 secs
235- self.assert_(1.5 <= round(time_took, 1) < 1.7)
236+ self.assertEquals(1.5, round(time_took, 1))
237
238 def test_ratelimit_acc_vrs_container(self):
239 conf_dict = {'clock_accuracy': 1000,
240@@ -354,14 +392,13 @@
241 threads.append(rc)
242 for thread in threads:
243 thread.join()
244-
245 begin = time.time()
246 req.environ['swift.cache'].set(cont_key, {'container_size': 20})
247 begin = time.time()
248 threads = []
249 runthreads(threads, 3)
250 time_took = time.time() - begin
251- self.assert_(round(time_took, 1) == .4)
252+ self.assertEquals(round(time_took, 1), .4)
253
254 def test_call_invalid_path(self):
255 env = {'REQUEST_METHOD': 'GET',
256@@ -393,7 +430,10 @@
257 req.environ['swift.cache'] = None
258 make_app_call = lambda: self.test_ratelimit(req.environ,
259 start_response)
260- self._run(make_app_call, num_calls, current_rate)
261+ begin = time.time()
262+ self._run(make_app_call, num_calls, current_rate, check_time=False)
263+ time_took = time.time() - begin
264+ self.assertEquals(round(time_took, 1), 0) # no memcache, no limiting
265
266 def test_restarting_memcache(self):
267 current_rate = 2
268@@ -409,7 +449,7 @@
269 begin = time.time()
270 self._run(make_app_call, num_calls, current_rate, check_time=False)
271 time_took = time.time() - begin
272- self.assert_(round(time_took, 1) == 0) # no memcache, no limiting
273+ self.assertEquals(round(time_took, 1), 0) # no memcache, no limiting
274
275 if __name__ == '__main__':
276 unittest.main()