forked from camptocamp/pytest-odoo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpytest_odoo.py
190 lines (161 loc) · 7.1 KB
/
pytest_odoo.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# -*- coding: utf-8 -*-
# Copyright 2016 Camptocamp SA
# Copyright 2015 Odoo
# License AGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html)
import pytest
import signal
import os
import sys
import _pytest
import _pytest.python
import py.code
import py.error
import py.path
import threading
try:
import openerp
odoo = openerp
odoo_namespace = 'openerp'
except ImportError: # Odoo >= 10.0
import odoo # noqa
odoo_namespace = 'odoo'
def pytest_addoption(parser):
parser.addoption("--odoo-database",
action="store",
help="Name of the Odoo database to test")
parser.addoption("--odoo-log-level",
action="store",
default='critical',
help="Log-level used by the Odoo process during tests")
@pytest.hookimpl(hookwrapper=True)
def pytest_cmdline_main(config):
if (config.getoption('--odoo-database')
or os.environ.get('OPENERP_SERVER')
or os.environ.get('ODOO_RC')):
options = []
# Replace --odoo-<something> by --<something> and prepare the argument
# to propagate to odoo.
for option in ['--odoo-database', '--odoo-log-level']:
value = config.getoption(option)
if value:
odoo_arg = '--%s' % option[7:]
options.append('%s=%s' % (odoo_arg, value))
odoo.tools.config.parse_config(options)
if not odoo.tools.config['db_name']:
# if you fall here, it means you have OPENERP_SERVER pointing
# to a configuration file without 'database' configuration
raise Exception(
"please provide a database name in the Odoo configuration file"
)
odoo.service.server.start(preload=[], stop=True)
# odoo.service.server.start() modifies the SIGINT signal by its own
# one which in fact prevents us to stop anthem with Ctrl-c.
# Restore the default one.
signal.signal(signal.SIGINT, signal.default_int_handler)
with odoo.api.Environment.manage():
yield
else:
yield
@pytest.fixture(scope='session', autouse=True)
def load_registry():
# Initialize the registry before running tests.
# If we don't do that, the modules will be loaded *inside* of the first
# test we run, which would trigger the launch of the postinstall tests
# (because we force 'test_enable' to True and the at end of the loading of
# the registry, the postinstall tests are run when test_enable is enabled).
# And also give wrong timing indications.
# Finally we enable `testing` flag on current thread
# since Odoo sets it when loading test suites.
threading.currentThread().testing = True
odoo.registry(odoo.tests.common.get_db_name())
@pytest.fixture(scope='module', autouse=True)
def enable_odoo_test_flag():
# When we run tests through Odoo, test_enable is always activated, and some
# code might rely on this (for instance to selectively disable database
# commits). When we run the tests through pytest, the flag is not
# activated, and if it was activated globally, it would make odoo start all
# tests in addition to the tests we are running through pytest. If we
# enable the option only in the scope of the tests modules, we won't
# interfere with the odoo's loading of modules, thus we are good.
odoo.tools.config['test_enable'] = True
yield
odoo.tools.config['test_enable'] = False
# Original code of xmo-odoo:
# https://github.com/odoo-dev/odoo/commit/95a131b7f4eebc6e2c623f936283153d62f9e70f
class OdooTestModule(_pytest.python.Module):
""" Should only be invoked for paths inside Odoo addons
"""
def _importtestmodule(self):
# copy/paste/modified from original: removed sys.path injection &
# added Odoo module prefixing so import within modules is correct
try:
pypkgpath = self.fspath.pypkgpath()
pkgroot = pypkgpath.dirpath()
sep = self.fspath.sep
names = self.fspath.new(ext="").relto(pkgroot).split(sep)
if names[-1] == "__init__":
names.pop()
modname = ".".join(names)
# modules installed with pip for odoo<=9 are into the
# odoo_addons namespace. Makes module part of the odoo namespace
if modname.startswith('odoo_addons'):
modname = odoo_namespace + '.addons.' + modname.replace(
'odoo_addons.', '')
# for modules in openerp/addons, since there is a __init__ the
# module name is already fully qualified (maybe?)
if (not modname.startswith(odoo_namespace + '.addons.')
and modname != odoo_namespace + '.addons'
and modname != odoo_namespace):
modname = odoo_namespace + '.addons.' + modname
__import__(modname)
mod = sys.modules[modname]
if self.fspath.basename == "__init__.py":
# we don't check anything as we might
# we in a namespace package ... too icky to check
return mod
modfile = mod.__file__
if modfile[-4:] in ('.pyc', '.pyo'):
modfile = modfile[:-1]
elif modfile.endswith('$py.class'):
modfile = modfile[:-9] + '.py'
if modfile.endswith(os.path.sep + "__init__.py"):
if self.fspath.basename != "__init__.py":
modfile = modfile[:-12]
try:
issame = self.fspath.samefile(modfile)
except py.error.ENOENT:
issame = False
if not issame:
raise self.fspath.ImportMismatchError(modname, modfile, self)
except SyntaxError:
raise self.CollectError(
py.code.ExceptionInfo().getrepr(style="short"))
except self.fspath.ImportMismatchError:
e = sys.exc_info()[1]
raise self.CollectError(
"import file mismatch:\n"
"imported module %r has this __file__ attribute:\n"
" %s\n"
"which is not the same as the test file we want to collect:\n"
" %s\n"
"HINT: remove __pycache__ / .pyc files and/or use a "
"unique basename for your test file modules" % e.args
)
self.config.pluginmanager.consider_module(mod)
return mod
def __repr__(self):
return "<Module %r>" % (getattr(self, "name", None), )
class OdooTestPackage(_pytest.python.Package, OdooTestModule):
"""Package with odoo module lookup.
Any python module inside the package will be imported with
the prefix `odoo.addons`.
This class is used to prevent loading odoo modules in duplicate,
which happens if a module is loaded with and without the prefix.
"""
def __repr__(self):
return "<Package %r>" % (getattr(self, "name", None), )
def pytest_pycollect_makemodule(path, parent):
if path.basename == "__init__.py":
return OdooTestPackage(path, parent)
else:
return OdooTestModule(path, parent)