[ADD] oe: provides sane (unfucked) command-line interface.
[odoo/odoo.git] / openerpcommand / run_tests.py
1 """
2 Execute the unittest2 tests available in OpenERP addons.
3 """
4
5 import os
6 import sys
7 import types
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     if submodule is None:
60         # Use auto-discovered sub-modules.
61         ms = submodules
62     elif submodule == '__fast_suite__':
63         # Obtain the explicit test sub-modules list.
64         ms = getattr(sys.modules[module], 'fast_suite', None)
65         # `suite` was used before the 6.1 release instead of `fast_suite`.
66         ms = ms if ms else getattr(sys.modules[module], 'suite', None)
67         if ms is None:
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 = getattr(sys.modules[module], 'checks', None)
75         if ms is None:
76             if explode:
77                 print 'The module `%s` has no defined sanity checks.' % (module,)
78                 show_submodules_and_exit()
79             else:
80                 ms = []
81     else:
82         # Pick the command-line-specified test sub-module.
83         m = getattr(sys.modules[module], submodule, None)
84         ms = [m]
85
86         if m is None:
87             if explode:
88                 print 'The module `%s` has no submodule named `%s`.' % \
89                     (module, submodule)
90                 show_submodules_and_exit()
91             else:
92                 ms = []
93
94     return ms
95
96 def run(args):
97     import unittest2
98
99     import openerp
100
101     config = openerp.tools.config
102     config['db_name'] = args.database
103     if args.port:
104         config['xmlrpc_port'] = int(args.port)
105     config['admin_passwd'] = 'admin'
106     config['db_password'] = 'a2aevl8w' # TODO from .openerpserverrc
107     config['addons_path'] = args.addons.replace(':',',')
108     if args.addons:
109         args.addons = args.addons.split(':')
110     else:
111         args.addons = []
112     if args.sanity_checks and args.fast_suite:
113         print 'Only at most one of `--sanity-checks` and `--fast-suite` ' \
114             'can be specified.'
115         sys.exit(1)
116
117     import logging
118     openerp.netsvc.init_alternative_logger()
119     logging.getLogger('openerp').setLevel(logging.CRITICAL)
120
121     # Install the import hook, to import openerp.addons.<module>.
122     openerp.modules.module.initialize_sys_path()
123     openerp.modules.loading.open_openerp_namespace()
124
125     # Extract module, submodule from the command-line args.
126     if args.module is None:
127         module, submodule = None, None
128     else:
129         splitted = args.module.split('.')
130         if len(splitted) == 1:
131             module, submodule = splitted[0], None
132         elif len(splitted) == 2:
133             module, submodule = splitted
134         else:
135             print 'The `module` argument must have the form ' \
136                 '`module[.submodule]`.'
137             sys.exit(1)
138
139     # Import the necessary modules and get the corresponding suite.
140     if module is None:
141         # TODO
142         modules = common.get_addons_from_paths(args.addons, []) # TODO openerp.addons.base is not included ?
143         test_modules = []
144         for module in ['openerp'] + modules:
145             if args.fast_suite:
146                 submodule = '__fast_suite__'
147             if args.sanity_checks:
148                 submodule = '__sanity_checks__'
149             test_modules.extend(get_test_modules(module,
150                 submodule, explode=False))
151     else:
152         if submodule and args.fast_suite:
153             print "Submodule name `%s` given, ignoring `--fast-suite`." % (submodule,)
154         if submodule and args.sanity_checks:
155             print "Submodule name `%s` given, ignoring `--sanity-checks`." % (submodule,)
156         if not submodule and args.fast_suite:
157             submodule = '__fast_suite__'
158         if not submodule and args.sanity_checks:
159             submodule = '__sanity_checks__'
160         test_modules = get_test_modules(module,
161             submodule, explode=True)
162
163     # Run the test suite.
164     if not args.dry_run:
165         suite = unittest2.TestSuite()
166         for test_module in test_modules:
167             suite.addTests(unittest2.TestLoader().loadTestsFromModule(test_module))
168         r = unittest2.TextTestRunner(verbosity=2).run(suite)
169         if r.errors or r.failures:
170             sys.exit(1)
171     else:
172         print 'Test modules:'
173         for test_module in test_modules:
174             print ' ', test_module.__name__
175
176 def add_parser(subparsers):
177     parser = subparsers.add_parser('run-tests',
178         description='Run the OpenERP server and/or addons tests.')
179     parser.add_argument('-d', '--database', metavar='DATABASE', required=True,
180         help='the database to test. Depending on the test suites, the '
181         'database must already exist or not.')
182     parser.add_argument('-p', '--port', metavar='PORT',
183         help='the port used for WML-RPC tests')
184     common.add_addons_argument(parser)
185     parser.add_argument('-m', '--module', metavar='MODULE',
186         default=None,
187         help='the module to test in `module[.submodule]` notation. '
188         'Use `openerp` for the core OpenERP tests. '
189         'Leave empty to run every declared tests. '
190         'Give a module but no submodule to run all the module\'s declared '
191         'tests. If both the module and the submodule are given, '
192         'the sub-module can be run even if it is not declared in the module.')
193     parser.add_argument('--fast-suite', action='store_true',
194         help='run only the tests explicitely declared in the fast suite (this '
195         'makes sense only with the bare `module` notation or no module at '
196         'all).')
197     parser.add_argument('--sanity-checks', action='store_true',
198         help='run only the sanity check tests')
199     parser.add_argument('--dry-run', action='store_true',
200         help='do not run the tests')
201
202     parser.set_defaults(run=run)