##// END OF EJS Templates
tests: fixed starting of customized gunicorn with a explicit --bind call
super-admin -
r4976:6c82c462 default
parent child Browse files
Show More
@@ -1,285 +1,285 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2020 RhodeCode GmbH
3 # Copyright (C) 2010-2020 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import json
21 import json
22 import platform
22 import platform
23 import socket
23 import socket
24 import random
24 import random
25 import pytest
25 import pytest
26
26
27 from rhodecode.lib.pyramid_utils import get_app_config
27 from rhodecode.lib.pyramid_utils import get_app_config
28 from rhodecode.tests.fixture import TestINI
28 from rhodecode.tests.fixture import TestINI
29 from rhodecode.tests.server_utils import RcVCSServer
29 from rhodecode.tests.server_utils import RcVCSServer
30
30
31
31
32 def _parse_json(value):
32 def _parse_json(value):
33 return json.loads(value) if value else None
33 return json.loads(value) if value else None
34
34
35
35
36 def pytest_addoption(parser):
36 def pytest_addoption(parser):
37 parser.addoption(
37 parser.addoption(
38 '--test-loglevel', dest='test_loglevel',
38 '--test-loglevel', dest='test_loglevel',
39 help="Set default Logging level for tests, critical(default), error, warn , info, debug")
39 help="Set default Logging level for tests, critical(default), error, warn , info, debug")
40 group = parser.getgroup('pylons')
40 group = parser.getgroup('pylons')
41 group.addoption(
41 group.addoption(
42 '--with-pylons', dest='pyramid_config',
42 '--with-pylons', dest='pyramid_config',
43 help="Set up a Pylons environment with the specified config file.")
43 help="Set up a Pylons environment with the specified config file.")
44 group.addoption(
44 group.addoption(
45 '--ini-config-override', action='store', type=_parse_json,
45 '--ini-config-override', action='store', type=_parse_json,
46 default=None, dest='pyramid_config_override', help=(
46 default=None, dest='pyramid_config_override', help=(
47 "Overrides the .ini file settings. Should be specified in JSON"
47 "Overrides the .ini file settings. Should be specified in JSON"
48 " format, e.g. '{\"section\": {\"parameter\": \"value\", ...}}'"
48 " format, e.g. '{\"section\": {\"parameter\": \"value\", ...}}'"
49 )
49 )
50 )
50 )
51 parser.addini(
51 parser.addini(
52 'pyramid_config',
52 'pyramid_config',
53 "Set up a Pyramid environment with the specified config file.")
53 "Set up a Pyramid environment with the specified config file.")
54
54
55 vcsgroup = parser.getgroup('vcs')
55 vcsgroup = parser.getgroup('vcs')
56 vcsgroup.addoption(
56 vcsgroup.addoption(
57 '--without-vcsserver', dest='with_vcsserver', action='store_false',
57 '--without-vcsserver', dest='with_vcsserver', action='store_false',
58 help="Do not start the VCSServer in a background process.")
58 help="Do not start the VCSServer in a background process.")
59 vcsgroup.addoption(
59 vcsgroup.addoption(
60 '--with-vcsserver-http', dest='vcsserver_config_http',
60 '--with-vcsserver-http', dest='vcsserver_config_http',
61 help="Start the HTTP VCSServer with the specified config file.")
61 help="Start the HTTP VCSServer with the specified config file.")
62 vcsgroup.addoption(
62 vcsgroup.addoption(
63 '--vcsserver-protocol', dest='vcsserver_protocol',
63 '--vcsserver-protocol', dest='vcsserver_protocol',
64 help="Start the VCSServer with HTTP protocol support.")
64 help="Start the VCSServer with HTTP protocol support.")
65 vcsgroup.addoption(
65 vcsgroup.addoption(
66 '--vcsserver-config-override', action='store', type=_parse_json,
66 '--vcsserver-config-override', action='store', type=_parse_json,
67 default=None, dest='vcsserver_config_override', help=(
67 default=None, dest='vcsserver_config_override', help=(
68 "Overrides the .ini file settings for the VCSServer. "
68 "Overrides the .ini file settings for the VCSServer. "
69 "Should be specified in JSON "
69 "Should be specified in JSON "
70 "format, e.g. '{\"section\": {\"parameter\": \"value\", ...}}'"
70 "format, e.g. '{\"section\": {\"parameter\": \"value\", ...}}'"
71 )
71 )
72 )
72 )
73 vcsgroup.addoption(
73 vcsgroup.addoption(
74 '--vcsserver-port', action='store', type=int,
74 '--vcsserver-port', action='store', type=int,
75 default=None, help=(
75 default=None, help=(
76 "Allows to set the port of the vcsserver. Useful when testing "
76 "Allows to set the port of the vcsserver. Useful when testing "
77 "against an already running server and random ports cause "
77 "against an already running server and random ports cause "
78 "trouble."))
78 "trouble."))
79 parser.addini(
79 parser.addini(
80 'vcsserver_config_http',
80 'vcsserver_config_http',
81 "Start the HTTP VCSServer with the specified config file.")
81 "Start the HTTP VCSServer with the specified config file.")
82 parser.addini(
82 parser.addini(
83 'vcsserver_protocol',
83 'vcsserver_protocol',
84 "Start the VCSServer with HTTP protocol support.")
84 "Start the VCSServer with HTTP protocol support.")
85
85
86
86
87 @pytest.fixture(scope='session')
87 @pytest.fixture(scope='session')
88 def vcsserver(request, vcsserver_port, vcsserver_factory):
88 def vcsserver(request, vcsserver_port, vcsserver_factory):
89 """
89 """
90 Session scope VCSServer.
90 Session scope VCSServer.
91
91
92 Tests wich need the VCSServer have to rely on this fixture in order
92 Tests wich need the VCSServer have to rely on this fixture in order
93 to ensure it will be running.
93 to ensure it will be running.
94
94
95 For specific needs, the fixture vcsserver_factory can be used. It allows to
95 For specific needs, the fixture vcsserver_factory can be used. It allows to
96 adjust the configuration file for the test run.
96 adjust the configuration file for the test run.
97
97
98 Command line args:
98 Command line args:
99
99
100 --without-vcsserver: Allows to switch this fixture off. You have to
100 --without-vcsserver: Allows to switch this fixture off. You have to
101 manually start the server.
101 manually start the server.
102
102
103 --vcsserver-port: Will expect the VCSServer to listen on this port.
103 --vcsserver-port: Will expect the VCSServer to listen on this port.
104 """
104 """
105
105
106 if not request.config.getoption('with_vcsserver'):
106 if not request.config.getoption('with_vcsserver'):
107 return None
107 return None
108
108
109 return vcsserver_factory(
109 return vcsserver_factory(
110 request, vcsserver_port=vcsserver_port)
110 request, vcsserver_port=vcsserver_port)
111
111
112
112
113 @pytest.fixture(scope='session')
113 @pytest.fixture(scope='session')
114 def vcsserver_factory(tmpdir_factory):
114 def vcsserver_factory(tmpdir_factory):
115 """
115 """
116 Use this if you need a running vcsserver with a special configuration.
116 Use this if you need a running vcsserver with a special configuration.
117 """
117 """
118
118
119 def factory(request, overrides=(), vcsserver_port=None,
119 def factory(request, overrides=(), vcsserver_port=None,
120 log_file=None):
120 log_file=None):
121
121
122 if vcsserver_port is None:
122 if vcsserver_port is None:
123 vcsserver_port = get_available_port()
123 vcsserver_port = get_available_port()
124
124
125 overrides = list(overrides)
125 overrides = list(overrides)
126 overrides.append({'server:main': {'port': vcsserver_port}})
126 overrides.append({'server:main': {'port': vcsserver_port}})
127
127
128 option_name = 'vcsserver_config_http'
128 option_name = 'vcsserver_config_http'
129 override_option_name = 'vcsserver_config_override'
129 override_option_name = 'vcsserver_config_override'
130 config_file = get_config(
130 config_file = get_config(
131 request.config, option_name=option_name,
131 request.config, option_name=option_name,
132 override_option_name=override_option_name, overrides=overrides,
132 override_option_name=override_option_name, overrides=overrides,
133 basetemp=tmpdir_factory.getbasetemp().strpath,
133 basetemp=tmpdir_factory.getbasetemp().strpath,
134 prefix='test_vcs_')
134 prefix='test_vcs_')
135
135
136 server = RcVCSServer(config_file, log_file)
136 server = RcVCSServer(config_file, log_file)
137 server.start()
137 server.start()
138
138
139 @request.addfinalizer
139 @request.addfinalizer
140 def cleanup():
140 def cleanup():
141 server.shutdown()
141 server.shutdown()
142
142
143 server.wait_until_ready()
143 server.wait_until_ready()
144 return server
144 return server
145
145
146 return factory
146 return factory
147
147
148
148
149 def is_cygwin():
149 def is_cygwin():
150 return 'cygwin' in platform.system().lower()
150 return 'cygwin' in platform.system().lower()
151
151
152
152
153 def _use_log_level(config):
153 def _use_log_level(config):
154 level = config.getoption('test_loglevel') or 'critical'
154 level = config.getoption('test_loglevel') or 'critical'
155 return level.upper()
155 return level.upper()
156
156
157
157
158 @pytest.fixture(scope='session')
158 @pytest.fixture(scope='session')
159 def ini_config(request, tmpdir_factory, rcserver_port, vcsserver_port):
159 def ini_config(request, tmpdir_factory, rcserver_port, vcsserver_port):
160 option_name = 'pyramid_config'
160 option_name = 'pyramid_config'
161 log_level = _use_log_level(request.config)
161 log_level = _use_log_level(request.config)
162
162
163 overrides = [
163 overrides = [
164 {'server:main': {'port': rcserver_port}},
164 {'server:main': {'port': rcserver_port}},
165 {'app:main': {
165 {'app:main': {
166 'vcs.server': 'localhost:%s' % vcsserver_port,
166 'vcs.server': 'localhost:%s' % vcsserver_port,
167 # johbo: We will always start the VCSServer on our own based on the
167 # johbo: We will always start the VCSServer on our own based on the
168 # fixtures of the test cases. For the test run it must always be
168 # fixtures of the test cases. For the test run it must always be
169 # off in the INI file.
169 # off in the INI file.
170 'vcs.start_server': 'false',
170 'vcs.start_server': 'false',
171
171
172 'vcs.server.protocol': 'http',
172 'vcs.server.protocol': 'http',
173 'vcs.scm_app_implementation': 'http',
173 'vcs.scm_app_implementation': 'http',
174 'vcs.hooks.protocol': 'http',
174 'vcs.hooks.protocol': 'http',
175 'vcs.hooks.host': '127.0.0.1',
175 'vcs.hooks.host': '127.0.0.1',
176 }},
176 }},
177
177
178 {'handler_console': {
178 {'handler_console': {
179 'class ': 'StreamHandler',
179 'class': 'StreamHandler',
180 'args ': '(sys.stderr,)',
180 'args': '(sys.stderr,)',
181 'level': log_level,
181 'level': log_level,
182 }},
182 }},
183
183
184 ]
184 ]
185
185
186 filename = get_config(
186 filename = get_config(
187 request.config, option_name=option_name,
187 request.config, option_name=option_name,
188 override_option_name='{}_override'.format(option_name),
188 override_option_name='{}_override'.format(option_name),
189 overrides=overrides,
189 overrides=overrides,
190 basetemp=tmpdir_factory.getbasetemp().strpath,
190 basetemp=tmpdir_factory.getbasetemp().strpath,
191 prefix='test_rce_')
191 prefix='test_rce_')
192 return filename
192 return filename
193
193
194
194
195 @pytest.fixture(scope='session')
195 @pytest.fixture(scope='session')
196 def ini_settings(ini_config):
196 def ini_settings(ini_config):
197 ini_path = ini_config
197 ini_path = ini_config
198 return get_app_config(ini_path)
198 return get_app_config(ini_path)
199
199
200
200
201 def get_available_port(min_port=40000, max_port=55555):
201 def get_available_port(min_port=40000, max_port=55555):
202 from rhodecode.lib.utils2 import get_available_port as _get_port
202 from rhodecode.lib.utils2 import get_available_port as _get_port
203 return _get_port(min_port, max_port)
203 return _get_port(min_port, max_port)
204
204
205
205
206 @pytest.fixture(scope='session')
206 @pytest.fixture(scope='session')
207 def rcserver_port(request):
207 def rcserver_port(request):
208 port = get_available_port()
208 port = get_available_port()
209 print('Using rhodecode port {}'.format(port))
209 print('Using rhodecode port {}'.format(port))
210 return port
210 return port
211
211
212
212
213 @pytest.fixture(scope='session')
213 @pytest.fixture(scope='session')
214 def vcsserver_port(request):
214 def vcsserver_port(request):
215 port = request.config.getoption('--vcsserver-port')
215 port = request.config.getoption('--vcsserver-port')
216 if port is None:
216 if port is None:
217 port = get_available_port()
217 port = get_available_port()
218 print('Using vcsserver port {}'.format(port))
218 print('Using vcsserver port {}'.format(port))
219 return port
219 return port
220
220
221
221
222 @pytest.fixture(scope='session')
222 @pytest.fixture(scope='session')
223 def available_port_factory():
223 def available_port_factory():
224 """
224 """
225 Returns a callable which returns free port numbers.
225 Returns a callable which returns free port numbers.
226 """
226 """
227 return get_available_port
227 return get_available_port
228
228
229
229
230 @pytest.fixture()
230 @pytest.fixture()
231 def available_port(available_port_factory):
231 def available_port(available_port_factory):
232 """
232 """
233 Gives you one free port for the current test.
233 Gives you one free port for the current test.
234
234
235 Uses "available_port_factory" to retrieve the port.
235 Uses "available_port_factory" to retrieve the port.
236 """
236 """
237 return available_port_factory()
237 return available_port_factory()
238
238
239
239
240 @pytest.fixture(scope='session')
240 @pytest.fixture(scope='session')
241 def testini_factory(tmpdir_factory, ini_config):
241 def testini_factory(tmpdir_factory, ini_config):
242 """
242 """
243 Factory to create an INI file based on TestINI.
243 Factory to create an INI file based on TestINI.
244
244
245 It will make sure to place the INI file in the correct directory.
245 It will make sure to place the INI file in the correct directory.
246 """
246 """
247 basetemp = tmpdir_factory.getbasetemp().strpath
247 basetemp = tmpdir_factory.getbasetemp().strpath
248 return TestIniFactory(basetemp, ini_config)
248 return TestIniFactory(basetemp, ini_config)
249
249
250
250
251 class TestIniFactory(object):
251 class TestIniFactory(object):
252
252
253 def __init__(self, basetemp, template_ini):
253 def __init__(self, basetemp, template_ini):
254 self._basetemp = basetemp
254 self._basetemp = basetemp
255 self._template_ini = template_ini
255 self._template_ini = template_ini
256
256
257 def __call__(self, ini_params, new_file_prefix='test'):
257 def __call__(self, ini_params, new_file_prefix='test'):
258 ini_file = TestINI(
258 ini_file = TestINI(
259 self._template_ini, ini_params=ini_params,
259 self._template_ini, ini_params=ini_params,
260 new_file_prefix=new_file_prefix, dir=self._basetemp)
260 new_file_prefix=new_file_prefix, dir=self._basetemp)
261 result = ini_file.create()
261 result = ini_file.create()
262 return result
262 return result
263
263
264
264
265 def get_config(
265 def get_config(
266 config, option_name, override_option_name, overrides=None,
266 config, option_name, override_option_name, overrides=None,
267 basetemp=None, prefix='test'):
267 basetemp=None, prefix='test'):
268 """
268 """
269 Find a configuration file and apply overrides for the given `prefix`.
269 Find a configuration file and apply overrides for the given `prefix`.
270 """
270 """
271 config_file = (
271 config_file = (
272 config.getoption(option_name) or config.getini(option_name))
272 config.getoption(option_name) or config.getini(option_name))
273 if not config_file:
273 if not config_file:
274 pytest.exit(
274 pytest.exit(
275 "Configuration error, could not extract {}.".format(option_name))
275 "Configuration error, could not extract {}.".format(option_name))
276
276
277 overrides = overrides or []
277 overrides = overrides or []
278 config_override = config.getoption(override_option_name)
278 config_override = config.getoption(override_option_name)
279 if config_override:
279 if config_override:
280 overrides.append(config_override)
280 overrides.append(config_override)
281 temp_ini_file = TestINI(
281 temp_ini_file = TestINI(
282 config_file, ini_params=overrides, new_file_prefix=prefix,
282 config_file, ini_params=overrides, new_file_prefix=prefix,
283 dir=basetemp)
283 dir=basetemp)
284
284
285 return temp_ini_file.create()
285 return temp_ini_file.create()
@@ -1,201 +1,208 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2020 RhodeCode GmbH
3 # Copyright (C) 2010-2020 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 import os
22 import os
23 import time
23 import time
24 import tempfile
24 import tempfile
25 import pytest
25 import pytest
26 import subprocess
26 import subprocess
27 import logging
27 import logging
28 from urllib.request import urlopen
28 from urllib.request import urlopen
29 from urllib.error import URLError
29 from urllib.error import URLError
30 import configparser
30 import configparser
31
31
32
32
33 from rhodecode.tests import TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS
33 from rhodecode.tests import TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS
34 from rhodecode.tests.utils import is_url_reachable
34 from rhodecode.tests.utils import is_url_reachable
35
35
36 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
37
37
38
38
39 def get_port(pyramid_config):
39 def get_port(pyramid_config):
40 config = configparser.ConfigParser()
40 config = configparser.ConfigParser()
41 config.read(pyramid_config)
41 config.read(pyramid_config)
42 return config.get('server:main', 'port')
42 return config.get('server:main', 'port')
43
43
44
44
45 def get_host_url(pyramid_config):
45 def get_host_url(pyramid_config):
46 """Construct the host url using the port in the test configuration."""
46 """Construct the host url using the port in the test configuration."""
47 port = get_port(pyramid_config)
47 port = get_port(pyramid_config)
48 return f'127.0.0.1:{port}'
48 return f'127.0.0.1:{port}'
49
49
50
50
51 def assert_no_running_instance(url):
51 def assert_no_running_instance(url):
52 if is_url_reachable(url):
52 if is_url_reachable(url):
53 print(f"Hint: Usually this means another instance of server "
53 print(f"Hint: Usually this means another instance of server "
54 f"is running in the background at {url}.")
54 f"is running in the background at {url}.")
55 pytest.fail(f"Port is not free at {url}, cannot start server at")
55 pytest.fail(f"Port is not free at {url}, cannot start server at")
56
56
57
57
58 class ServerBase(object):
58 class ServerBase(object):
59 _args = []
59 _args = []
60 log_file_name = 'NOT_DEFINED.log'
60 log_file_name = 'NOT_DEFINED.log'
61 status_url_tmpl = 'http://{host}:{port}'
61 status_url_tmpl = 'http://{host}:{port}'
62
62
63 def __init__(self, config_file, log_file):
63 def __init__(self, config_file, log_file):
64 self.config_file = config_file
64 self.config_file = config_file
65 config = configparser.ConfigParser()
65 config = configparser.ConfigParser()
66 config.read(config_file)
66 config.read(config_file)
67
67
68 self._config = {k: v for k, v in config['server:main'].items()}
68 self._config = {k: v for k, v in config['server:main'].items()}
69
69
70 self._args = []
70 self._args = []
71 self.log_file = log_file or os.path.join(
71 self.log_file = log_file or os.path.join(
72 tempfile.gettempdir(), self.log_file_name)
72 tempfile.gettempdir(), self.log_file_name)
73 self.process = None
73 self.process = None
74 self.server_out = None
74 self.server_out = None
75 log.info("Using the {} configuration:{}".format(
75 log.info("Using the {} configuration:{}".format(
76 self.__class__.__name__, config_file))
76 self.__class__.__name__, config_file))
77
77
78 if not os.path.isfile(config_file):
78 if not os.path.isfile(config_file):
79 raise RuntimeError(f'Failed to get config at {config_file}')
79 raise RuntimeError(f'Failed to get config at {config_file}')
80
80
81 @property
81 @property
82 def command(self):
82 def command(self):
83 return ' '.join(self._args)
83 return ' '.join(self._args)
84
84
85 @property
85 @property
86 def bind_addr(self):
87 return '{host}:{port}'.format(**self._config)
88
89 @property
86 def http_url(self):
90 def http_url(self):
87 template = 'http://{host}:{port}/'
91 template = 'http://{host}:{port}/'
88 return template.format(**self._config)
92 return template.format(**self._config)
89
93
90 def host_url(self):
94 def host_url(self):
91 return 'http://' + get_host_url(self.config_file)
95 host = get_host_url(self.config_file)
96 return f'http://{host}'
92
97
93 def get_rc_log(self):
98 def get_rc_log(self):
94 with open(self.log_file) as f:
99 with open(self.log_file) as f:
95 return f.read()
100 return f.read()
96
101
97 def wait_until_ready(self, timeout=30):
102 def wait_until_ready(self, timeout=30):
98 host = self._config['host']
103 host = self._config['host']
99 port = self._config['port']
104 port = self._config['port']
100 status_url = self.status_url_tmpl.format(host=host, port=port)
105 status_url = self.status_url_tmpl.format(host=host, port=port)
101 start = time.time()
106 start = time.time()
102
107
103 while time.time() - start < timeout:
108 while time.time() - start < timeout:
104 try:
109 try:
105 urlopen(status_url)
110 urlopen(status_url)
106 break
111 break
107 except URLError:
112 except URLError:
108 time.sleep(0.2)
113 time.sleep(0.2)
109 else:
114 else:
110 pytest.fail(
115 pytest.fail(
111 "Starting the {} failed or took more than {} "
116 "Starting the {} failed or took more than {} "
112 "seconds. cmd: `{}`".format(
117 "seconds. cmd: `{}`".format(
113 self.__class__.__name__, timeout, self.command))
118 self.__class__.__name__, timeout, self.command))
114
119
115 log.info('Server of {} ready at url {}'.format(
120 log.info('Server of {} ready at url {}'.format(
116 self.__class__.__name__, status_url))
121 self.__class__.__name__, status_url))
117
122
118 def shutdown(self):
123 def shutdown(self):
119 self.process.kill()
124 self.process.kill()
120 self.server_out.flush()
125 self.server_out.flush()
121 self.server_out.close()
126 self.server_out.close()
122
127
123 def get_log_file_with_port(self):
128 def get_log_file_with_port(self):
124 log_file = list(self.log_file.partition('.log'))
129 log_file = list(self.log_file.partition('.log'))
125 log_file.insert(1, get_port(self.config_file))
130 log_file.insert(1, get_port(self.config_file))
126 log_file = ''.join(log_file)
131 log_file = ''.join(log_file)
127 return log_file
132 return log_file
128
133
129
134
130 class RcVCSServer(ServerBase):
135 class RcVCSServer(ServerBase):
131 """
136 """
132 Represents a running VCSServer instance.
137 Represents a running VCSServer instance.
133 """
138 """
134
139
135 log_file_name = 'rc-vcsserver.log'
140 log_file_name = 'rc-vcsserver.log'
136 status_url_tmpl = 'http://{host}:{port}/status'
141 status_url_tmpl = 'http://{host}:{port}/status'
137
142
138 def __init__(self, config_file, log_file=None):
143 def __init__(self, config_file, log_file=None):
139 super(RcVCSServer, self).__init__(config_file, log_file)
144 super(RcVCSServer, self).__init__(config_file, log_file)
140 self._args = ['gunicorn', '--paste', self.config_file]
145 self._args = [
146 'gunicorn', '--bind', self.bind_addr,
147 '--paste', self.config_file]
141
148
142 def start(self):
149 def start(self):
143 env = os.environ.copy()
150 env = os.environ.copy()
144
151
145 self.log_file = self.get_log_file_with_port()
152 self.log_file = self.get_log_file_with_port()
146 self.server_out = open(self.log_file, 'w')
153 self.server_out = open(self.log_file, 'w')
147
154
148 host_url = self.host_url()
155 host_url = self.host_url()
149 assert_no_running_instance(host_url)
156 assert_no_running_instance(host_url)
150
157
151 log.info('rhodecode-vcsserver start command: {}'.format(' '.join(self._args)))
158 print(f'rhodecode-vcsserver starting at: {host_url}')
152 log.info('rhodecode-vcsserver starting at: {}'.format(host_url))
159 print(f'rhodecode-vcsserver command: {self.command}')
153 log.info('rhodecode-vcsserver command: {}'.format(self.command))
160 print(f'rhodecode-vcsserver logfile: {self.log_file}')
154 log.info('rhodecode-vcsserver logfile: {}'.format(self.log_file))
155
161
156 self.process = subprocess.Popen(
162 self.process = subprocess.Popen(
157 self._args, bufsize=0, env=env,
163 self._args, bufsize=0, env=env,
158 stdout=self.server_out, stderr=self.server_out)
164 stdout=self.server_out, stderr=self.server_out)
159
165
160
166
161 class RcWebServer(ServerBase):
167 class RcWebServer(ServerBase):
162 """
168 """
163 Represents a running RCE web server used as a test fixture.
169 Represents a running RCE web server used as a test fixture.
164 """
170 """
165
171
166 log_file_name = 'rc-web.log'
172 log_file_name = 'rc-web.log'
167 status_url_tmpl = 'http://{host}:{port}/_admin/ops/ping'
173 status_url_tmpl = 'http://{host}:{port}/_admin/ops/ping'
168
174
169 def __init__(self, config_file, log_file=None):
175 def __init__(self, config_file, log_file=None):
170 super(RcWebServer, self).__init__(config_file, log_file)
176 super(RcWebServer, self).__init__(config_file, log_file)
171 self._args = [
177 self._args = [
172 'gunicorn', '--worker-class', 'gevent', '--paste', config_file]
178 'gunicorn', '--bind', self.bind_addr, '--worker-class', 'gevent',
179 '--paste', self.config_file]
173
180
174 def start(self):
181 def start(self):
175 env = os.environ.copy()
182 env = os.environ.copy()
176 env['RC_NO_TMP_PATH'] = '1'
183 env['RC_NO_TMP_PATH'] = '1'
177
184
178 self.log_file = self.get_log_file_with_port()
185 self.log_file = self.get_log_file_with_port()
179 self.server_out = open(self.log_file, 'w')
186 self.server_out = open(self.log_file, 'w')
180
187
181 host_url = self.host_url()
188 host_url = self.host_url()
182 assert_no_running_instance(host_url)
189 assert_no_running_instance(host_url)
183
190
184 log.info('rhodecode-web starting at: {}'.format(host_url))
191 print(f'rhodecode-web starting at: {host_url}')
185 log.info('rhodecode-web command: {}'.format(self.command))
192 print(f'rhodecode-web command: {self.command}')
186 log.info('rhodecode-web logfile: {}'.format(self.log_file))
193 print(f'rhodecode-web logfile: {self.log_file}')
187
194
188 self.process = subprocess.Popen(
195 self.process = subprocess.Popen(
189 self._args, bufsize=0, env=env,
196 self._args, bufsize=0, env=env,
190 stdout=self.server_out, stderr=self.server_out)
197 stdout=self.server_out, stderr=self.server_out)
191
198
192 def repo_clone_url(self, repo_name, **kwargs):
199 def repo_clone_url(self, repo_name, **kwargs):
193 params = {
200 params = {
194 'user': TEST_USER_ADMIN_LOGIN,
201 'user': TEST_USER_ADMIN_LOGIN,
195 'passwd': TEST_USER_ADMIN_PASS,
202 'passwd': TEST_USER_ADMIN_PASS,
196 'host': get_host_url(self.config_file),
203 'host': get_host_url(self.config_file),
197 'cloned_repo': repo_name,
204 'cloned_repo': repo_name,
198 }
205 }
199 params.update(**kwargs)
206 params.update(**kwargs)
200 _url = 'http://%(user)s:%(passwd)s@%(host)s/%(cloned_repo)s' % params
207 _url = 'http://%(user)s:%(passwd)s@%(host)s/%(cloned_repo)s' % params
201 return _url
208 return _url
General Comments 0
You need to be logged in to leave comments. Login now