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