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

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

Work towards testing caching with instances as inputs.
Test fails deliberately at the moment.

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