root/projects/sAsync/trunk/sasync/test/test_pdict.py

Revision 3, 14.5 kB (checked in by edsuom, 2 years ago)

Import of trunk from old repo

Line 
1 # sAsync:
2 # An enhancement to the SQLAlchemy package that provides persistent
3 # dictionaries, text indexing and searching, and an access broker for
4 # conveniently managing database access, table setup, and
5 # transactions. Everything can be run in an asynchronous fashion using the
6 # Twisted framework and its deferred processing capabilities.
7 #
8 # Copyright (C) 2006 by Edwin A. Suominen, http://www.eepatents.com
9 #
10 # This program is free software; you can redistribute it and/or modify it under
11 # the terms of the GNU General Public License as published by the Free Software
12 # Foundation; either version 2 of the License, or (at your option) any later
13 # version.
14 #
15 # This program is distributed in the hope that it will be useful, but WITHOUT
16 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 # FOR A PARTICULAR PURPOSE.  See the file COPYING for more details.
18 #
19 # You should have received a copy of the GNU General Public License along with
20 # this program; if not, write to the Free Software Foundation, Inc., 51
21 # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22
23 """
24 Unit tests for sasync.pdict.py.
25 """
26
27 import os
28 from twisted.internet import defer, reactor
29 from twisted.trial.unittest import TestCase
30
31 import sqlalchemy as SA
32 import sasync
33 from sasync.pdict import PersistentDict
34 from sasync.parray import PersistentArray
35
36 ID = 341
37 VERBOSE = False
38
39
40 db = '/tmp/pdict.db'
41 URL = "sqlite:///%s" % db
42 sasync.engine(URL)
43
44
45 def itemsEqual(itemsA, itemsB):
46     if VERBOSE:
47         print "\n%s\n\tvs\n%s\n" % (str(itemsA), str(itemsB))
48     for item in itemsA:
49         if not itemsB.count(item):
50             print "Item '%s' of list A not in list B" % (item,)
51             return False
52     for item in itemsB:
53         if not itemsA.count(item):
54             print "Item '%s' of list B not in list A" % (item,)
55             return False
56     return True
57
58
59 class TestPlayNice(TestCase):
60     def testShutdown(self):
61         def first(null):
62             y = PersistentDict('alpha')
63             d = y['eagle']
64             d.addCallback(self.failUnlessEqual, 'bald')
65             return d
66        
67         x = PersistentDict('alpha')
68         x['eagle'] = 'bald'
69         d = x.shutdown()
70         d.addCallback(first)
71         return d
72    
73     def testSequentiallyStartedDicts(self):
74         x = PersistentDict('alpha')
75         y = PersistentDict('bravo')
76        
77         def first():
78             d = x.preload()
79             d.addCallback(lambda _: y.preload())
80             return d
81
82         def second(null):
83             x['a'] = 1
84             y['a'] = 10
85             return defer.DeferredList([x.deferToWrites(), y.deferToWrites()])
86
87         def third(null):
88             self.failUnlessEqual(x['a'], 1)
89             self.failUnlessEqual(y['a'], 10)
90             return defer.DeferredList([x.shutdown(), y.shutdown()])
91        
92         d = first()
93         d.addCallback(second)
94         d.addCallback(third)
95         return d
96
97     def testThreeSeparateDicts(self):
98         def first():
99             self.x['a'] = 1
100             self.y['a'] = 10
101             self.z['a'] = 100
102             return defer.DeferredList([
103                 self.x.deferToWrites(),
104                 self.y.deferToWrites(),
105                 self.z.deferToWrites()])
106
107         def second(null):
108             d = self.x['a']
109             d.addCallback(self.failUnlessEqual, 1)
110             d.addCallback(lambda _: self.y['a'])
111             d.addCallback(self.failUnlessEqual, 10)
112             d.addCallback(lambda _: self.z['a'])
113             d.addCallback(self.failUnlessEqual, 100)
114             return d
115
116         def third(null):
117             def wait():
118                 d = defer.Deferred()
119                 reactor.callLater(1.0, d.callback, None)
120                 return d
121            
122             def thisOneShutdown(null, objectName):
123                 print "Done shutting down PDict '%s'" % objectName
124
125             dList = []
126             for objectName in ('x', 'y', 'z'):
127                 d1 = getattr(self, objectName).shutdown()
128                 if VERBOSE:
129                     print "\nAbout to shut down Pdict '%s'" % objectName
130                     d1.addCallback(thisOneShutdown, objectName)
131                 d2 = wait()
132                 dList.append(defer.DeferredList([d1,d2]))
133             return defer.DeferredList(dList)
134
135         self.x = PersistentDict('alpha')
136         self.y = PersistentDict('bravo')
137         self.z = PersistentDict('charlie')
138        
139         d = first()
140         d.addCallback(second)
141         d.addCallback(third)
142         return d
143
144     def testThreeSeparatePreloadedDicts(self):
145         def first():
146             d1 = self.x.preload()
147             d2 = self.y.preload()
148             d3 = self.z.preload()
149             d4 = defer.Deferred()
150             reactor.callLater(0.5, d4.callback, None)
151             return defer.DeferredList([d1,d2,d3,d4])
152
153         def second(null):
154             self.x['a'] = 1
155             self.y['a'] = 10
156             self.z['a'] = 100
157             return defer.DeferredList([
158                 self.x.deferToWrites(),
159                 self.y.deferToWrites(),
160                 self.z.deferToWrites()])
161
162         def third(null):
163             self.failUnlessEqual(self.x['a'], 1)
164             self.failUnlessEqual(self.y['a'], 10)
165             self.failUnlessEqual(self.z['a'], 100)
166
167         def fourth(null):
168             def wait():
169                 d = defer.Deferred()
170                 reactor.callLater(1.0, d.callback, None)
171                 return d
172            
173             def thisOneShutdown(null, objectName):
174                 print "Done shutting down PDict '%s'" % objectName
175
176             dList = []
177             for objectName in ('x', 'y', 'z'):
178                 d1 = getattr(self, objectName).shutdown()
179                 if VERBOSE:
180                     print "\nAbout to shut down Pdict '%s'" % objectName
181                     d1.addCallback(thisOneShutdown, objectName)
182                 d2 = wait()
183                 dList.append(defer.DeferredList([d1,d2]))
184             return defer.DeferredList(dList)
185
186         self.x = PersistentDict('alpha')
187         self.y = PersistentDict('bravo')
188         self.z = PersistentDict('charlie')
189        
190         d = first()
191         d.addCallback(second)
192         d.addCallback(third)
193         d.addCallback(fourth)
194         return d
195
196     def testOneDictWithParray(self):
197         import sasync.parray as parray
198        
199         x = PersistentDict('foo')
200         y = PersistentArray('bar')
201        
202         def first():
203             x['a'] = 1
204             return x.deferToWrites()
205        
206         def second(null):
207             d = x['a']
208             d.addCallback(self.failUnlessEqual, 1)
209             return d
210        
211         def third(null):
212             return defer.DeferredList([x.shutdown(), y.shutdown()])
213        
214         d = first()
215         d.addCallback(second)
216         d.addCallback(third)
217         return d
218
219     def testTwoDictsWithParray(self):
220         import sasync.parray as parray
221        
222         x = PersistentDict('foo')
223         y = PersistentDict('bar')
224         z = PersistentArray('whatever')
225        
226         def first():
227             x['a'] = 1
228             y['a'] = 10
229             return defer.DeferredList([x.deferToWrites(), y.deferToWrites()])
230        
231         def second(null):
232             d = x['a']
233             d.addCallback(self.failUnlessEqual, 1)
234             d.addCallback(lambda _: y['a'])
235             d.addCallback(self.failUnlessEqual, 10)
236             return d
237        
238         def third(null):
239             return defer.DeferredList([
240                 x.shutdown(), y.shutdown(), z.shutdown()])
241        
242         d = first()
243         d.addCallback(second)
244         d.addCallback(third)
245         return d
246
247
248 class Pdict:
249     def tearDown(self):
250         return self.p.shutdown()
251    
252     def writeToDB(self, **items):
253         def _writeToDB(insertionList):
254             if VERBOSE:
255                 print "\nWRITE-TO-DB", insertionList, "\n\n"
256             self.pit.sasync_items.insert().execute(*insertionList)
257        
258         insertionList = []
259         for name, value in items.iteritems():
260             insertionList.append({'group_id':ID, 'name':name, 'value':value})
261         return self.pit.deferToQueue(_writeToDB, insertionList)
262
263     def clearDB(self):
264         def _clearDB():
265             if VERBOSE:
266                 print "\nCLEAR-DB\n"
267             self.pit.sasync_items.delete(
268                 self.pit.sasync_items.c.group_id == ID).execute()
269        
270         return self.pit.deferToQueue(_clearDB)
271
272
273 class PdictNormal(Pdict):
274     def setUp(self):
275         def started(null):
276             self.pit = self.p.i.t
277             self.p.data.clear()
278             return self.pit.deferToQueue(clear)
279        
280         def clear():
281             si = self.pit.sasync_items
282             si.delete(si.c.group_id == ID).execute()
283
284         self.p = PersistentDict(ID)
285         d = self.p.i.t.startup()
286         d.addCallback(started)
287         return d
288
289
290 class TestPdictNormalCore(PdictNormal, TestCase):
291     def testSomeWriteSomeSet(self):
292         def setStuff(null):
293             self.p['b'] = 'beta'
294             self.p['d'] = 'delta'
295             d = self.p.deferToWrites()
296             d.addCallback(lambda _: self.p.items())
297             d.addCallback(
298                 itemsEqual,
299                 [('a','alpha'), ('b','beta'), ('c','charlie'), ('d','delta')])
300             d.addCallback(self.failUnless, "Items not equal")
301             return d
302        
303         d = self.writeToDB(a='alpha', b='bravo', c='charlie')
304         d.addCallback(setStuff)
305         return d
306
307     def testWriteAndGet(self):
308         d = self.writeToDB(a=100, b=200, c='foo')
309         d.addCallback(lambda _: self.p['a'])
310         d.addCallback(self.failUnlessEqual, 100)
311         d.addCallback(lambda _: self.p['b'])
312         d.addCallback(self.failUnlessEqual, 200)
313         d.addCallback(lambda _: self.p['c'])
314         d.addCallback(self.failUnlessEqual, 'foo')
315         return d
316
317
318 class TestPdictNormalMain(PdictNormal, TestCase):
319     def testLoadAll(self):
320         def checkItems(items):
321             self.failUnlessEqual(items, {'a':1, 'b':2})
322            
323         d = self.writeToDB(a=1, b=2)
324         d.addCallback(lambda _: self.p.loadAll())
325         d.addCallback(checkItems)
326         return d
327
328     def testSetAndGet(self):
329         self.p['a'] = 10       
330         d = self.p.deferToWrites()
331         d.addCallback(lambda _: self.p['a'])
332         d.addCallback(self.failUnlessEqual, 10)
333         return d
334
335     def testSetAndLoadAll(self):
336         self.p['a'] = 1
337         self.p['b'] = 2
338
339         d = self.p.deferToWrites()
340         d.addCallback(lambda _: self.p.loadAll())
341         d.addCallback(self.failUnlessEqual, {'a':1, 'b':2})
342         return d
343            
344     def testSetdefaultEmpty(self):
345         self.p['a'] = 1
346         self.p.writeTracker.put(self.p.setdefault('b', 2))
347
348         d = self.p.deferToWrites()
349         d.addCallback(lambda _: self.p.loadAll())
350         d.addCallback(self.failUnlessEqual, {'a':1, 'b':2})
351         return d
352
353     def testSetClearAndLoadAll(self):
354         self.p['a'] = 1
355         self.p['b'] = 2
356         self.p.clear()
357         d = self.p.deferToWrites()
358         d.addCallback(lambda _: self.p.loadAll())
359         d.addCallback(self.failUnlessEqual, {})
360         return d
361
362     def testSetdefaultSet(self):
363         self.p['a'] = 1
364         self.p.writeTracker.put(self.p.setdefault('a', 2))
365
366         d = self.p.deferToWrites()
367         d.addCallback(lambda _: self.p.items())
368         d.addCallback(self.failUnlessEqual, [('a',1)])
369         return d
370
371     def testSetAndGetComplex(self):
372         self.p['a'] = 1
373         self.p['b'] = 2
374         self.p.writeTracker.put(self.p.setdefault('b', 20))
375         self.p.writeTracker.put(self.p.setdefault('c', 3))
376         self.p.update({'d':4, 'e':5})
377
378         d = self.p.deferToWrites()
379         d.addCallback(lambda _: self.p.items())
380         d.addCallback(itemsEqual, [('a',1), ('b',2), ('c',3), ('d',4), ('e',5)])
381         d.addCallback(self.failUnless, "Items not equal")
382         return d
383
384     def testKeys(self):
385         d = self.writeToDB(a=1.1, b=1.2, c=1.3)
386         d.addCallback(lambda _: self.p.keys())
387         d.addCallback(itemsEqual, ['a', 'b', 'c'])
388         d.addCallback(self.failUnless)
389         return d
390
391     def testValues(self):
392         d = self.writeToDB(a=1.1, b=1.2, c=1.3)
393         d.addCallback(lambda _: self.p.values())
394         d.addCallback(itemsEqual, [1.1, 1.2, 1.3])
395         d.addCallback(self.failUnless)
396         return d
397
398     def testItems(self):
399         d = self.writeToDB(a=2.1, b=2.2, c=2.3)
400         d.addCallback(lambda _: self.p.items())
401         d.addCallback(itemsEqual, [('a',2.1), ('b',2.2), ('c',2.3)])
402         d.addCallback(self.failUnless)
403         return d
404
405     def testContains(self):
406         def one(null):
407             d = self.p.has_key('a')
408             d.addCallback(
409                 self.failUnless, "Item 'a' should be in the dictionary")
410             return d
411        
412         def another(null):
413             d = self.p.has_key('d')
414             d.addCallback(self.failIf, "Item 'd' shouldn't be in the dictionary")
415             return d
416        
417         d = self.clearDB()
418         d.addCallback(lambda _: self.writeToDB(a=1.1, b=1.2, c=1.3))
419         d.addCallback(one)
420         d.addCallback(another)
421         return d
422
423     def testGetMethod(self):
424         d = self.clearDB()
425         d.addCallback(lambda _: self.writeToDB(a='present'))
426         d.addCallback(lambda _: self.p.get('a', None))
427         d.addCallback(self.failUnlessEqual, 'present')
428         d.addCallback(lambda _: self.p.get('b', None))
429         d.addCallback(self.failUnlessEqual, None)
430         return d
431
432
433 class PdictPreload(Pdict):
434     def setUp(self):
435         def started(null):
436             self.pit = self.p.i.t
437             self.p.data.clear()
438             return self.pit.deferToQueue(clear)
439        
440         def clear():
441             si = self.pit.sasync_items
442             si.delete(si.c.group_id == ID).execute()
443
444         self.p = PersistentDict(ID)
445         d = self.p.preload()
446         d.addCallback(started)
447         return d
448
449
450 class TestPdictPreload(PdictPreload, TestCase):
451     def testSetAndGet(self):
452         self.p['a'] = 10       
453         self.failUnlessEqual(self.p['a'], 10)
454
455     def testSetActuallyWrites(self):
456         def first(null):
457             self.p['a'] = 'new'
458             return self.p.deferToWrites()
459         def second(null):
460             def _second():
461                 si = self.pit.sasync_items
462                 row = si.select(
463                     SA.and_(
464                     si.c.group_id==ID, si.c.name=='a')).execute().fetchone()
465                 return row['value']
466             return self.pit.deferToQueue(_second)
467         d = self.clearDB()
468         d.addCallback(first)
469         d.addCallback(second)
470         d.addCallback(self.failUnlessEqual, 'new')
471         return d
Note: See TracBrowser for help on using the browser.