##// END OF EJS Templates
tests: address PytestDeprecationWarning for @pytest.yield_fixture...
Mads Kiilerich -
r8785:92653a85 stable
parent child Browse files
Show More
@@ -1,216 +1,216 b''
1 import logging
1 import logging
2 import os
2 import os
3 import sys
3 import sys
4 import time
4 import time
5
5
6 import formencode
6 import formencode
7 import pkg_resources
7 import pkg_resources
8 import pytest
8 import pytest
9 from paste.deploy import loadwsgi
9 from paste.deploy import loadwsgi
10 from pytest_localserver.http import WSGIServer
10 from pytest_localserver.http import WSGIServer
11 from routes.util import URLGenerator
11 from routes.util import URLGenerator
12 from tg.util.webtest import test_context
12 from tg.util.webtest import test_context
13
13
14 import kallithea.tests.base # FIXME: needed for setting testapp instance!!!
14 import kallithea.tests.base # FIXME: needed for setting testapp instance!!!
15 from kallithea.controllers.root import RootController
15 from kallithea.controllers.root import RootController
16 from kallithea.lib import inifile
16 from kallithea.lib import inifile
17 from kallithea.lib.utils import repo2db_mapper
17 from kallithea.lib.utils import repo2db_mapper
18 from kallithea.model import db, meta
18 from kallithea.model import db, meta
19 from kallithea.model.scm import ScmModel
19 from kallithea.model.scm import ScmModel
20 from kallithea.model.user import UserModel
20 from kallithea.model.user import UserModel
21 from kallithea.tests.base import TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS, TEST_USER_REGULAR_LOGIN, TESTS_TMP_PATH, invalidate_all_caches
21 from kallithea.tests.base import TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS, TEST_USER_REGULAR_LOGIN, TESTS_TMP_PATH, invalidate_all_caches
22 from kallithea.tests.fixture import create_test_env, create_test_index
22 from kallithea.tests.fixture import create_test_env, create_test_index
23
23
24
24
25 def pytest_configure():
25 def pytest_configure():
26 os.environ['TZ'] = 'UTC'
26 os.environ['TZ'] = 'UTC'
27 if not kallithea.is_windows:
27 if not kallithea.is_windows:
28 time.tzset() # only available on Unix
28 time.tzset() # only available on Unix
29
29
30 path = os.getcwd()
30 path = os.getcwd()
31 sys.path.insert(0, path)
31 sys.path.insert(0, path)
32 pkg_resources.working_set.add_entry(path)
32 pkg_resources.working_set.add_entry(path)
33
33
34 # Disable INFO logging of test database creation, restore with NOTSET
34 # Disable INFO logging of test database creation, restore with NOTSET
35 logging.disable(logging.INFO)
35 logging.disable(logging.INFO)
36
36
37 ini_settings = {
37 ini_settings = {
38 '[server:main]': {
38 '[server:main]': {
39 'port': '4999',
39 'port': '4999',
40 },
40 },
41 '[app:main]': {
41 '[app:main]': {
42 'ssh_enabled': 'true',
42 'ssh_enabled': 'true',
43 # Mainly to safeguard against accidentally overwriting the real one:
43 # Mainly to safeguard against accidentally overwriting the real one:
44 'ssh_authorized_keys': os.path.join(TESTS_TMP_PATH, 'authorized_keys'),
44 'ssh_authorized_keys': os.path.join(TESTS_TMP_PATH, 'authorized_keys'),
45 #'ssh_locale': 'C',
45 #'ssh_locale': 'C',
46 'app_instance_uuid': 'test',
46 'app_instance_uuid': 'test',
47 'show_revision_number': 'true',
47 'show_revision_number': 'true',
48 'session.secret': '{74e0cd75-b339-478b-b129-07dd221def1f}',
48 'session.secret': '{74e0cd75-b339-478b-b129-07dd221def1f}',
49 #'i18n.lang': '',
49 #'i18n.lang': '',
50 },
50 },
51 '[handler_console]': {
51 '[handler_console]': {
52 'formatter': 'color_formatter',
52 'formatter': 'color_formatter',
53 },
53 },
54 # The 'handler_console_sql' block is very similar to the one in
54 # The 'handler_console_sql' block is very similar to the one in
55 # development.ini, but without the explicit 'level=DEBUG' setting:
55 # development.ini, but without the explicit 'level=DEBUG' setting:
56 # it causes duplicate sqlalchemy debug logs, one through
56 # it causes duplicate sqlalchemy debug logs, one through
57 # handler_console_sql and another through another path.
57 # handler_console_sql and another through another path.
58 '[handler_console_sql]': {
58 '[handler_console_sql]': {
59 'formatter': 'color_formatter_sql',
59 'formatter': 'color_formatter_sql',
60 },
60 },
61 }
61 }
62 create_database = os.environ.get('TEST_DB') # TODO: rename to 'CREATE_TEST_DB'
62 create_database = os.environ.get('TEST_DB') # TODO: rename to 'CREATE_TEST_DB'
63 if create_database:
63 if create_database:
64 ini_settings['[app:main]']['sqlalchemy.url'] = create_database
64 ini_settings['[app:main]']['sqlalchemy.url'] = create_database
65 reuse_database = os.environ.get('REUSE_TEST_DB')
65 reuse_database = os.environ.get('REUSE_TEST_DB')
66 if reuse_database:
66 if reuse_database:
67 ini_settings['[app:main]']['sqlalchemy.url'] = reuse_database
67 ini_settings['[app:main]']['sqlalchemy.url'] = reuse_database
68
68
69 test_ini_file = os.path.join(TESTS_TMP_PATH, 'test.ini')
69 test_ini_file = os.path.join(TESTS_TMP_PATH, 'test.ini')
70 inifile.create(test_ini_file, None, ini_settings)
70 inifile.create(test_ini_file, None, ini_settings)
71
71
72 context = loadwsgi.loadcontext(loadwsgi.APP, 'config:%s' % test_ini_file)
72 context = loadwsgi.loadcontext(loadwsgi.APP, 'config:%s' % test_ini_file)
73
73
74 # set KALLITHEA_NO_TMP_PATH=1 to disable re-creating the database and test repos
74 # set KALLITHEA_NO_TMP_PATH=1 to disable re-creating the database and test repos
75 if not int(os.environ.get('KALLITHEA_NO_TMP_PATH', 0)):
75 if not int(os.environ.get('KALLITHEA_NO_TMP_PATH', 0)):
76 create_test_env(TESTS_TMP_PATH, context.config(), reuse_database=bool(reuse_database))
76 create_test_env(TESTS_TMP_PATH, context.config(), reuse_database=bool(reuse_database))
77
77
78 # set KALLITHEA_WHOOSH_TEST_DISABLE=1 to disable whoosh index during tests
78 # set KALLITHEA_WHOOSH_TEST_DISABLE=1 to disable whoosh index during tests
79 if not int(os.environ.get('KALLITHEA_WHOOSH_TEST_DISABLE', 0)):
79 if not int(os.environ.get('KALLITHEA_WHOOSH_TEST_DISABLE', 0)):
80 create_test_index(TESTS_TMP_PATH, context.config(), True)
80 create_test_index(TESTS_TMP_PATH, context.config(), True)
81
81
82 kallithea.tests.base.testapp = context.create()
82 kallithea.tests.base.testapp = context.create()
83 # do initial repo scan
83 # do initial repo scan
84 repo2db_mapper(ScmModel().repo_scan(TESTS_TMP_PATH))
84 repo2db_mapper(ScmModel().repo_scan(TESTS_TMP_PATH))
85
85
86 logging.disable(logging.NOTSET)
86 logging.disable(logging.NOTSET)
87
87
88 kallithea.tests.base.url = URLGenerator(RootController().mapper, {'HTTP_HOST': 'example.com'})
88 kallithea.tests.base.url = URLGenerator(RootController().mapper, {'HTTP_HOST': 'example.com'})
89
89
90 # set fixed language for form messages, regardless of environment settings
90 # set fixed language for form messages, regardless of environment settings
91 formencode.api.set_stdtranslation(languages=[])
91 formencode.api.set_stdtranslation(languages=[])
92
92
93
93
94 @pytest.fixture
94 @pytest.fixture
95 def create_test_user():
95 def create_test_user():
96 """Provide users that automatically disappear after test is over."""
96 """Provide users that automatically disappear after test is over."""
97 test_user_ids = []
97 test_user_ids = []
98
98
99 def _create_test_user(user_form):
99 def _create_test_user(user_form):
100 user = UserModel().create(user_form)
100 user = UserModel().create(user_form)
101 test_user_ids.append(user.user_id)
101 test_user_ids.append(user.user_id)
102 return user
102 return user
103 yield _create_test_user
103 yield _create_test_user
104 for user_id in test_user_ids:
104 for user_id in test_user_ids:
105 UserModel().delete(user_id)
105 UserModel().delete(user_id)
106 meta.Session().commit()
106 meta.Session().commit()
107
107
108
108
109 def _set_settings(*kvtseq):
109 def _set_settings(*kvtseq):
110 session = meta.Session()
110 session = meta.Session()
111 for kvt in kvtseq:
111 for kvt in kvtseq:
112 assert len(kvt) in (2, 3)
112 assert len(kvt) in (2, 3)
113 k = kvt[0]
113 k = kvt[0]
114 v = kvt[1]
114 v = kvt[1]
115 t = kvt[2] if len(kvt) == 3 else 'unicode'
115 t = kvt[2] if len(kvt) == 3 else 'unicode'
116 db.Setting.create_or_update(k, v, t)
116 db.Setting.create_or_update(k, v, t)
117 session.commit()
117 session.commit()
118
118
119
119
120 @pytest.fixture
120 @pytest.fixture
121 def set_test_settings():
121 def set_test_settings():
122 """Restore settings after test is over."""
122 """Restore settings after test is over."""
123 # Save settings.
123 # Save settings.
124 settings_snapshot = [
124 settings_snapshot = [
125 (s.app_settings_name, s.app_settings_value, s.app_settings_type)
125 (s.app_settings_name, s.app_settings_value, s.app_settings_type)
126 for s in db.Setting.query().all()]
126 for s in db.Setting.query().all()]
127 yield _set_settings
127 yield _set_settings
128 # Restore settings.
128 # Restore settings.
129 session = meta.Session()
129 session = meta.Session()
130 keys = frozenset(k for (k, v, t) in settings_snapshot)
130 keys = frozenset(k for (k, v, t) in settings_snapshot)
131 for s in db.Setting.query().all():
131 for s in db.Setting.query().all():
132 if s.app_settings_name not in keys:
132 if s.app_settings_name not in keys:
133 session.delete(s)
133 session.delete(s)
134 for k, v, t in settings_snapshot:
134 for k, v, t in settings_snapshot:
135 if t == 'list' and hasattr(v, '__iter__'):
135 if t == 'list' and hasattr(v, '__iter__'):
136 v = ','.join(v) # Quirk: must format list value manually.
136 v = ','.join(v) # Quirk: must format list value manually.
137 db.Setting.create_or_update(k, v, t)
137 db.Setting.create_or_update(k, v, t)
138 session.commit()
138 session.commit()
139
139
140
140
141 @pytest.fixture
141 @pytest.fixture
142 def auto_clear_ip_permissions():
142 def auto_clear_ip_permissions():
143 """Fixture that provides nothing but clearing IP permissions upon test
143 """Fixture that provides nothing but clearing IP permissions upon test
144 exit. This clearing is needed to avoid other test failing to make fake http
144 exit. This clearing is needed to avoid other test failing to make fake http
145 accesses."""
145 accesses."""
146 yield
146 yield
147 # cleanup
147 # cleanup
148 user_model = UserModel()
148 user_model = UserModel()
149
149
150 user_ids = []
150 user_ids = []
151 user_ids.append(kallithea.DEFAULT_USER_ID)
151 user_ids.append(kallithea.DEFAULT_USER_ID)
152 user_ids.append(db.User.get_by_username(TEST_USER_REGULAR_LOGIN).user_id)
152 user_ids.append(db.User.get_by_username(TEST_USER_REGULAR_LOGIN).user_id)
153
153
154 for user_id in user_ids:
154 for user_id in user_ids:
155 for ip in db.UserIpMap.query().filter(db.UserIpMap.user_id == user_id):
155 for ip in db.UserIpMap.query().filter(db.UserIpMap.user_id == user_id):
156 user_model.delete_extra_ip(user_id, ip.ip_id)
156 user_model.delete_extra_ip(user_id, ip.ip_id)
157
157
158 # IP permissions are cached, need to invalidate this cache explicitly
158 # IP permissions are cached, need to invalidate this cache explicitly
159 invalidate_all_caches()
159 invalidate_all_caches()
160 session = meta.Session()
160 session = meta.Session()
161 session.commit()
161 session.commit()
162
162
163
163
164 @pytest.fixture
164 @pytest.fixture
165 def test_context_fixture(app_fixture):
165 def test_context_fixture(app_fixture):
166 """
166 """
167 Encompass the entire test using this fixture in a test_context,
167 Encompass the entire test using this fixture in a test_context,
168 making sure that certain functionality still works even if no call to
168 making sure that certain functionality still works even if no call to
169 self.app.get/post has been made.
169 self.app.get/post has been made.
170 The typical error message indicating you need a test_context is:
170 The typical error message indicating you need a test_context is:
171 TypeError: No object (name: context) has been registered for this thread
171 TypeError: No object (name: context) has been registered for this thread
172
172
173 The standard way to fix this is simply using the test_context context
173 The standard way to fix this is simply using the test_context context
174 manager directly inside your test:
174 manager directly inside your test:
175 with test_context(self.app):
175 with test_context(self.app):
176 <actions>
176 <actions>
177 but if test setup code (xUnit-style or pytest fixtures) also needs to be
177 but if test setup code (xUnit-style or pytest fixtures) also needs to be
178 executed inside the test context, that method is not possible.
178 executed inside the test context, that method is not possible.
179 Even if there is no such setup code, the fixture may reduce code complexity
179 Even if there is no such setup code, the fixture may reduce code complexity
180 if the entire test needs to run inside a test context.
180 if the entire test needs to run inside a test context.
181
181
182 To apply this fixture (like any other fixture) to all test methods of a
182 To apply this fixture (like any other fixture) to all test methods of a
183 class, use the following class decorator:
183 class, use the following class decorator:
184 @pytest.mark.usefixtures("test_context_fixture")
184 @pytest.mark.usefixtures("test_context_fixture")
185 class TestFoo(TestController):
185 class TestFoo(TestController):
186 ...
186 ...
187 """
187 """
188 with test_context(app_fixture):
188 with test_context(app_fixture):
189 yield
189 yield
190
190
191
191
192 class MyWSGIServer(WSGIServer):
192 class MyWSGIServer(WSGIServer):
193 def repo_url(self, repo_name, username=TEST_USER_ADMIN_LOGIN, password=TEST_USER_ADMIN_PASS):
193 def repo_url(self, repo_name, username=TEST_USER_ADMIN_LOGIN, password=TEST_USER_ADMIN_PASS):
194 """Return URL to repo on this web server."""
194 """Return URL to repo on this web server."""
195 host, port = self.server_address
195 host, port = self.server_address
196 proto = 'http' if self._server.ssl_context is None else 'https'
196 proto = 'http' if self._server.ssl_context is None else 'https'
197 auth = ''
197 auth = ''
198 if username is not None:
198 if username is not None:
199 auth = username
199 auth = username
200 if password is not None:
200 if password is not None:
201 auth += ':' + password
201 auth += ':' + password
202 if auth:
202 if auth:
203 auth += '@'
203 auth += '@'
204 return '%s://%s%s:%s/%s' % (proto, auth, host, port, repo_name)
204 return '%s://%s%s:%s/%s' % (proto, auth, host, port, repo_name)
205
205
206
206
207 @pytest.yield_fixture(scope="session")
207 @pytest.fixture(scope="session")
208 def webserver():
208 def webserver():
209 """Start web server while tests are running.
209 """Start web server while tests are running.
210 Useful for debugging and necessary for vcs operation tests."""
210 Useful for debugging and necessary for vcs operation tests."""
211 server = MyWSGIServer(application=kallithea.tests.base.testapp)
211 server = MyWSGIServer(application=kallithea.tests.base.testapp)
212 server.start()
212 server.start()
213
213
214 yield server
214 yield server
215
215
216 server.stop()
216 server.stop()
General Comments 0
You need to be logged in to leave comments. Login now