Refactoring: Changed all check parameters starting with an 'o' to the new rulespec...
[check_mk.git] / tests / conftest.py
blob14a357abaee47601d6eae9a368dacd9f573facf5
1 # This file initializes the py.test environment
3 import pytest
4 # TODO: Can we somehow push some of the registrations below to the subdirectories?
5 pytest.register_assert_rewrite(
6 "testlib", #
7 "unit.checks.checktestlib", #
8 "unit.checks.generictests.run", #
9 "unit.cmk.gui.old.html_tests", #
10 "unit.cmk.gui.tools")
12 import _pytest.monkeypatch
13 import re
14 import collections
15 import errno
16 import os
17 import pwd
18 import shutil
19 import sys
20 import tempfile
21 import testlib
24 # Each test is of one of the following types.
26 # The tests are marked using the marker pytest.marker.type("TYPE")
27 # which is added to the test automatically according to their location.
29 # With each call to py.test one type of tests needs to be selected using
30 # the "-T TYPE" option. Only these tests will then be executed. Tests of
31 # the other type will be skipped.
34 EXECUTE_IN_SITE, EXECUTE_IN_VENV = True, False
36 test_types = collections.OrderedDict([
37 ("unit", EXECUTE_IN_VENV),
38 ("pylint", EXECUTE_IN_VENV),
39 ("docker", EXECUTE_IN_VENV),
40 ("integration", EXECUTE_IN_SITE),
41 ("gui_crawl", EXECUTE_IN_SITE),
42 ("packaging", EXECUTE_IN_VENV),
46 def pytest_addoption(parser):
47 """Register the -T option to pytest"""
48 options = [name for opt in parser._anonymous.options for name in opt.names()]
49 # conftest.py is symlinked from enterprise/tests/conftest.py which makes it being executed
50 # twice. Only register this option once.
51 if "-T" in options:
52 return
54 parser.addoption(
55 "-T",
56 action="store",
57 metavar="TYPE",
58 default=None,
59 help="Run tests of the given TYPE. Available types are: %s" % ", ".join(test_types.keys()))
62 def pytest_configure(config):
63 """Register the type marker to pytest"""
64 config.addinivalue_line(
65 "markers", "type(TYPE): Mark TYPE of test. Available: %s" % ", ".join(test_types.keys()))
68 def pytest_collection_modifyitems(items):
69 """Mark collected test types based on their location"""
70 for item in items:
71 type_marker = item.get_closest_marker("type")
72 if type_marker and type_marker.args:
73 continue # Do not modify manually set marks
75 file_path = "%s" % item.reportinfo()[0]
76 if "tests/unit" in file_path:
77 ty = "unit"
78 elif "tests/git" in file_path:
79 ty = "unit"
80 elif "tests/packaging" in file_path:
81 ty = "packaging"
82 elif "tests/pylint" in file_path:
83 ty = "pylint"
84 elif "tests/docker" in file_path:
85 ty = "docker"
86 elif "tests/integration" in file_path:
87 ty = "integration"
88 else:
89 raise Exception("Test not TYPE marked: %r" % item)
91 item.add_marker(pytest.mark.type.with_args(ty))
94 def pytest_runtest_setup(item):
95 """Skip tests of unwanted types"""
96 testlib.skip_unwanted_test_types(item)
99 # Some cmk.* code is calling things like cmk. is_raw_edition() at import time
100 # (e.g. cmk_base/default_config/notify.py) for edition specific variable
101 # defaults. In integration tests we want to use the exact version of the
102 # site. For unit tests we assume we are in Enterprise Edition context.
103 def fake_version_and_paths():
104 if is_running_as_site_user():
105 return
107 monkeypatch = _pytest.monkeypatch.MonkeyPatch()
108 tmp_dir = tempfile.mkdtemp(prefix="pytest_cmk_")
110 import cmk
111 monkeypatch.setattr(cmk, "omd_version", lambda: "%s.cee" % cmk.__version__)
113 monkeypatch.setattr("cmk.utils.paths.checks_dir", "%s/checks" % cmk_path())
114 monkeypatch.setattr("cmk.utils.paths.notifications_dir", "%s/notifications" % cmk_path())
115 monkeypatch.setattr("cmk.utils.paths.inventory_dir", "%s/inventory" % cmk_path())
116 monkeypatch.setattr("cmk.utils.paths.check_manpages_dir", "%s/checkman" % cmk_path())
117 monkeypatch.setattr("cmk.utils.paths.tmp_dir", tmp_dir)
118 monkeypatch.setattr("cmk.utils.paths.precompiled_checks_dir",
119 os.path.join(tmp_dir, "var/check_mk/precompiled_checks"))
120 monkeypatch.setattr("cmk.utils.paths.include_cache_dir",
121 os.path.join(tmp_dir, "check_mk/check_includes"))
124 # Cleanup temporary directory created above
125 @pytest.fixture(scope="session", autouse=True)
126 def cleanup_cmk():
127 yield
129 if is_running_as_site_user():
130 return
132 import cmk.utils.paths
134 if "pytest_cmk_" not in cmk.utils.paths.tmp_dir:
135 return
137 try:
138 shutil.rmtree(cmk.utils.paths.tmp_dir)
139 except OSError as exc:
140 if exc.errno != errno.ENOENT:
141 raise # re-raise exception
144 def cmk_path():
145 return os.path.dirname(os.path.dirname(__file__))
148 def cmc_path():
149 return os.path.realpath(cmk_path() + "/enterprise")
152 def cme_path():
153 return os.path.realpath(cmk_path() + "/managed")
156 def add_python_paths():
157 # make the testlib available to the test modules
158 sys.path.insert(0, os.path.dirname(__file__))
159 # make the repo directory available (cmk lib)
160 sys.path.insert(0, cmk_path())
162 # if not running as site user, make the livestatus module available
163 if not is_running_as_site_user():
164 sys.path.insert(0, os.path.join(cmk_path(), "livestatus/api/python"))
165 sys.path.insert(0, os.path.join(cmk_path(), "omd/packages/omd"))
168 def pytest_cmdline_main(config):
169 """There are 2 environments for testing:
171 * A real Check_MK site environment (e.g. integration tests)
172 * Python virtual environment (e.g. for unit tests)
174 Depending on the selected "type" marker the environment is ensured
175 or switched here."""
176 if not config.getoption("-T"):
177 return # missing option is handled later
179 context = test_types[config.getoption("-T")]
180 if context == EXECUTE_IN_SITE:
181 setup_site_and_switch_user()
182 else:
183 verify_virtualenv()
186 def verify_virtualenv():
187 if not testlib.virtualenv_path():
188 raise SystemExit("ERROR: Please load virtual environment first "
189 "(Use \"pipenv shell\" or configure direnv)")
192 def is_running_as_site_user():
193 return pwd.getpwuid(os.getuid()).pw_name == _site_id()
196 def setup_site_and_switch_user():
197 if is_running_as_site_user():
198 return # This is executed as site user. Nothing to be done.
200 sys.stdout.write("===============================================\n")
201 sys.stdout.write("Setting up site '%s'\n" % _site_id())
202 sys.stdout.write("===============================================\n")
204 site = _get_site_object()
206 cleanup_pattern = os.environ.get("CLEANUP_OLD")
207 if cleanup_pattern:
208 site.cleanup_old_sites(cleanup_pattern)
210 site.cleanup_if_wrong_version()
211 site.create()
212 #site.open_livestatus_tcp()
213 site.start()
214 site.prepare_for_tests()
216 sys.stdout.write("===============================================\n")
217 sys.stdout.write("Switching to site context\n")
218 sys.stdout.write("===============================================\n")
219 sys.stdout.flush()
221 exit_code = site.switch_to_site_user()
223 sys.stdout.write("===============================================\n")
224 sys.stdout.write("Cleaning up after testing\n")
225 sys.stdout.write("===============================================\n")
227 #site.rm_if_not_reusing()
228 sys.exit(exit_code)
231 def _get_site_object():
232 def site_version():
233 return os.environ.get("VERSION", testlib.CMKVersion.DAILY)
235 def site_edition():
236 return os.environ.get("EDITION", testlib.CMKVersion.CEE)
238 def site_branch():
239 return os.environ.get("BRANCH", testlib.current_branch_name())
241 def reuse_site():
242 return os.environ.get("REUSE", "1") == "1"
244 return testlib.Site(
245 site_id=_site_id(),
246 version=site_version(),
247 edition=site_edition(),
248 reuse=reuse_site(),
249 branch=site_branch())
252 def _site_id():
253 site_id = os.environ.get("OMD_SITE")
254 if site_id is not None:
255 return site_id
257 branch_name = os.environ.get("BRANCH", testlib.current_branch_name())
258 # Split by / and get last element, remove unwanted chars
259 branch_part = re.sub("[^a-zA-Z0-9_]", "", branch_name.split("/")[-1])
260 site_id = "int_%s" % branch_part
262 os.putenv("OMD_SITE", site_id)
263 return site_id
267 # MAIN
270 add_python_paths()
271 fake_version_and_paths()
274 # Session fixtures must be in conftest.py to work properly
275 @pytest.fixture(scope="session", autouse=True)
276 def site(request):
277 return _get_site_object()