load tests from tests directory instead of modules
[tests.git] / qaapi / qa / QAAPI.py
1 import sys, os
2 import traceback
3 import tests
4 from Config import Config
5 from logger import log  
6
7 class QAAPI:
8    
9     tests_path = os.path.realpath(tests.__path__[0])
10     methods = []
11                 
12         
13     def __init__(self, globals, config = None, logging=None, verbose=None):
14         if config is None: self.config = Config()
15         else: self.config = Config(config)
16
17         test_files = self.test_files(self.tests_path)
18         callables = set()
19         # determine what is callable
20         for file in test_files:
21             tests = self.callables(file)
22             tests = filter(lambda t: t.test_name not in ['Test'], tests)
23             callables.update(tests)
24                 
25         # Add methods to self and global environemt     
26         for method in callables:
27             if logging: method = log(method, method.test_name)
28             elif hasattr(self.config, 'log') and self.config.log:
29                 method = log(method, method.test_name)
30             class Dummy: pass
31             paths = method.test_name.split(".")
32             
33             if len(paths) > 1:
34                 first = paths.pop(0)
35
36                 if not hasattr(self, first):
37                     obj = Dummy()
38                     setattr(self, first, obj)
39                     # Also add to global environment if specified
40                     if globals is not None:
41                         globals[first] = obj
42
43                 obj = getattr(self, first)
44
45                 for path in paths:
46                     if not hasattr(obj, path):
47                         if path == paths[-1]:
48                             setattr(obj, path, method)
49                             globals[method.test_name]=obj  
50                         else:
51                             setattr(obj, path, Dummy())
52                     obj = getattr(obj, path)
53             else:
54                 if globals is not None:
55                     globals[method.test_name] = method          
56
57     def test_files(self, tests_dir):
58         """
59         Build a list of files   
60         """     
61         
62         # Load files from tests direcotry
63         real_files = lambda name: not name.startswith('__init__') \
64                                   and  name.endswith('.py')
65         remove_ext = lambda name: name.split(".py")[0]
66         iterator = os.walk(tests_dir)
67         (root, basenames, files) = iterator.next()
68         test_base = ""
69         test_files = []
70         test_files.extend([test_base+file for file in map(remove_ext, filter(real_files, files))])
71         
72         # recurse through directory             
73         for (root, dirs, files) in iterator:
74             parts = root.split(os.sep)
75             for basename in basenames:
76                 if basename in parts:
77                     test_base = ".".join(parts[parts.index(basename):])+"."
78             files = filter(real_files, files)
79             files = map(remove_ext, files)
80             test_files.extend([test_base+file for file in  files])
81         return list(set(test_files)) 
82
83     def callables(self, test_file):
84         """
85         Return a new instance of the specified method. 
86         """      
87         
88         # Get new instance of method
89         parts = test_file.split(".")
90         # add every part except for the last to name (filename)
91         tests_dir =  "tests."
92         test_basename = ".".join(parts[:-1])
93         if test_basename: test_basename += '.'
94         test_path = tests_dir + test_file
95         try:
96             test = __import__(test_path, globals(), locals(), test_path)
97             callables = []
98
99             for attribute in dir(test):
100                 attr = getattr(test, attribute)
101                 if callable(attr) and hasattr(attr, 'status'):
102                     setattr(attr, 'test_name', test_basename+attribute)
103                     callables.append(attr(self.config))
104             return callables 
105         except ImportError, AttributeError:
106             raise  
107          
108