source: anuga_core/source/anuga/caching/test_caching.py @ 5851

Last change on this file since 5851 was 5851, checked in by ole, 15 years ago

Added two new tests verifying that caching works with Numeric arrays based on
their contents rather than id, but that (as we know) this is not currently
the case for instances.

The latter test fails at the moment.

File size: 15.4 KB
Line 
1
2import unittest
3from Numeric import arange, array
4
5from anuga.caching import *
6
7
8
9# Define a test function to be cached
10#
11def f(a,b,c,N,x=0,y='abcdefg'):
12  """f(a,b,c,N)
13     Do something time consuming and produce a complex result.
14  """
15
16  import string
17
18  B = []
19  for n in range(N):
20    s = str(n+2.0/(n + 4.0))+'.a'*10
21    B.append((a,b,c,s,n,x,y))
22  return(B)
23 
24def f_numeric(A, B):
25  """Operation on Numeric arrays
26  """
27 
28  return 3.1*A + B + 1
29 
30 
31def f_object(A, B):
32  """Operation of objecs of class Dummy
33  """
34 
35  return A.value+B.value, A.another+B.another
36 
37 
38 
39class Dummy:
40  def __init__(self, value, another):
41    self.value = value
42    self.another = another
43   
44  def copy(self):
45    return Dummy(self.value, self.another)
46   
47
48def clear_and_create_cache(Dummy, verbose=False):
49  a = cache(Dummy, 'clear', verbose=verbose)
50       
51  a = cache(Dummy, args=(9,10),
52            verbose=verbose)
53     
54
55def retrieve_cache(Dummy, verbose=False):
56  if verbose: print 'Check that cache is there'
57  assert cache(Dummy, args=(9,10), test=1,
58               verbose=verbose)     
59     
60
61   
62
63class Test_Caching(unittest.TestCase):
64    def setUp(self):
65        set_option('verbose', 0)  #Why
66
67        pass
68
69    def tearDown(self):
70        pass
71
72    def test_simple(self):
73        """Check set_option (and switch stats off)
74        """
75
76        set_option('savestat', 0)
77        assert options['savestat'] == 0
78        set_option('verbose', 0)
79        assert options['verbose'] == 0       
80       
81
82    def test_basic_caching(self):
83
84        verbose=False
85        # Make some test input arguments
86        #
87        N = 5000  #Make N fairly small here
88
89        a = [1,2]
90        b = ('Thou shalt count the number three',4)
91        c = {'Five is right out': 6, (7,8): 9}
92        x = 3
93        y = 'holy hand granate'
94
95        # Test caching
96        #
97
98        comprange = 2
99
100        for comp in range(comprange):
101 
102            # Evaluate and store
103            #
104            T1 = cache(f, (a,b,c,N), {'x':x, 'y':y}, evaluate=1, \
105                       compression=comp, verbose=verbose)
106
107            # Retrieve
108            #                           
109            T2 = cache(f, (a,b,c,N), {'x':x, 'y':y}, compression=comp) 
110
111            # Reference result
112            #   
113            T3 = f(a,b,c,N,x=x,y=y)  # Compute without caching
114
115
116            assert T1 == T2, 'Cached result does not match computed result'
117            assert T2 == T3, 'Cached result does not match computed result'
118           
119
120    def test_caching_of_numeric_arrays(self):
121        """test_caching_of_numeric_arrays
122       
123        Test that Numeric arrays can be recognised by caching even if their id's are different
124        """
125       
126        verbose = False
127       
128        # Make some test input arguments
129        A0 = arange(5)
130        B0 = array([1.1, 2.2, 0.0, -5, -5])
131       
132        A1 = A0.copy()
133        B1 = B0.copy()
134       
135        # Check that their ids are different
136        assert id(A0) != id(A1)
137        assert id(B0) != id(B1)       
138       
139       
140        # Test caching
141        comprange = 2
142        for comp in range(comprange):
143 
144            # Evaluate and store
145            T1 = cache(f_numeric, (A0, B0), evaluate=1,
146                       compression=comp, verbose=verbose)
147
148            # Retrieve
149            T2 = cache(f_numeric, (A1, B1), 
150                       compression=comp, test=1, verbose=verbose) 
151                       
152            # Check for presence of cached result
153            msg = 'Different array objects with same contents were not recognised'           
154            assert T2 is not None, msg
155
156            # Reference result
157            T3 = f_numeric(A0, B0) # Compute without caching
158
159
160            assert T1 == T2, 'Cached result does not match computed result'
161            assert T2 == T3, 'Cached result does not match computed result'
162           
163
164
165    def test_caching_of_objects(self):
166        """test_caching_of_objects
167       
168        Test that Objecs can be recognised as input variabelse
169        by caching even if their id's are different
170        """
171   
172
173        verbose = False
174       
175        # Make some test input arguments
176        A0 = Dummy(5, 7)
177        B0 = Dummy(2.2, -5)
178       
179        A1 = A0.copy()
180        B1 = B0.copy()
181       
182        # Check that their ids are different
183        assert id(A0) != id(A1)
184        assert id(B0) != id(B1)       
185       
186       
187        # Test caching
188        comprange = 2
189        for comp in range(comprange):
190 
191            # Evaluate and store
192            T1 = cache(f_object, (A0, B0), evaluate=1,
193                       compression=comp, verbose=verbose)
194
195            # Retrieve
196            T2 = cache(f_object, (A1, B1), 
197                       compression=comp, test=1, verbose=verbose) 
198                       
199            # Check for presence of cached result
200            msg = 'Different objects with same attributes were not recognised'
201            assert T2 is not None, msg
202
203            # Reference result
204            T3 = f_object(A0, B0) # Compute without caching
205
206
207            assert T1 == T2, 'Cached result does not match computed result'
208            assert T2 == T3, 'Cached result does not match computed result'
209           
210
211                       
212           
213           
214    def test_cachefiles(self):
215        """Test existence of cachefiles
216        """       
217        N = 5000  #Make N fairly small here
218
219        a = [1,2]
220        b = ('Thou shalt count the number three',4)
221        c = {'Five is right out': 6, (7,8): 9}
222        x = 3
223        y = 'holy hand granate'
224
225       
226        FN = cache(f,(a,b,c,N), {'x':x, 'y':y}, verbose=0, \
227                  return_filename = 1)
228
229
230        assert FN[:2] == 'f['
231
232        CD = checkdir(cachedir)
233        compression = 1
234
235        (datafile,compressed0) = myopen(CD+FN+'_'+file_types[0],"rb",compression)
236        (argsfile,compressed1) = myopen(CD+FN+'_'+file_types[1],"rb",compression)
237        (admfile,compressed2) =  myopen(CD+FN+'_'+file_types[2],"rb",compression)
238
239        datafile.close()
240        argsfile.close()
241        admfile.close()
242
243    def test_test(self):       
244        """Test 'test' function when cache is present
245        """
246        N = 5000  #Make N fairly small here
247
248        a = [1,2]
249        b = ('Thou shalt count the number three',4)
250        c = {'Five is right out': 6, (7,8): 9}
251        x = 3
252        y = 'holy hand granate'
253       
254
255        T1 = cache(f,(a,b,c,N), {'x':x, 'y':y}, evaluate=1)
256       
257        T4 = cache(f,(a,b,c,N), {'x':x, 'y':y}, test=1)
258        assert T1 == T4, "Option 'test' when cache file present failed"     
259
260
261    def test_clear(self):       
262        """Test that 'clear' works
263        """
264
265        N = 5000  #Make N fairly small here
266
267        a = [1,2]
268        b = ('Thou shalt count the number three',4)
269        c = {'Five is right out': 6, (7,8): 9}
270        x = 3
271        y = 'holy hand granate'
272       
273
274        T1 = cache(f,(a,b,c,N), {'x':x, 'y':y}, evaluate = 1)
275       
276       
277        cache(f, (a,b,c,N), {'x':x, 'y':y}, clear = 1)   
278
279 
280        # Test 'test' function when cache is absent
281       
282       
283        T4 = cache(f, (a,b,c,N), {'x':x, 'y':y}, test=1)
284        #print 'T4', T4
285        assert T4 is None, "Option 'test' when cache absent failed"
286
287
288    def test_dependencies(self):
289       
290        # Make a dependency file
291        CD = checkdir(cachedir)       
292
293        DepFN = CD + 'testfile.tmp'
294        DepFN_wildcard = CD + 'test*.tmp'
295        Depfile = open(DepFN,'w')
296        Depfile.write('We are the knights who say NI!')
297        Depfile.close()
298
299       
300        # Test
301        #
302
303        N = 5000  #Make N fairly small here
304
305        a = [1,2]
306        b = ('Thou shalt count the number three',4)
307        c = {'Five is right out': 6, (7,8): 9}
308        x = 3
309        y = 'holy hand granate'
310       
311        T1 = cache(f,(a,b,c,N), {'x':x, 'y':y}, dependencies=DepFN) 
312        T2 = cache(f,(a,b,c,N), {'x':x, 'y':y}, dependencies=DepFN)                     
313                       
314        assert T1 == T2, 'Dependencies do not work'
315
316
317        # Test basic wildcard dependency
318        T3 = cache(f,(a,b,c,N), {'x':x, 'y':y}, dependencies=DepFN_wildcard)                     
319   
320        assert T1 == T3, 'Dependencies with wildcards do not work'
321
322
323        # Test that changed timestamp in dependencies triggers recomputation
324 
325        # Modify dependency file
326        Depfile = open(DepFN,'a')
327        Depfile.write('You must cut down the mightiest tree in the forest with a Herring')
328        Depfile.close()
329 
330        T3 = cache(f,(a,b,c,N), {'x':x, 'y':y}, dependencies=DepFN, test = 1)
331       
332        assert T3 is None, 'Changed dependencies not recognised'
333 
334        # Test recomputation when dependencies have changed
335        #
336        T3 = cache(f,(a,b,c,N), {'x':x, 'y':y}, dependencies=DepFN)                       
337        assert T1 == T3, 'Recomputed value with changed dependencies failed'
338
339    #def test_performance(self):       
340    #    """Performance test (with statistics)
341    #    Don't really rely on this as it will depend on specific computer.
342    #    """
343    #
344    #    import time
345    #    set_option('savestat', 1)
346    #
347    #    N = 300000   #Should be large on fast computers...
348    #    a = [1,2]
349    #    b = ('Thou shalt count the number three',4)
350    #    c = {'Five is right out': 6, (7,8): 9}
351    #    x = 3
352    #    y = 'holy hand granate'
353    #     
354    #   
355    #    tt = time.time()
356    #    T1 = cache(f,(a,b,c,N), {'x':x, 'y':y})
357    #    t1 = time.time() - tt
358    #
359    #    tt = time.time()
360    #    T2 = cache(f,(a,b,c,N), {'x':x, 'y':y})
361    #    t2 = time.time() - tt
362     
363    #    assert T1 == T2
364    #     assert t1 > t2, 'WARNING: Performance a bit low - this could be specific to current platform. Try to increase N in this test'
365    #    #test_OK('Performance test: relative time saved = %s pct' \
366    #    #        %str(round((t1-t2)*100/t1,2)))
367
368
369    def test_statsfile(self):                   
370        """Test presence of statistics file
371        """
372        import os, string
373        statsfile  = '.cache_stat'  # Basefilename for cached statistics.
374       
375        CD = checkdir(cachedir)               
376        DIRLIST = os.listdir(CD)
377        SF = []
378        for FN in DIRLIST:
379            if string.find(FN,statsfile) >= 0:
380                try:
381                    fid = open(CD+FN,'r')
382                    fid.close()
383                except:
384                    raise 'Statistics files cannot be opened'         
385 
386         
387
388    # def test_network_cachedir(self):
389
390#         #set_option('cachedir', 'H:\\.python_cache\\')
391#         set_option('cachedir', 'V:\\2\\cit\\.python_cache\\')
392#         set_option('verbose', 1)
393
394       
395#         # Make some test input arguments
396#         #
397#         N = 5000  #Make N fairly small here
398
399#         a = [1,2]
400#         b = ('Thou shalt count the number three',4)
401#         c = {'Five is right out': 6, (7,8): 9}
402#         x = 3
403#         y = 'holy hand granate'
404
405#         # Test caching
406#         #
407
408#         comprange = 2
409
410#         for comp in range(comprange):
411 
412#             # Evaluate and store
413#             #
414#             T1 = cache(f, (a,b,c,N), {'x':x, 'y':y}, evaluate=1, \
415#                        compression=comp)
416
417#             # Retrieve
418#             #                           
419#             T2 = cache(f, (a,b,c,N), {'x':x, 'y':y}, compression=comp)
420
421#             # Reference result
422#             #   
423#             T3 = f(a,b,c,N,x=x,y=y)  # Compute without caching
424
425
426#             assert T1 == T2, 'Cached result does not match computed result'
427#             assert T2 == T3, 'Cached result does not match computed result'
428             
429
430
431    def Will_fail_test_objects(self):
432      """
433      This test shows how instances can't be effectively cached.
434      myhash uses hash which uses id which uses the memory address.
435      """
436      verbose = True
437      #verbose = False
438
439      for i in range(2):
440        if verbose: print "clear cache"
441        a = cache(Dummy, 'clear')
442       
443        if verbose: print "cache for first time"
444        a = cache(Dummy, args=(9,10), verbose=verbose)
445        hash_value = myhash(a)
446       
447        #print "hash_value",hash_value
448        if verbose: print "cache for second time"
449        a = cache(Dummy, args=(9,10), verbose=verbose)
450       
451        #print "myhash(a)",myhash(a)
452        assert hash_value == myhash(a)
453
454
455    # This test works in the caching dir and in anuga_core, but not in the
456    # anuga_core/source/anuga dir
457    # This has to do with pickle (see e.g. http://telin.ugent.be/~slippens/drupal/pickleproblem)
458    # The error message is
459    # PicklingError: Can't pickle test_caching.Dummy: it's not the same object as test_caching.Dummy
460    def Xtest_objects_are_created(self):
461      """
462      This test shows how instances can be created from cache
463      as long as input arguments are unchanged.
464
465      Such instances will have different id's and cannot be used as input
466      arguments in subsequent caches. However, this is still useful.
467
468      Do it for all combinations of compression
469
470      """
471
472      verbose = False
473
474      for compression_store in [False, True]:
475        for compression_retrieve in [False, True]:       
476       
477          if verbose: print 'clear cache'
478          a = cache(Dummy, 'clear')
479       
480          if verbose: print 'cache for first time'
481          a = cache(Dummy, args=(9,10),
482                    compression=compression_store,
483                    verbose=verbose)
484         
485          if verbose: print 'Check that cache is there'
486          assert cache(Dummy, args=(9,10), test=1,
487                       compression=compression_retrieve,
488                       verbose=verbose)
489
490
491
492    # NOTE (Ole): This test has been commented out because, although the test will pass
493    #             inside the caching dir and also at the anuga_core level,
494    #             it won't pass at the anuga_core/source/anuga level.
495    # See  message above.
496    def Xtest_objects_are_created_memory(self):
497      """
498     
499      This test shows how instances can be created from cache
500      as long as input arguments are unchanged - even if the class
501      lives in different memory locations.
502
503      This is using cache created in the main program below
504      """
505
506      verbose = False
507
508      # Redefine class Dummy_memorytest
509      class Dummy_memorytest:
510        def __init__(self, value, another):
511          self.value = value     
512
513      # Make sure that class has been redefined to another address
514      #print
515      #print 'Initial_addr  ', initial_addr
516      #print 'Redefined addr', `Dummy_memorytest`
517      msg = 'Redefined class ended up at same memory location as '
518      msg += 'original class making this test irrelevant. Try to run '
519      msg += 'it again and see if this error goes away.'
520      msg += 'If it persists contact Ole.Nielsen@ga.gov.au'
521      assert initial_addr != `Dummy_memorytest`, msg   
522
523     
524      retrieve_cache(Dummy_memorytest, verbose=verbose)     
525         
526# Define class Dummy_memorytest before any tests are run
527# to make sure it has a different memory address
528# to the one defined in test 'test_objects_are_created_memory'
529#class Dummy_memorytest:
530#  def __init__(self, value, another):
531#    self.value = value     
532
533# Cache created for use with 'test_objects_are_created_memory'
534#initial_addr = `Dummy_memorytest`
535#clear_and_create_cache(Dummy_memorytest, verbose=False)
536 
537     
538
539
540
541     
542       
543
544
545#-------------------------------------------------------------
546if __name__ == "__main__":
547    suite = unittest.makeSuite(Test_Caching,'test')
548    runner = unittest.TextTestRunner()
549    runner.run(suite)
Note: See TracBrowser for help on using the repository browser.