My favorites | Sign in
Project Home
New issue   Search
for
  Advanced search   Search tips   Subscriptions

Issue 208 attachment: 01-issue-208-test_http.patch (3.1 KB)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# HG changeset patch
# User Alexander Shorin
# Date 1322355442 -10800
# Branch httplib
# Node ID 76c04aa831942427b6cd08043386bec8d80818ac
# Parent 7db07fb6811fa1ffb3d23a45092fd730d22c51dc
Add test case to notice race condition on Session.cache operations.

diff -r 7db07fb6811f -r 76c04aa83194 couchdb/tests/http.py
--- a/couchdb/tests/http.py Wed Nov 16 21:36:22 2011 +0000
+++ b/couchdb/tests/http.py Sun Nov 27 03:57:22 2011 +0300
@@ -8,7 +8,9 @@

import doctest
import socket
+import sys
import time
+import threading
import unittest
from StringIO import StringIO

@@ -67,11 +69,77 @@
self.assertEqual(list(response), [])


+class ConcurrencyTestCase(testutil.TempDatabaseMixin, unittest.TestCase):
+
+ class Worker(threading.Thread):
+ def __init__(self, func, *args, **kwargs):
+ self.func = func
+ self.args = args
+ self.kwargs = kwargs
+ self.exc_info = None
+ super(ConcurrencyTestCase.Worker, self).__init__()
+
+ def run(self):
+ try:
+ self.func(*self.args, **self.kwargs)
+ except Exception:
+ self.exc_info = sys.exc_info()
+
+ def test_concurrent_cache_access(self):
+ # issue #208
+ # task: handle race condition on Session.cache operations
+
+ class SlowCache(dict):
+ def __setitem__(self, key, value):
+ value[1]['etag'] = '' # forge etag to have out of date cache hit
+ super(SlowCache, self).__setitem__(key, value)
+
+ def iteritems(self):
+ items = super(SlowCache, self).iteritems()
+ for item in items:
+ yield item
+ # make iteritem slow to raise race condition chances
+ time.sleep(1)
+
+ url = self.db.resource.url
+ dummy_cache = dict([
+ ('%s/%s' % (url, i),
+ (200, {'Date': 'Sat, 26 Nov 2011 00:00:00 GMT'}, ''))
+ for i in range(1, http.CACHE_SIZE[1] + 10) # cache overflow
+ ])
+ self.db.resource.session = http.Session(cache=SlowCache(dummy_cache))
+
+ def do_work():
+ for i in range(10):
+ idx = str(i)
+ if idx in self.db:
+ doc = self.db[idx]
+ else:
+ doc = {'_id': idx, 'foo': 'bar'}
+ try:
+ self.db.save(doc)
+ except http.ResourceConflict:
+ pass
+
+ workers = [self.Worker(do_work) for i in range(2)]
+
+ for worker in workers:
+ worker.start()
+
+ while not all(map(lambda w: not w.is_alive(), workers)):
+ pass
+
+ for worker in workers:
+ if worker.exc_info is not None:
+ raise worker.exc_info[1], None, worker.exc_info[2]
+
+
def suite():
suite = unittest.TestSuite()
suite.addTest(doctest.DocTestSuite(http))
suite.addTest(unittest.makeSuite(SessionTestCase, 'test'))
suite.addTest(unittest.makeSuite(ResponseBodyTestCase, 'test'))
+ suite.addTest(unittest.makeSuite(ConcurrencyTestCase, 'test'))
return suite


Powered by Google Project Hosting