[FIX] gamification: correct name of ir.rule fixing bad copy-paste
[odoo/odoo.git] / openerpcommand / run_tests.py
1 """
2 Execute the unittest2 tests available in OpenERP addons.
3 """
4
5 import sys
6 import types
7 import argparse
8
9 import common
10
11 def get_test_modules(module, submodule, explode):
12     """
13     Return a list of submodules containing tests.
14     `submodule` can be:
15       - None
16       - the name of a submodule
17       - '__fast_suite__'
18       - '__sanity_checks__'
19     """
20     # Turn command-line module, submodule into importable names.
21     if module is None:
22         pass
23     elif module == 'openerp':
24         module = 'openerp.tests'
25     else:
26         module = 'openerp.addons.' + module + '.tests'
27
28     # Try to import the module
29     try:
30         __import__(module)
31     except Exception, e:
32         if explode:
33             print 'Can not `import %s`.' % module
34             import logging
35             logging.exception('')
36             sys.exit(1)
37         else:
38             if str(e) == 'No module named tests':
39                 # It seems the module has no `tests` sub-module, no problem.
40                 pass
41             else:
42                 print 'Can not `import %s`.' % module
43             return []
44
45     # Discover available test sub-modules.
46     m = sys.modules[module]
47     submodule_names =  sorted([x for x in dir(m) \
48         if x.startswith('test_') and \
49         isinstance(getattr(m, x), types.ModuleType)])
50     submodules = [getattr(m, x) for x in submodule_names]
51
52     def show_submodules_and_exit():
53         if submodule_names:
54             print 'Available submodules are:'
55             for x in submodule_names:
56                 print ' ', x
57         sys.exit(1)
58
59     fast_suite = getattr(m, 'fast_suite', [])
60     checks = getattr(m, 'checks', [])
61     if submodule is None:
62         # Use auto-discovered sub-modules.
63         ms = submodules
64     elif submodule == '__fast_suite__':
65         # `suite` was used before the 6.1 release instead of `fast_suite`.
66         ms = fast_suite if hasattr(m, 'fast_suite') else getattr(m, 'suite', None)
67         if not ms:
68             if explode:
69                 print 'The module `%s` has no defined test suite.' % (module,)
70                 show_submodules_and_exit()
71             else:
72                 ms = []
73     elif submodule == '__sanity_checks__':
74         ms = checks
75         if not ms:
76             if explode:
77                 print 'The module `%s` has no defined sanity checks.' % (module,)
78                 show_submodules_and_exit()
79             else:
80                 ms = []
81     elif submodule == '__slow_suite__':
82         ms = list(set(submodules).difference(fast_suite, checks))
83     else:
84         # Pick the command-line-specified test sub-module.
85         m = getattr(m, submodule, None)
86         ms = [m]
87
88         if m is None:
89             if explode:
90                 print 'The module `%s` has no submodule named `%s`.' % \
91                     (module, submodule)
92                 show_submodules_and_exit()
93             else:
94                 ms = []
95
96     return ms
97
98 def run(args):
99     import unittest2
100
101     import openerp
102
103     config = openerp.tools.config
104     config.load()
105
106     config['db_name'] = args.database
107     if args.port:
108         config['xmlrpc_port'] = int(args.port)
109
110     if args.addons:
111         args.addons = args.addons.replace(':',',').split(',')
112     else:
113         args.addons = []
114
115     # ensure no duplication in addons paths
116     args.addons = list(set(args.addons))
117     config['addons_path'] = ','.join(args.addons)
118
119     import logging
120     openerp.netsvc.init_alternative_logger()
121     logging.getLogger('openerp').setLevel(logging.CRITICAL)
122
123     # Install the import hook, to import openerp.addons.<module>.
124     openerp.modules.module.initialize_sys_path()
125
126     module = args.module
127     submodule = args.submodule
128
129     # Import the necessary modules and get the corresponding suite.
130     if module is None:
131         # TODO
132         modules = common.get_addons_from_paths(args.addons, []) # TODO openerp.addons.base is not included ?
133         test_modules = []
134         for module in ['openerp'] + modules:
135             test_modules.extend(
136                 get_test_modules(module, submodule, explode=False))
137     else:
138         test_modules = get_test_modules(module, submodule, explode=True)
139
140     print 'Test modules:'
141     for test_module in test_modules:
142         print '    ', test_module.__name__
143     print
144     sys.stdout.flush()
145
146     if not args.dry_run:
147         suite = unittest2.TestSuite()
148         for test_module in test_modules:
149             suite.addTests(unittest2.TestLoader().loadTestsFromModule(test_module))
150         r = unittest2.TextTestRunner(verbosity=2).run(suite)
151         if r.errors or r.failures:
152             sys.exit(1)
153
154 def add_parser(subparsers):
155     parser = subparsers.add_parser('run-tests',
156         description='Run the OpenERP server and/or addons tests.')
157     parser.add_argument('-d', '--database', metavar='DATABASE', required=True,
158         help='the database to test. Depending on the test suites, the '
159         'database must already exist or not.')
160     parser.add_argument('-p', '--port', metavar='PORT',
161         help='the port used for WML-RPC tests')
162     common.add_addons_argument(parser)
163
164     parser.add_argument(
165         '-m', '--module', metavar='MODULE', action=ModuleAction, default=None,
166         help="the module to test in `module[.submodule]` notation. "
167              "Use `openerp` for the core OpenERP tests. "
168              "Leave empty to run every declared tests. "
169              "Give a module but no submodule to run all the module's declared "
170              "tests. If both the module and the submodule are given, "
171              "the sub-module can be run even if it is not declared in the module.")
172     group = parser.add_mutually_exclusive_group()
173     group.add_argument(
174         '--fast-suite',
175         dest='submodule', action=GuardAction, nargs=0, const='__fast_suite__',
176         help='run only the tests explicitly declared in the fast suite (this '
177         'makes sense only with the bare `module` notation or no module at '
178         'all).')
179     group.add_argument(
180         '--sanity-checks',
181         dest='submodule', action=GuardAction, nargs=0, const='__sanity_checks__',
182         help='run only the sanity check tests')
183     group.add_argument(
184         '--slow-suite',
185         dest='submodule', action=GuardAction, nargs=0, const='__slow_suite__',
186         help="Only run slow tests (tests which are neither in the fast nor in"
187              " the sanity suite)")
188     parser.add_argument('--dry-run', action='store_true',
189         help='do not run the tests')
190
191     parser.set_defaults(run=run, submodule=None)
192
193 class ModuleAction(argparse.Action):
194     def __call__(self, parser, namespace, values, option_string=None):
195         split = values.split('.')
196         if len(split) == 1:
197             module, submodule = values, None
198         elif len(split) == 2:
199             module, submodule = split
200         else:
201             raise argparse.ArgumentError(
202                 option_string,
203                 "must have the form 'module[.submodule]', got '%s'" % values)
204
205         setattr(namespace, self.dest, module)
206         if submodule is not None:
207             setattr(namespace, 'submodule', submodule)
208
209 class GuardAction(argparse.Action):
210     def __call__(self, parser, namespace, values, option_string=None):
211         if getattr(namespace, self.dest, None):
212             print "%s value provided, ignoring '%s'" % (self.dest, option_string)
213             return
214         setattr(namespace, self.dest, self.const)