##// 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,201 +1,208 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21
22 22 import os
23 23 import time
24 24 import tempfile
25 25 import pytest
26 26 import subprocess
27 27 import logging
28 28 from urllib.request import urlopen
29 29 from urllib.error import URLError
30 30 import configparser
31 31
32 32
33 33 from rhodecode.tests import TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS
34 34 from rhodecode.tests.utils import is_url_reachable
35 35
36 36 log = logging.getLogger(__name__)
37 37
38 38
39 39 def get_port(pyramid_config):
40 40 config = configparser.ConfigParser()
41 41 config.read(pyramid_config)
42 42 return config.get('server:main', 'port')
43 43
44 44
45 45 def get_host_url(pyramid_config):
46 46 """Construct the host url using the port in the test configuration."""
47 47 port = get_port(pyramid_config)
48 48 return f'127.0.0.1:{port}'
49 49
50 50
51 51 def assert_no_running_instance(url):
52 52 if is_url_reachable(url):
53 53 print(f"Hint: Usually this means another instance of server "
54 54 f"is running in the background at {url}.")
55 55 pytest.fail(f"Port is not free at {url}, cannot start server at")
56 56
57 57
58 58 class ServerBase(object):
59 59 _args = []
60 60 log_file_name = 'NOT_DEFINED.log'
61 61 status_url_tmpl = 'http://{host}:{port}'
62 62
63 63 def __init__(self, config_file, log_file):
64 64 self.config_file = config_file
65 65 config = configparser.ConfigParser()
66 66 config.read(config_file)
67 67
68 68 self._config = {k: v for k, v in config['server:main'].items()}
69 69
70 70 self._args = []
71 71 self.log_file = log_file or os.path.join(
72 72 tempfile.gettempdir(), self.log_file_name)
73 73 self.process = None
74 74 self.server_out = None
75 75 log.info("Using the {} configuration:{}".format(
76 76 self.__class__.__name__, config_file))
77 77
78 78 if not os.path.isfile(config_file):
79 79 raise RuntimeError(f'Failed to get config at {config_file}')
80 80
81 81 @property
82 82 def command(self):
83 83 return ' '.join(self._args)
84 84
85 85 @property
86 def bind_addr(self):
87 return '{host}:{port}'.format(**self._config)
88
89 @property
86 90 def http_url(self):
87 91 template = 'http://{host}:{port}/'
88 92 return template.format(**self._config)
89 93
90 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 98 def get_rc_log(self):
94 99 with open(self.log_file) as f:
95 100 return f.read()
96 101
97 102 def wait_until_ready(self, timeout=30):
98 103 host = self._config['host']
99 104 port = self._config['port']
100 105 status_url = self.status_url_tmpl.format(host=host, port=port)
101 106 start = time.time()
102 107
103 108 while time.time() - start < timeout:
104 109 try:
105 110 urlopen(status_url)
106 111 break
107 112 except URLError:
108 113 time.sleep(0.2)
109 114 else:
110 115 pytest.fail(
111 116 "Starting the {} failed or took more than {} "
112 117 "seconds. cmd: `{}`".format(
113 118 self.__class__.__name__, timeout, self.command))
114 119
115 120 log.info('Server of {} ready at url {}'.format(
116 121 self.__class__.__name__, status_url))
117 122
118 123 def shutdown(self):
119 124 self.process.kill()
120 125 self.server_out.flush()
121 126 self.server_out.close()
122 127
123 128 def get_log_file_with_port(self):
124 129 log_file = list(self.log_file.partition('.log'))
125 130 log_file.insert(1, get_port(self.config_file))
126 131 log_file = ''.join(log_file)
127 132 return log_file
128 133
129 134
130 135 class RcVCSServer(ServerBase):
131 136 """
132 137 Represents a running VCSServer instance.
133 138 """
134 139
135 140 log_file_name = 'rc-vcsserver.log'
136 141 status_url_tmpl = 'http://{host}:{port}/status'
137 142
138 143 def __init__(self, config_file, log_file=None):
139 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 149 def start(self):
143 150 env = os.environ.copy()
144 151
145 152 self.log_file = self.get_log_file_with_port()
146 153 self.server_out = open(self.log_file, 'w')
147 154
148 155 host_url = self.host_url()
149 156 assert_no_running_instance(host_url)
150 157
151 log.info('rhodecode-vcsserver start command: {}'.format(' '.join(self._args)))
152 log.info('rhodecode-vcsserver starting at: {}'.format(host_url))
153 log.info('rhodecode-vcsserver command: {}'.format(self.command))
154 log.info('rhodecode-vcsserver logfile: {}'.format(self.log_file))
158 print(f'rhodecode-vcsserver starting at: {host_url}')
159 print(f'rhodecode-vcsserver command: {self.command}')
160 print(f'rhodecode-vcsserver logfile: {self.log_file}')
155 161
156 162 self.process = subprocess.Popen(
157 163 self._args, bufsize=0, env=env,
158 164 stdout=self.server_out, stderr=self.server_out)
159 165
160 166
161 167 class RcWebServer(ServerBase):
162 168 """
163 169 Represents a running RCE web server used as a test fixture.
164 170 """
165 171
166 172 log_file_name = 'rc-web.log'
167 173 status_url_tmpl = 'http://{host}:{port}/_admin/ops/ping'
168 174
169 175 def __init__(self, config_file, log_file=None):
170 176 super(RcWebServer, self).__init__(config_file, log_file)
171 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 181 def start(self):
175 182 env = os.environ.copy()
176 183 env['RC_NO_TMP_PATH'] = '1'
177 184
178 185 self.log_file = self.get_log_file_with_port()
179 186 self.server_out = open(self.log_file, 'w')
180 187
181 188 host_url = self.host_url()
182 189 assert_no_running_instance(host_url)
183 190
184 log.info('rhodecode-web starting at: {}'.format(host_url))
185 log.info('rhodecode-web command: {}'.format(self.command))
186 log.info('rhodecode-web logfile: {}'.format(self.log_file))
191 print(f'rhodecode-web starting at: {host_url}')
192 print(f'rhodecode-web command: {self.command}')
193 print(f'rhodecode-web logfile: {self.log_file}')
187 194
188 195 self.process = subprocess.Popen(
189 196 self._args, bufsize=0, env=env,
190 197 stdout=self.server_out, stderr=self.server_out)
191 198
192 199 def repo_clone_url(self, repo_name, **kwargs):
193 200 params = {
194 201 'user': TEST_USER_ADMIN_LOGIN,
195 202 'passwd': TEST_USER_ADMIN_PASS,
196 203 'host': get_host_url(self.config_file),
197 204 'cloned_repo': repo_name,
198 205 }
199 206 params.update(**kwargs)
200 207 _url = 'http://%(user)s:%(passwd)s@%(host)s/%(cloned_repo)s' % params
201 208 return _url
General Comments 0
You need to be logged in to leave comments. Login now