##// END OF EJS Templates
tests: rewrote code for running vcs_operations. Now it starts it's own...
marcink -
r2457:240dad60 default
parent child Browse files
Show More
@@ -0,0 +1,194 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 #
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
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
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/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21
22 import os
23 import time
24 import tempfile
25 import pytest
26 import subprocess32
27 import configobj
28
29 from urllib2 import urlopen, URLError
30 from pyramid.compat import configparser
31
32
33 from rhodecode.tests import TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS
34 from rhodecode.tests.utils import is_url_reachable
35
36
37 def get_port(pyramid_config):
38 config = configparser.ConfigParser()
39 config.read(pyramid_config)
40 return config.get('server:main', 'port')
41
42
43 def get_host_url(pyramid_config):
44 """Construct the host url using the port in the test configuration."""
45 return '127.0.0.1:%s' % get_port(pyramid_config)
46
47
48 def assert_no_running_instance(url):
49 if is_url_reachable(url):
50 print("Hint: Usually this means another instance of server "
51 "is running in the background at %s." % url)
52 pytest.fail(
53 "Port is not free at %s, cannot start server at" % url)
54
55
56 class ServerBase(object):
57 _args = []
58 log_file_name = 'NOT_DEFINED.log'
59 status_url_tmpl = 'http://{host}:{port}'
60
61 def __init__(self, config_file, log_file):
62 self.config_file = config_file
63 config_data = configobj.ConfigObj(config_file)
64 self._config = config_data['server:main']
65
66 self._args = []
67 self.log_file = log_file or os.path.join(
68 tempfile.gettempdir(), self.log_file_name)
69 self.process = None
70 self.server_out = None
71 print("Using the {} configuration:{}".format(
72 self.__class__.__name__, config_file))
73
74 if not os.path.isfile(config_file):
75 raise RuntimeError('Failed to get config at {}'.format(config_file))
76
77 @property
78 def command(self):
79 return ' '.join(self._args)
80
81 @property
82 def http_url(self):
83 template = 'http://{host}:{port}/'
84 return template.format(**self._config)
85
86 def host_url(self):
87 return 'http://' + get_host_url(self.config_file)
88
89 def get_rc_log(self):
90 with open(self.log_file) as f:
91 return f.read()
92
93 def wait_until_ready(self, timeout=15):
94 host = self._config['host']
95 port = self._config['port']
96 status_url = self.status_url_tmpl.format(host=host, port=port)
97 start = time.time()
98
99 while time.time() - start < timeout:
100 try:
101 urlopen(status_url)
102 break
103 except URLError:
104 time.sleep(0.2)
105 else:
106 pytest.exit(
107 "Starting the {} failed or took more than {} "
108 "seconds. cmd: `{}`".format(
109 self.__class__.__name__, timeout, self.command))
110
111 def shutdown(self):
112 self.process.kill()
113 self.server_out.flush()
114 self.server_out.close()
115
116 def get_log_file_with_port(self):
117 log_file = list(self.log_file.partition('.log'))
118 log_file.insert(1, get_port(self.config_file))
119 log_file = ''.join(log_file)
120 return log_file
121
122
123 class RcVCSServer(ServerBase):
124 """
125 Represents a running VCSServer instance.
126 """
127
128 log_file_name = 'rc-vcsserver.log'
129 status_url_tmpl = 'http://{host}:{port}/status'
130
131 def __init__(self, config_file, log_file=None):
132 super(RcVCSServer, self).__init__(config_file, log_file)
133 self._args = [
134 'gunicorn', '--paste', self.config_file]
135
136 def start(self):
137 env = os.environ.copy()
138
139 self.log_file = self.get_log_file_with_port()
140 self.server_out = open(self.log_file, 'w')
141
142 host_url = self.host_url()
143 assert_no_running_instance(host_url)
144
145 print('rhodecode-vcsserver starting at: {}'.format(host_url))
146 print('rhodecode-vcsserver command: {}'.format(self.command))
147 print('rhodecode-vcsserver logfile: {}'.format(self.log_file))
148
149 self.process = subprocess32.Popen(
150 self._args, bufsize=0, env=env,
151 stdout=self.server_out, stderr=self.server_out)
152
153
154 class RcWebServer(ServerBase):
155 """
156 Represents a running RCE web server used as a test fixture.
157 """
158
159 log_file_name = 'rc-web.log'
160 status_url_tmpl = 'http://{host}:{port}/_admin/ops/ping'
161
162 def __init__(self, config_file, log_file=None):
163 super(RcWebServer, self).__init__(config_file, log_file)
164 self._args = [
165 'gunicorn', '--worker-class', 'gevent', '--paste', config_file]
166
167 def start(self):
168 env = os.environ.copy()
169 env['RC_NO_TMP_PATH'] = '1'
170
171 self.log_file = self.get_log_file_with_port()
172 self.server_out = open(self.log_file, 'w')
173
174 host_url = self.host_url()
175 assert_no_running_instance(host_url)
176
177 print('rhodecode-web starting at: {}'.format(host_url))
178 print('rhodecode-web command: {}'.format(self.command))
179 print('rhodecode-web logfile: {}'.format(self.log_file))
180
181 self.process = subprocess32.Popen(
182 self._args, bufsize=0, env=env,
183 stdout=self.server_out, stderr=self.server_out)
184
185 def repo_clone_url(self, repo_name, **kwargs):
186 params = {
187 'user': TEST_USER_ADMIN_LOGIN,
188 'passwd': TEST_USER_ADMIN_PASS,
189 'host': get_host_url(self.config_file),
190 'cloned_repo': repo_name,
191 }
192 params.update(**kwargs)
193 _url = 'http://%(user)s:%(passwd)s@%(host)s/%(cloned_repo)s' % params
194 return _url
@@ -1,83 +1,82 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 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 pytest
21 import pytest
22
22
23 from rhodecode.tests.utils import CustomTestApp
23 from rhodecode.tests.utils import CustomTestApp
24 from rhodecode.lib.middleware.utils import scm_app_http, scm_app
24 from rhodecode.lib.middleware.utils import scm_app_http, scm_app
25 from rhodecode.lib.vcs.conf import settings
25 from rhodecode.lib.vcs.conf import settings
26
26
27
27
28 def vcs_http_app(vcsserver_http_echo_app):
28 def vcs_http_app(vcsserver_http_echo_app):
29 """
29 """
30 VcsHttpProxy wrapped in WebTest.
30 VcsHttpProxy wrapped in WebTest.
31 """
31 """
32 git_url = vcsserver_http_echo_app.http_url + 'stream/git/'
32 git_url = vcsserver_http_echo_app.http_url + 'stream/git/'
33 vcs_http_proxy = scm_app_http.VcsHttpProxy(
33 vcs_http_proxy = scm_app_http.VcsHttpProxy(
34 git_url, 'stub_path', 'stub_name', None)
34 git_url, 'stub_path', 'stub_name', None)
35 app = CustomTestApp(vcs_http_proxy)
35 app = CustomTestApp(vcs_http_proxy)
36 return app
36 return app
37
37
38
38
39 @pytest.fixture(scope='module')
39 @pytest.fixture(scope='module')
40 def vcsserver_http_echo_app(request, vcsserver_factory):
40 def vcsserver_http_echo_app(request, vcsserver_factory):
41 """
41 """
42 A running VCSServer with the EchoApp activated via HTTP.
42 A running VCSServer with the EchoApp activated via HTTP.
43 """
43 """
44 vcsserver = vcsserver_factory(
44 vcsserver = vcsserver_factory(
45 request=request,
45 request=request,
46 use_http=True,
47 overrides=[{'app:main': {'dev.use_echo_app': 'true'}}])
46 overrides=[{'app:main': {'dev.use_echo_app': 'true'}}])
48 return vcsserver
47 return vcsserver
49
48
50
49
51 @pytest.fixture(scope='session')
50 @pytest.fixture(scope='session')
52 def data():
51 def data():
53 one_kb = "x" * 1024
52 one_kb = "x" * 1024
54 return one_kb * 1024 * 10
53 return one_kb * 1024 * 10
55
54
56
55
57 def test_reuse_app_no_data(repeat, vcsserver_http_echo_app):
56 def test_reuse_app_no_data(repeat, vcsserver_http_echo_app):
58 app = vcs_http_app(vcsserver_http_echo_app)
57 app = vcs_http_app(vcsserver_http_echo_app)
59 for x in xrange(repeat / 10):
58 for x in xrange(repeat / 10):
60 response = app.post('/')
59 response = app.post('/')
61 assert response.status_code == 200
60 assert response.status_code == 200
62
61
63
62
64 def test_reuse_app_with_data(data, repeat, vcsserver_http_echo_app):
63 def test_reuse_app_with_data(data, repeat, vcsserver_http_echo_app):
65 app = vcs_http_app(vcsserver_http_echo_app)
64 app = vcs_http_app(vcsserver_http_echo_app)
66 for x in xrange(repeat / 10):
65 for x in xrange(repeat / 10):
67 response = app.post('/', params=data)
66 response = app.post('/', params=data)
68 assert response.status_code == 200
67 assert response.status_code == 200
69
68
70
69
71 def test_create_app_per_request_no_data(repeat, vcsserver_http_echo_app):
70 def test_create_app_per_request_no_data(repeat, vcsserver_http_echo_app):
72 for x in xrange(repeat / 10):
71 for x in xrange(repeat / 10):
73 app = vcs_http_app(vcsserver_http_echo_app)
72 app = vcs_http_app(vcsserver_http_echo_app)
74 response = app.post('/')
73 response = app.post('/')
75 assert response.status_code == 200
74 assert response.status_code == 200
76
75
77
76
78 def test_create_app_per_request_with_data(
77 def test_create_app_per_request_with_data(
79 data, repeat, vcsserver_http_echo_app):
78 data, repeat, vcsserver_http_echo_app):
80 for x in xrange(repeat / 10):
79 for x in xrange(repeat / 10):
81 app = vcs_http_app(vcsserver_http_echo_app)
80 app = vcs_http_app(vcsserver_http_echo_app)
82 response = app.post('/', params=data)
81 response = app.post('/', params=data)
83 assert response.status_code == 200
82 assert response.status_code == 200
@@ -1,408 +1,297 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 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 os
22 import json
21 import json
23 import time
24 import platform
22 import platform
25 import socket
23 import socket
26 import tempfile
27 import subprocess32
28
24
29 from urllib2 import urlopen, URLError
30
31 import configobj
32 import pytest
25 import pytest
33
26
34
35 from rhodecode.lib.pyramid_utils import get_app_config
27 from rhodecode.lib.pyramid_utils import get_app_config
36 from rhodecode.tests.fixture import TestINI
28 from rhodecode.tests.fixture import TestINI
37 from rhodecode.tests.vcs_operations.conftest import get_host_url, get_port
29 from rhodecode.tests.server_utils import RcVCSServer
38
39 VCSSERVER_LOG = os.path.join(tempfile.gettempdir(), 'rc-vcsserver.log')
40
30
41
31
42 def _parse_json(value):
32 def _parse_json(value):
43 return json.loads(value) if value else None
33 return json.loads(value) if value else None
44
34
45
35
46 def pytest_addoption(parser):
36 def pytest_addoption(parser):
47 parser.addoption(
37 parser.addoption(
48 '--test-loglevel', dest='test_loglevel',
38 '--test-loglevel', dest='test_loglevel',
49 help="Set default Logging level for tests, warn (default), info, debug")
39 help="Set default Logging level for tests, warn (default), info, debug")
50 group = parser.getgroup('pylons')
40 group = parser.getgroup('pylons')
51 group.addoption(
41 group.addoption(
52 '--with-pylons', dest='pyramid_config',
42 '--with-pylons', dest='pyramid_config',
53 help="Set up a Pylons environment with the specified config file.")
43 help="Set up a Pylons environment with the specified config file.")
54 group.addoption(
44 group.addoption(
55 '--ini-config-override', action='store', type=_parse_json,
45 '--ini-config-override', action='store', type=_parse_json,
56 default=None, dest='pyramid_config_override', help=(
46 default=None, dest='pyramid_config_override', help=(
57 "Overrides the .ini file settings. Should be specified in JSON"
47 "Overrides the .ini file settings. Should be specified in JSON"
58 " format, e.g. '{\"section\": {\"parameter\": \"value\", ...}}'"
48 " format, e.g. '{\"section\": {\"parameter\": \"value\", ...}}'"
59 )
49 )
60 )
50 )
61 parser.addini(
51 parser.addini(
62 'pyramid_config',
52 'pyramid_config',
63 "Set up a Pyramid environment with the specified config file.")
53 "Set up a Pyramid environment with the specified config file.")
64
54
65 vcsgroup = parser.getgroup('vcs')
55 vcsgroup = parser.getgroup('vcs')
66 vcsgroup.addoption(
56 vcsgroup.addoption(
67 '--without-vcsserver', dest='with_vcsserver', action='store_false',
57 '--without-vcsserver', dest='with_vcsserver', action='store_false',
68 help="Do not start the VCSServer in a background process.")
58 help="Do not start the VCSServer in a background process.")
69 vcsgroup.addoption(
59 vcsgroup.addoption(
70 '--with-vcsserver-http', dest='vcsserver_config_http',
60 '--with-vcsserver-http', dest='vcsserver_config_http',
71 help="Start the HTTP VCSServer with the specified config file.")
61 help="Start the HTTP VCSServer with the specified config file.")
72 vcsgroup.addoption(
62 vcsgroup.addoption(
73 '--vcsserver-protocol', dest='vcsserver_protocol',
63 '--vcsserver-protocol', dest='vcsserver_protocol',
74 help="Start the VCSServer with HTTP protocol support.")
64 help="Start the VCSServer with HTTP protocol support.")
75 vcsgroup.addoption(
65 vcsgroup.addoption(
76 '--vcsserver-config-override', action='store', type=_parse_json,
66 '--vcsserver-config-override', action='store', type=_parse_json,
77 default=None, dest='vcsserver_config_override', help=(
67 default=None, dest='vcsserver_config_override', help=(
78 "Overrides the .ini file settings for the VCSServer. "
68 "Overrides the .ini file settings for the VCSServer. "
79 "Should be specified in JSON "
69 "Should be specified in JSON "
80 "format, e.g. '{\"section\": {\"parameter\": \"value\", ...}}'"
70 "format, e.g. '{\"section\": {\"parameter\": \"value\", ...}}'"
81 )
71 )
82 )
72 )
83 vcsgroup.addoption(
73 vcsgroup.addoption(
84 '--vcsserver-port', action='store', type=int,
74 '--vcsserver-port', action='store', type=int,
85 default=None, help=(
75 default=None, help=(
86 "Allows to set the port of the vcsserver. Useful when testing "
76 "Allows to set the port of the vcsserver. Useful when testing "
87 "against an already running server and random ports cause "
77 "against an already running server and random ports cause "
88 "trouble."))
78 "trouble."))
89 parser.addini(
79 parser.addini(
90 'vcsserver_config_http',
80 'vcsserver_config_http',
91 "Start the HTTP VCSServer with the specified config file.")
81 "Start the HTTP VCSServer with the specified config file.")
92 parser.addini(
82 parser.addini(
93 'vcsserver_protocol',
83 'vcsserver_protocol',
94 "Start the VCSServer with HTTP protocol support.")
84 "Start the VCSServer with HTTP protocol support.")
95
85
96
86
97 @pytest.fixture(scope="session")
98 def vcs_server_config_override(request):
99 """
100 Allows injecting the overrides by specifying this inside test class
101 """
102
103 return ()
104
105
106 @pytest.fixture(scope='session')
87 @pytest.fixture(scope='session')
107 def vcsserver(request, vcsserver_port, vcsserver_factory, vcs_server_config_override):
88 def vcsserver(request, vcsserver_port, vcsserver_factory):
108 """
89 """
109 Session scope VCSServer.
90 Session scope VCSServer.
110
91
111 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
112 to ensure it will be running.
93 to ensure it will be running.
113
94
114 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
115 adjust the configuration file for the test run.
96 adjust the configuration file for the test run.
116
97
117 Command line args:
98 Command line args:
118
99
119 --without-vcsserver: Allows to switch this fixture off. You have to
100 --without-vcsserver: Allows to switch this fixture off. You have to
120 manually start the server.
101 manually start the server.
121
102
122 --vcsserver-port: Will expect the VCSServer to listen on this port.
103 --vcsserver-port: Will expect the VCSServer to listen on this port.
123 """
104 """
124
105
125 if not request.config.getoption('with_vcsserver'):
106 if not request.config.getoption('with_vcsserver'):
126 return None
107 return None
127
108
128 use_http = _use_vcs_http_server(request.config)
129 return vcsserver_factory(
109 return vcsserver_factory(
130 request, use_http=use_http, vcsserver_port=vcsserver_port,
110 request, vcsserver_port=vcsserver_port)
131 overrides=vcs_server_config_override)
132
111
133
112
134 @pytest.fixture(scope='session')
113 @pytest.fixture(scope='session')
135 def vcsserver_factory(tmpdir_factory):
114 def vcsserver_factory(tmpdir_factory):
136 """
115 """
137 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.
138 """
117 """
139
118
140 def factory(request, use_http=True, overrides=(), vcsserver_port=None):
119 def factory(request, overrides=(), vcsserver_port=None,
120 log_file=None):
141
121
142 if vcsserver_port is None:
122 if vcsserver_port is None:
143 vcsserver_port = get_available_port()
123 vcsserver_port = get_available_port()
144
124
145 overrides = list(overrides)
125 overrides = list(overrides)
146 if use_http:
147 overrides.append({'server:main': {'port': vcsserver_port}})
126 overrides.append({'server:main': {'port': vcsserver_port}})
148 else:
149 overrides.append({'DEFAULT': {'port': vcsserver_port}})
150
127
151 if is_cygwin():
128 if is_cygwin():
152 platform_override = {'DEFAULT': {
129 platform_override = {'DEFAULT': {
153 'beaker.cache.repo_object.type': 'nocache'}}
130 'beaker.cache.repo_object.type': 'nocache'}}
154 overrides.append(platform_override)
131 overrides.append(platform_override)
155
132
156 option_name = 'vcsserver_config_http' if use_http else ''
133 option_name = 'vcsserver_config_http'
157 override_option_name = 'vcsserver_config_override'
134 override_option_name = 'vcsserver_config_override'
158 config_file = get_config(
135 config_file = get_config(
159 request.config, option_name=option_name,
136 request.config, option_name=option_name,
160 override_option_name=override_option_name, overrides=overrides,
137 override_option_name=override_option_name, overrides=overrides,
161 basetemp=tmpdir_factory.getbasetemp().strpath,
138 basetemp=tmpdir_factory.getbasetemp().strpath,
162 prefix='test_vcs_')
139 prefix='test_vcs_')
163
140
164 print("Using the VCSServer configuration:{}".format(config_file))
141 server = RcVCSServer(config_file, log_file)
165 ServerClass = HttpVCSServer if use_http else None
166 server = ServerClass(config_file)
167 server.start()
142 server.start()
168
143
169 @request.addfinalizer
144 @request.addfinalizer
170 def cleanup():
145 def cleanup():
171 server.shutdown()
146 server.shutdown()
172
147
173 server.wait_until_ready()
148 server.wait_until_ready()
174 return server
149 return server
175
150
176 return factory
151 return factory
177
152
178
153
179 def is_cygwin():
154 def is_cygwin():
180 return 'cygwin' in platform.system().lower()
155 return 'cygwin' in platform.system().lower()
181
156
182
157
183 def _use_vcs_http_server(config):
184 protocol_option = 'vcsserver_protocol'
185 protocol = (
186 config.getoption(protocol_option) or
187 config.getini(protocol_option) or
188 'http')
189 return protocol == 'http'
190
191
192 def _use_log_level(config):
158 def _use_log_level(config):
193 level = config.getoption('test_loglevel') or 'warn'
159 level = config.getoption('test_loglevel') or 'warn'
194 return level.upper()
160 return level.upper()
195
161
196
162
197 class VCSServer(object):
198 """
199 Represents a running VCSServer instance.
200 """
201
202 _args = []
203
204 def start(self):
205 print("Starting the VCSServer: {}".format(self._args))
206 self.process = subprocess32.Popen(self._args)
207
208 def wait_until_ready(self, timeout=30):
209 raise NotImplementedError()
210
211 def shutdown(self):
212 self.process.kill()
213
214
215 class HttpVCSServer(VCSServer):
216 """
217 Represents a running VCSServer instance.
218 """
219 def __init__(self, config_file):
220 self.config_file = config_file
221 config_data = configobj.ConfigObj(config_file)
222 self._config = config_data['server:main']
223
224 args = ['gunicorn', '--paste', config_file]
225 self._args = args
226
227 @property
228 def http_url(self):
229 template = 'http://{host}:{port}/'
230 return template.format(**self._config)
231
232 def start(self):
233 env = os.environ.copy()
234 host_url = 'http://' + get_host_url(self.config_file)
235
236 rc_log = list(VCSSERVER_LOG.partition('.log'))
237 rc_log.insert(1, get_port(self.config_file))
238 rc_log = ''.join(rc_log)
239
240 server_out = open(rc_log, 'w')
241
242 command = ' '.join(self._args)
243 print('rhodecode-vcsserver starting at: {}'.format(host_url))
244 print('rhodecode-vcsserver command: {}'.format(command))
245 print('rhodecode-vcsserver logfile: {}'.format(rc_log))
246 self.process = subprocess32.Popen(
247 self._args, bufsize=0, env=env, stdout=server_out, stderr=server_out)
248
249 def wait_until_ready(self, timeout=30):
250 host = self._config['host']
251 port = self._config['port']
252 status_url = 'http://{host}:{port}/status'.format(host=host, port=port)
253 start = time.time()
254
255 while time.time() - start < timeout:
256 try:
257 urlopen(status_url)
258 break
259 except URLError:
260 time.sleep(0.2)
261 else:
262 pytest.exit(
263 "Starting the VCSServer failed or took more than {} "
264 "seconds. cmd: `{}`".format(timeout, ' '.join(self._args)))
265
266 def shutdown(self):
267 self.process.kill()
268
269
270 @pytest.fixture(scope='session')
163 @pytest.fixture(scope='session')
271 def ini_config(request, tmpdir_factory, rcserver_port, vcsserver_port):
164 def ini_config(request, tmpdir_factory, rcserver_port, vcsserver_port):
272 option_name = 'pyramid_config'
165 option_name = 'pyramid_config'
273 log_level = _use_log_level(request.config)
166 log_level = _use_log_level(request.config)
274
167
275 overrides = [
168 overrides = [
276 {'server:main': {'port': rcserver_port}},
169 {'server:main': {'port': rcserver_port}},
277 {'app:main': {
170 {'app:main': {
278 'vcs.server': 'localhost:%s' % vcsserver_port,
171 'vcs.server': 'localhost:%s' % vcsserver_port,
279 # johbo: We will always start the VCSServer on our own based on the
172 # johbo: We will always start the VCSServer on our own based on the
280 # fixtures of the test cases. For the test run it must always be
173 # fixtures of the test cases. For the test run it must always be
281 # off in the INI file.
174 # off in the INI file.
282 'vcs.start_server': 'false',
175 'vcs.start_server': 'false',
176
177 'vcs.server.protocol': 'http',
178 'vcs.scm_app_implementation': 'http',
179 'vcs.hooks.protocol': 'http',
283 }},
180 }},
284
181
285 {'handler_console': {
182 {'handler_console': {
286 'class ': 'StreamHandler',
183 'class ': 'StreamHandler',
287 'args ': '(sys.stderr,)',
184 'args ': '(sys.stderr,)',
288 'level': log_level,
185 'level': log_level,
289 }},
186 }},
290
187
291 ]
188 ]
292 if _use_vcs_http_server(request.config):
293 overrides.append({
294 'app:main': {
295 'vcs.server.protocol': 'http',
296 'vcs.scm_app_implementation': 'http',
297 'vcs.hooks.protocol': 'http',
298 }
299 })
300
189
301 filename = get_config(
190 filename = get_config(
302 request.config, option_name=option_name,
191 request.config, option_name=option_name,
303 override_option_name='{}_override'.format(option_name),
192 override_option_name='{}_override'.format(option_name),
304 overrides=overrides,
193 overrides=overrides,
305 basetemp=tmpdir_factory.getbasetemp().strpath,
194 basetemp=tmpdir_factory.getbasetemp().strpath,
306 prefix='test_rce_')
195 prefix='test_rce_')
307 return filename
196 return filename
308
197
309
198
310 @pytest.fixture(scope='session')
199 @pytest.fixture(scope='session')
311 def ini_settings(ini_config):
200 def ini_settings(ini_config):
312 ini_path = ini_config
201 ini_path = ini_config
313 return get_app_config(ini_path)
202 return get_app_config(ini_path)
314
203
315
204
205 def get_available_port():
206 family = socket.AF_INET
207 socktype = socket.SOCK_STREAM
208 host = '127.0.0.1'
209
210 mysocket = socket.socket(family, socktype)
211 mysocket.bind((host, 0))
212 port = mysocket.getsockname()[1]
213 mysocket.close()
214 del mysocket
215 return port
216
217
316 @pytest.fixture(scope='session')
218 @pytest.fixture(scope='session')
317 def rcserver_port(request):
219 def rcserver_port(request):
318 port = get_available_port()
220 port = get_available_port()
319 print('Using rcserver port {}'.format(port))
221 print('Using rcserver port {}'.format(port))
320 return port
222 return port
321
223
322
224
323 @pytest.fixture(scope='session')
225 @pytest.fixture(scope='session')
324 def vcsserver_port(request):
226 def vcsserver_port(request):
325 port = request.config.getoption('--vcsserver-port')
227 port = request.config.getoption('--vcsserver-port')
326 if port is None:
228 if port is None:
327 port = get_available_port()
229 port = get_available_port()
328 print('Using vcsserver port {}'.format(port))
230 print('Using vcsserver port {}'.format(port))
329 return port
231 return port
330
232
331
233
332 def get_available_port():
333 family = socket.AF_INET
334 socktype = socket.SOCK_STREAM
335 host = '127.0.0.1'
336
337 mysocket = socket.socket(family, socktype)
338 mysocket.bind((host, 0))
339 port = mysocket.getsockname()[1]
340 mysocket.close()
341 del mysocket
342 return port
343
344
345 @pytest.fixture(scope='session')
234 @pytest.fixture(scope='session')
346 def available_port_factory():
235 def available_port_factory():
347 """
236 """
348 Returns a callable which returns free port numbers.
237 Returns a callable which returns free port numbers.
349 """
238 """
350 return get_available_port
239 return get_available_port
351
240
352
241
353 @pytest.fixture
242 @pytest.fixture
354 def available_port(available_port_factory):
243 def available_port(available_port_factory):
355 """
244 """
356 Gives you one free port for the current test.
245 Gives you one free port for the current test.
357
246
358 Uses "available_port_factory" to retrieve the port.
247 Uses "available_port_factory" to retrieve the port.
359 """
248 """
360 return available_port_factory()
249 return available_port_factory()
361
250
362
251
363 @pytest.fixture(scope='session')
252 @pytest.fixture(scope='session')
364 def testini_factory(tmpdir_factory, ini_config):
253 def testini_factory(tmpdir_factory, ini_config):
365 """
254 """
366 Factory to create an INI file based on TestINI.
255 Factory to create an INI file based on TestINI.
367
256
368 It will make sure to place the INI file in the correct directory.
257 It will make sure to place the INI file in the correct directory.
369 """
258 """
370 basetemp = tmpdir_factory.getbasetemp().strpath
259 basetemp = tmpdir_factory.getbasetemp().strpath
371 return TestIniFactory(basetemp, ini_config)
260 return TestIniFactory(basetemp, ini_config)
372
261
373
262
374 class TestIniFactory(object):
263 class TestIniFactory(object):
375
264
376 def __init__(self, basetemp, template_ini):
265 def __init__(self, basetemp, template_ini):
377 self._basetemp = basetemp
266 self._basetemp = basetemp
378 self._template_ini = template_ini
267 self._template_ini = template_ini
379
268
380 def __call__(self, ini_params, new_file_prefix='test'):
269 def __call__(self, ini_params, new_file_prefix='test'):
381 ini_file = TestINI(
270 ini_file = TestINI(
382 self._template_ini, ini_params=ini_params,
271 self._template_ini, ini_params=ini_params,
383 new_file_prefix=new_file_prefix, dir=self._basetemp)
272 new_file_prefix=new_file_prefix, dir=self._basetemp)
384 result = ini_file.create()
273 result = ini_file.create()
385 return result
274 return result
386
275
387
276
388 def get_config(
277 def get_config(
389 config, option_name, override_option_name, overrides=None,
278 config, option_name, override_option_name, overrides=None,
390 basetemp=None, prefix='test'):
279 basetemp=None, prefix='test'):
391 """
280 """
392 Find a configuration file and apply overrides for the given `prefix`.
281 Find a configuration file and apply overrides for the given `prefix`.
393 """
282 """
394 config_file = (
283 config_file = (
395 config.getoption(option_name) or config.getini(option_name))
284 config.getoption(option_name) or config.getini(option_name))
396 if not config_file:
285 if not config_file:
397 pytest.exit(
286 pytest.exit(
398 "Configuration error, could not extract {}.".format(option_name))
287 "Configuration error, could not extract {}.".format(option_name))
399
288
400 overrides = overrides or []
289 overrides = overrides or []
401 config_override = config.getoption(override_option_name)
290 config_override = config.getoption(override_option_name)
402 if config_override:
291 if config_override:
403 overrides.append(config_override)
292 overrides.append(config_override)
404 temp_ini_file = TestINI(
293 temp_ini_file = TestINI(
405 config_file, ini_params=overrides, new_file_prefix=prefix,
294 config_file, ini_params=overrides, new_file_prefix=prefix,
406 dir=basetemp)
295 dir=basetemp)
407
296
408 return temp_ini_file.create()
297 return temp_ini_file.create()
@@ -1,262 +1,257 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 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 time
21 import time
22 import shutil
22 import shutil
23 import datetime
23 import datetime
24
24
25 import pytest
25 import pytest
26
26
27 from rhodecode.lib.vcs.backends import get_backend
27 from rhodecode.lib.vcs.backends import get_backend
28 from rhodecode.lib.vcs.backends.base import Config
28 from rhodecode.lib.vcs.backends.base import Config
29 from rhodecode.lib.vcs.nodes import FileNode
29 from rhodecode.lib.vcs.nodes import FileNode
30 from rhodecode.tests import get_new_dir
30 from rhodecode.tests import get_new_dir
31 from rhodecode.tests.utils import check_skip_backends, check_xfail_backends
31 from rhodecode.tests.utils import check_skip_backends, check_xfail_backends
32
32
33
33
34 @pytest.fixture(scope="session")
35 def vcs_server_config_override():
36 return ({'server:main': {'workers': 1}},)
37
38
39 @pytest.fixture()
34 @pytest.fixture()
40 def vcs_repository_support(
35 def vcs_repository_support(
41 request, backend_alias, baseapp, _vcs_repo_container):
36 request, backend_alias, baseapp, _vcs_repo_container):
42 """
37 """
43 Provide a test repository for the test run.
38 Provide a test repository for the test run.
44
39
45 Depending on the value of `recreate_repo_per_test` a new repo for each
40 Depending on the value of `recreate_repo_per_test` a new repo for each
46 test will be created.
41 test will be created.
47
42
48 The parameter `--backends` can be used to limit this fixture to specific
43 The parameter `--backends` can be used to limit this fixture to specific
49 backend implementations.
44 backend implementations.
50 """
45 """
51 cls = request.cls
46 cls = request.cls
52
47
53 check_skip_backends(request.node, backend_alias)
48 check_skip_backends(request.node, backend_alias)
54 check_xfail_backends(request.node, backend_alias)
49 check_xfail_backends(request.node, backend_alias)
55
50
56 if _should_create_repo_per_test(cls):
51 if _should_create_repo_per_test(cls):
57 _vcs_repo_container = _create_vcs_repo_container(request)
52 _vcs_repo_container = _create_vcs_repo_container(request)
58
53
59 repo = _vcs_repo_container.get_repo(cls, backend_alias=backend_alias)
54 repo = _vcs_repo_container.get_repo(cls, backend_alias=backend_alias)
60
55
61 # TODO: johbo: Supporting old test class api, think about removing this
56 # TODO: johbo: Supporting old test class api, think about removing this
62 cls.repo = repo
57 cls.repo = repo
63 cls.repo_path = repo.path
58 cls.repo_path = repo.path
64 cls.default_branch = repo.DEFAULT_BRANCH_NAME
59 cls.default_branch = repo.DEFAULT_BRANCH_NAME
65 cls.Backend = cls.backend_class = repo.__class__
60 cls.Backend = cls.backend_class = repo.__class__
66 cls.imc = repo.in_memory_commit
61 cls.imc = repo.in_memory_commit
67
62
68 return backend_alias, repo
63 return backend_alias, repo
69
64
70
65
71 @pytest.fixture(scope='class')
66 @pytest.fixture(scope='class')
72 def _vcs_repo_container(request):
67 def _vcs_repo_container(request):
73 """
68 """
74 Internal fixture intended to help support class based scoping on demand.
69 Internal fixture intended to help support class based scoping on demand.
75 """
70 """
76 return _create_vcs_repo_container(request)
71 return _create_vcs_repo_container(request)
77
72
78
73
79 def _create_vcs_repo_container(request):
74 def _create_vcs_repo_container(request):
80 repo_container = VcsRepoContainer()
75 repo_container = VcsRepoContainer()
81 if not request.config.getoption('--keep-tmp-path'):
76 if not request.config.getoption('--keep-tmp-path'):
82 request.addfinalizer(repo_container.cleanup)
77 request.addfinalizer(repo_container.cleanup)
83 return repo_container
78 return repo_container
84
79
85
80
86 class VcsRepoContainer(object):
81 class VcsRepoContainer(object):
87
82
88 def __init__(self):
83 def __init__(self):
89 self._cleanup_paths = []
84 self._cleanup_paths = []
90 self._repos = {}
85 self._repos = {}
91
86
92 def get_repo(self, test_class, backend_alias):
87 def get_repo(self, test_class, backend_alias):
93 if backend_alias not in self._repos:
88 if backend_alias not in self._repos:
94 repo = _create_empty_repository(test_class, backend_alias)
89 repo = _create_empty_repository(test_class, backend_alias)
95
90
96 self._cleanup_paths.append(repo.path)
91 self._cleanup_paths.append(repo.path)
97 self._repos[backend_alias] = repo
92 self._repos[backend_alias] = repo
98 return self._repos[backend_alias]
93 return self._repos[backend_alias]
99
94
100 def cleanup(self):
95 def cleanup(self):
101 for repo_path in reversed(self._cleanup_paths):
96 for repo_path in reversed(self._cleanup_paths):
102 shutil.rmtree(repo_path)
97 shutil.rmtree(repo_path)
103
98
104
99
105 def _should_create_repo_per_test(cls):
100 def _should_create_repo_per_test(cls):
106 return getattr(cls, 'recreate_repo_per_test', False)
101 return getattr(cls, 'recreate_repo_per_test', False)
107
102
108
103
109 def _create_empty_repository(cls, backend_alias=None):
104 def _create_empty_repository(cls, backend_alias=None):
110 Backend = get_backend(backend_alias or cls.backend_alias)
105 Backend = get_backend(backend_alias or cls.backend_alias)
111 repo_path = get_new_dir(str(time.time()))
106 repo_path = get_new_dir(str(time.time()))
112 repo = Backend(repo_path, create=True)
107 repo = Backend(repo_path, create=True)
113 if hasattr(cls, '_get_commits'):
108 if hasattr(cls, '_get_commits'):
114 commits = cls._get_commits()
109 commits = cls._get_commits()
115 cls.tip = _add_commits_to_repo(repo, commits)
110 cls.tip = _add_commits_to_repo(repo, commits)
116
111
117 return repo
112 return repo
118
113
119
114
120 @pytest.fixture
115 @pytest.fixture
121 def config():
116 def config():
122 """
117 """
123 Instance of a repository config.
118 Instance of a repository config.
124
119
125 The instance contains only one value:
120 The instance contains only one value:
126
121
127 - Section: "section-a"
122 - Section: "section-a"
128 - Key: "a-1"
123 - Key: "a-1"
129 - Value: "value-a-1"
124 - Value: "value-a-1"
130
125
131 The intended usage is for cases where a config instance is needed but no
126 The intended usage is for cases where a config instance is needed but no
132 specific content is required.
127 specific content is required.
133 """
128 """
134 config = Config()
129 config = Config()
135 config.set('section-a', 'a-1', 'value-a-1')
130 config.set('section-a', 'a-1', 'value-a-1')
136 return config
131 return config
137
132
138
133
139 def _add_commits_to_repo(repo, commits):
134 def _add_commits_to_repo(repo, commits):
140 imc = repo.in_memory_commit
135 imc = repo.in_memory_commit
141 tip = None
136 tip = None
142
137
143 for commit in commits:
138 for commit in commits:
144 for node in commit.get('added', []):
139 for node in commit.get('added', []):
145 imc.add(FileNode(node.path, content=node.content))
140 imc.add(FileNode(node.path, content=node.content))
146 for node in commit.get('changed', []):
141 for node in commit.get('changed', []):
147 imc.change(FileNode(node.path, content=node.content))
142 imc.change(FileNode(node.path, content=node.content))
148 for node in commit.get('removed', []):
143 for node in commit.get('removed', []):
149 imc.remove(FileNode(node.path))
144 imc.remove(FileNode(node.path))
150
145
151 tip = imc.commit(
146 tip = imc.commit(
152 message=unicode(commit['message']),
147 message=unicode(commit['message']),
153 author=unicode(commit['author']),
148 author=unicode(commit['author']),
154 date=commit['date'],
149 date=commit['date'],
155 branch=commit.get('branch'))
150 branch=commit.get('branch'))
156
151
157 return tip
152 return tip
158
153
159
154
160 @pytest.fixture
155 @pytest.fixture
161 def vcs_repo(request, backend_alias):
156 def vcs_repo(request, backend_alias):
162 Backend = get_backend(backend_alias)
157 Backend = get_backend(backend_alias)
163 repo_path = get_new_dir(str(time.time()))
158 repo_path = get_new_dir(str(time.time()))
164 repo = Backend(repo_path, create=True)
159 repo = Backend(repo_path, create=True)
165
160
166 @request.addfinalizer
161 @request.addfinalizer
167 def cleanup():
162 def cleanup():
168 shutil.rmtree(repo_path)
163 shutil.rmtree(repo_path)
169
164
170 return repo
165 return repo
171
166
172
167
173 @pytest.fixture
168 @pytest.fixture
174 def generate_repo_with_commits(vcs_repo):
169 def generate_repo_with_commits(vcs_repo):
175 """
170 """
176 Creates a fabric to generate N comits with some file nodes on a randomly
171 Creates a fabric to generate N comits with some file nodes on a randomly
177 generated repository
172 generated repository
178 """
173 """
179
174
180 def commit_generator(num):
175 def commit_generator(num):
181 start_date = datetime.datetime(2010, 1, 1, 20)
176 start_date = datetime.datetime(2010, 1, 1, 20)
182 for x in xrange(num):
177 for x in xrange(num):
183 yield {
178 yield {
184 'message': 'Commit %d' % x,
179 'message': 'Commit %d' % x,
185 'author': 'Joe Doe <joe.doe@example.com>',
180 'author': 'Joe Doe <joe.doe@example.com>',
186 'date': start_date + datetime.timedelta(hours=12 * x),
181 'date': start_date + datetime.timedelta(hours=12 * x),
187 'added': [
182 'added': [
188 FileNode('file_%d.txt' % x, content='Foobar %d' % x),
183 FileNode('file_%d.txt' % x, content='Foobar %d' % x),
189 ],
184 ],
190 'modified': [
185 'modified': [
191 FileNode('file_%d.txt' % x,
186 FileNode('file_%d.txt' % x,
192 content='Foobar %d modified' % (x-1)),
187 content='Foobar %d modified' % (x-1)),
193 ]
188 ]
194 }
189 }
195
190
196 def commit_maker(num=5):
191 def commit_maker(num=5):
197 _add_commits_to_repo(vcs_repo, commit_generator(num))
192 _add_commits_to_repo(vcs_repo, commit_generator(num))
198 return vcs_repo
193 return vcs_repo
199
194
200 return commit_maker
195 return commit_maker
201
196
202
197
203 @pytest.fixture
198 @pytest.fixture
204 def hg_repo(request, vcs_repo):
199 def hg_repo(request, vcs_repo):
205 repo = vcs_repo
200 repo = vcs_repo
206
201
207 commits = repo._get_commits()
202 commits = repo._get_commits()
208 _add_commits_to_repo(repo, commits)
203 _add_commits_to_repo(repo, commits)
209
204
210 return repo
205 return repo
211
206
212
207
213 @pytest.fixture
208 @pytest.fixture
214 def hg_commit(hg_repo):
209 def hg_commit(hg_repo):
215 return hg_repo.get_commit()
210 return hg_repo.get_commit()
216
211
217
212
218 class BackendTestMixin(object):
213 class BackendTestMixin(object):
219 """
214 """
220 This is a backend independent test case class which should be created
215 This is a backend independent test case class which should be created
221 with ``type`` method.
216 with ``type`` method.
222
217
223 It is required to set following attributes at subclass:
218 It is required to set following attributes at subclass:
224
219
225 - ``backend_alias``: alias of used backend (see ``vcs.BACKENDS``)
220 - ``backend_alias``: alias of used backend (see ``vcs.BACKENDS``)
226 - ``repo_path``: path to the repository which would be created for set of
221 - ``repo_path``: path to the repository which would be created for set of
227 tests
222 tests
228 - ``recreate_repo_per_test``: If set to ``False``, repo would NOT be
223 - ``recreate_repo_per_test``: If set to ``False``, repo would NOT be
229 created
224 created
230 before every single test. Defaults to ``True``.
225 before every single test. Defaults to ``True``.
231 """
226 """
232 recreate_repo_per_test = True
227 recreate_repo_per_test = True
233
228
234 @classmethod
229 @classmethod
235 def _get_commits(cls):
230 def _get_commits(cls):
236 commits = [
231 commits = [
237 {
232 {
238 'message': u'Initial commit',
233 'message': u'Initial commit',
239 'author': u'Joe Doe <joe.doe@example.com>',
234 'author': u'Joe Doe <joe.doe@example.com>',
240 'date': datetime.datetime(2010, 1, 1, 20),
235 'date': datetime.datetime(2010, 1, 1, 20),
241 'added': [
236 'added': [
242 FileNode('foobar', content='Foobar'),
237 FileNode('foobar', content='Foobar'),
243 FileNode('foobar2', content='Foobar II'),
238 FileNode('foobar2', content='Foobar II'),
244 FileNode('foo/bar/baz', content='baz here!'),
239 FileNode('foo/bar/baz', content='baz here!'),
245 ],
240 ],
246 },
241 },
247 {
242 {
248 'message': u'Changes...',
243 'message': u'Changes...',
249 'author': u'Jane Doe <jane.doe@example.com>',
244 'author': u'Jane Doe <jane.doe@example.com>',
250 'date': datetime.datetime(2010, 1, 1, 21),
245 'date': datetime.datetime(2010, 1, 1, 21),
251 'added': [
246 'added': [
252 FileNode('some/new.txt', content='news...'),
247 FileNode('some/new.txt', content='news...'),
253 ],
248 ],
254 'changed': [
249 'changed': [
255 FileNode('foobar', 'Foobar I'),
250 FileNode('foobar', 'Foobar I'),
256 ],
251 ],
257 'removed': [],
252 'removed': [],
258 },
253 },
259 ]
254 ]
260 return commits
255 return commits
261
256
262
257
@@ -1,276 +1,262 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 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 py.test config for test suite for making push/pull operations.
22 py.test config for test suite for making push/pull operations.
23
23
24 .. important::
24 .. important::
25
25
26 You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
26 You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
27 to redirect things to stderr instead of stdout.
27 to redirect things to stderr instead of stdout.
28 """
28 """
29
29
30 import ConfigParser
31 import os
30 import os
32 import subprocess32
33 import tempfile
31 import tempfile
34 import textwrap
32 import textwrap
35 import pytest
33 import pytest
36
34
37 import rhodecode
35 from rhodecode import events
36 from rhodecode.model.db import Integration
37 from rhodecode.model.integration import IntegrationModel
38 from rhodecode.model.db import Repository
38 from rhodecode.model.db import Repository
39 from rhodecode.model.meta import Session
39 from rhodecode.model.meta import Session
40 from rhodecode.model.settings import SettingsModel
40 from rhodecode.model.settings import SettingsModel
41 from rhodecode.tests import (
41 from rhodecode.integrations.types.webhook import WebhookIntegrationType
42 GIT_REPO, HG_REPO, TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS,)
42
43 from rhodecode.tests import GIT_REPO, HG_REPO
43 from rhodecode.tests.fixture import Fixture
44 from rhodecode.tests.fixture import Fixture
44 from rhodecode.tests.utils import is_url_reachable, wait_for_url
45 from rhodecode.tests.server_utils import RcWebServer
45
46
46 RC_LOG = os.path.join(tempfile.gettempdir(), 'rc.log')
47 REPO_GROUP = 'a_repo_group'
47 REPO_GROUP = 'a_repo_group'
48 HG_REPO_WITH_GROUP = '%s/%s' % (REPO_GROUP, HG_REPO)
48 HG_REPO_WITH_GROUP = '%s/%s' % (REPO_GROUP, HG_REPO)
49 GIT_REPO_WITH_GROUP = '%s/%s' % (REPO_GROUP, GIT_REPO)
49 GIT_REPO_WITH_GROUP = '%s/%s' % (REPO_GROUP, GIT_REPO)
50
50
51
51
52 def assert_no_running_instance(url):
53 if is_url_reachable(url):
54 print("Hint: Usually this means another instance of Enterprise "
55 "is running in the background.")
56 pytest.fail(
57 "Port is not free at %s, cannot start web interface" % url)
58
59
60 def get_port(pyramid_config):
61 config = ConfigParser.ConfigParser()
62 config.read(pyramid_config)
63 return config.get('server:main', 'port')
64
65
66 def get_host_url(pyramid_config):
67 """Construct the host url using the port in the test configuration."""
68 return '127.0.0.1:%s' % get_port(pyramid_config)
69
70
71 class RcWebServer(object):
72 """
73 Represents a running RCE web server used as a test fixture.
74 """
75 def __init__(self, pyramid_config, log_file):
76 self.pyramid_config = pyramid_config
77 self.log_file = log_file
78
79 def repo_clone_url(self, repo_name, **kwargs):
80 params = {
81 'user': TEST_USER_ADMIN_LOGIN,
82 'passwd': TEST_USER_ADMIN_PASS,
83 'host': get_host_url(self.pyramid_config),
84 'cloned_repo': repo_name,
85 }
86 params.update(**kwargs)
87 _url = 'http://%(user)s:%(passwd)s@%(host)s/%(cloned_repo)s' % params
88 return _url
89
90 def host_url(self):
91 return 'http://' + get_host_url(self.pyramid_config)
92
93 def get_rc_log(self):
94 with open(self.log_file) as f:
95 return f.read()
96
97
98 @pytest.fixture(scope="module")
52 @pytest.fixture(scope="module")
99 def rcextensions(request, baseapp, tmpdir_factory):
53 def rcextensions(request, db_connection, tmpdir_factory):
100 """
54 """
101 Installs a testing rcextensions pack to ensure they work as expected.
55 Installs a testing rcextensions pack to ensure they work as expected.
102 """
56 """
103 init_content = textwrap.dedent("""
57 init_content = textwrap.dedent("""
104 # Forward import the example rcextensions to make it
58 # Forward import the example rcextensions to make it
105 # active for our tests.
59 # active for our tests.
106 from rhodecode.tests.other.example_rcextensions import *
60 from rhodecode.tests.other.example_rcextensions import *
107 """)
61 """)
108
62
109 # Note: rcextensions are looked up based on the path of the ini file
63 # Note: rcextensions are looked up based on the path of the ini file
110 root_path = tmpdir_factory.getbasetemp()
64 root_path = tmpdir_factory.getbasetemp()
111 rcextensions_path = root_path.join('rcextensions')
65 rcextensions_path = root_path.join('rcextensions')
112 init_path = rcextensions_path.join('__init__.py')
66 init_path = rcextensions_path.join('__init__.py')
113
67
114 if rcextensions_path.check():
68 if rcextensions_path.check():
115 pytest.fail(
69 pytest.fail(
116 "Path for rcextensions already exists, please clean up before "
70 "Path for rcextensions already exists, please clean up before "
117 "test run this path: %s" % (rcextensions_path, ))
71 "test run this path: %s" % (rcextensions_path, ))
118 return
72 return
119
73
120 request.addfinalizer(rcextensions_path.remove)
74 request.addfinalizer(rcextensions_path.remove)
121 init_path.write_binary(init_content, ensure=True)
75 init_path.write_binary(init_content, ensure=True)
122
76
123
77
124 @pytest.fixture(scope="module")
78 @pytest.fixture(scope="module")
125 def repos(request, baseapp):
79 def repos(request, db_connection):
126 """Create a copy of each test repo in a repo group."""
80 """Create a copy of each test repo in a repo group."""
127 fixture = Fixture()
81 fixture = Fixture()
128 repo_group = fixture.create_repo_group(REPO_GROUP)
82 repo_group = fixture.create_repo_group(REPO_GROUP)
129 repo_group_id = repo_group.group_id
83 repo_group_id = repo_group.group_id
130 fixture.create_fork(HG_REPO, HG_REPO,
84 fixture.create_fork(HG_REPO, HG_REPO,
131 repo_name_full=HG_REPO_WITH_GROUP,
85 repo_name_full=HG_REPO_WITH_GROUP,
132 repo_group=repo_group_id)
86 repo_group=repo_group_id)
133 fixture.create_fork(GIT_REPO, GIT_REPO,
87 fixture.create_fork(GIT_REPO, GIT_REPO,
134 repo_name_full=GIT_REPO_WITH_GROUP,
88 repo_name_full=GIT_REPO_WITH_GROUP,
135 repo_group=repo_group_id)
89 repo_group=repo_group_id)
136
90
137 @request.addfinalizer
91 @request.addfinalizer
138 def cleanup():
92 def cleanup():
139 fixture.destroy_repo(HG_REPO_WITH_GROUP)
93 fixture.destroy_repo(HG_REPO_WITH_GROUP)
140 fixture.destroy_repo(GIT_REPO_WITH_GROUP)
94 fixture.destroy_repo(GIT_REPO_WITH_GROUP)
141 fixture.destroy_repo_group(repo_group_id)
95 fixture.destroy_repo_group(repo_group_id)
142
96
143
97
144 @pytest.fixture(scope="session")
98 @pytest.fixture(scope="module")
145 def vcs_server_config_override():
99 def rc_web_server_config_modification():
146 return ({'server:main': {'workers': 2}},)
100 return []
147
101
148
102
149 @pytest.fixture(scope="module")
103 @pytest.fixture(scope="module")
150 def rc_web_server_config(testini_factory):
104 def rc_web_server_config_factory(testini_factory, rc_web_server_config_modification):
151 """
105 """
152 Configuration file used for the fixture `rc_web_server`.
106 Configuration file used for the fixture `rc_web_server`.
153 """
107 """
154 CUSTOM_PARAMS = [
108
109 def factory(vcsserver_port):
110 custom_params = [
155 {'handler_console': {'level': 'DEBUG'}},
111 {'handler_console': {'level': 'DEBUG'}},
112 {'app:main': {'vcs.server': 'localhost:%s' % vcsserver_port}}
156 ]
113 ]
157 return testini_factory(CUSTOM_PARAMS)
114 custom_params.extend(rc_web_server_config_modification)
115 return testini_factory(custom_params)
116 return factory
158
117
159
118
160 @pytest.fixture(scope="module")
119 @pytest.fixture(scope="module")
161 def rc_web_server(
120 def rc_web_server(
162 request, baseapp, rc_web_server_config, repos, rcextensions):
121 request, vcsserver_factory, available_port_factory,
163 """
122 rc_web_server_config_factory, repos, rcextensions):
164 Run the web server as a subprocess.
165
166 Since we have already a running vcsserver, this is not spawned again.
167 """
123 """
168 env = os.environ.copy()
124 Run the web server as a subprocess. with it's own instance of vcsserver
169 env['RC_NO_TMP_PATH'] = '1'
125 """
170
126
171 rc_log = list(RC_LOG.partition('.log'))
127 vcsserver_port = available_port_factory()
172 rc_log.insert(1, get_port(rc_web_server_config))
128 print('Using vcsserver ops test port {}'.format(vcsserver_port))
173 rc_log = ''.join(rc_log)
174
129
175 server_out = open(rc_log, 'w')
130 vcs_log = os.path.join(tempfile.gettempdir(), 'rc_op_vcs.log')
176
131 vcsserver_factory(
177 host_url = 'http://' + get_host_url(rc_web_server_config)
132 request, vcsserver_port=vcsserver_port,
178 assert_no_running_instance(host_url)
133 log_file=vcs_log,
179 command = ['gunicorn', '--worker-class', 'gevent', '--paste', rc_web_server_config]
134 overrides=({'server:main': {'workers': 2}},))
180
135
181 print('rhodecode-web starting at: {}'.format(host_url))
136 rc_log = os.path.join(tempfile.gettempdir(), 'rc_op_web.log')
182 print('rhodecode-web command: {}'.format(command))
137 rc_web_server_config = rc_web_server_config_factory(
183 print('rhodecode-web logfile: {}'.format(rc_log))
138 vcsserver_port=vcsserver_port)
184
139 server = RcWebServer(rc_web_server_config, log_file=rc_log)
185 proc = subprocess32.Popen(
140 server.start()
186 command, bufsize=0, env=env, stdout=server_out, stderr=server_out)
187
188 wait_for_url(host_url, timeout=30)
189
141
190 @request.addfinalizer
142 @request.addfinalizer
191 def stop_web_server():
143 def cleanup():
192 # TODO: Find out how to integrate with the reporting of py.test to
144 server.shutdown()
193 # make this information available.
194 print("\nServer log file written to %s" % (rc_log, ))
195 proc.kill()
196 server_out.flush()
197 server_out.close()
198
145
199 return RcWebServer(rc_web_server_config, log_file=rc_log)
146 server.wait_until_ready()
147 return server
200
148
201
149
202 @pytest.fixture
150 @pytest.fixture
203 def disable_locking(baseapp):
151 def disable_locking(baseapp):
204 r = Repository.get_by_repo_name(GIT_REPO)
152 r = Repository.get_by_repo_name(GIT_REPO)
205 Repository.unlock(r)
153 Repository.unlock(r)
206 r.enable_locking = False
154 r.enable_locking = False
207 Session().add(r)
155 Session().add(r)
208 Session().commit()
156 Session().commit()
209
157
210 r = Repository.get_by_repo_name(HG_REPO)
158 r = Repository.get_by_repo_name(HG_REPO)
211 Repository.unlock(r)
159 Repository.unlock(r)
212 r.enable_locking = False
160 r.enable_locking = False
213 Session().add(r)
161 Session().add(r)
214 Session().commit()
162 Session().commit()
215
163
216
164
217 @pytest.fixture
165 @pytest.fixture
218 def enable_auth_plugins(request, baseapp, csrf_token):
166 def enable_auth_plugins(request, baseapp, csrf_token):
219 """
167 """
220 Return a factory object that when called, allows to control which
168 Return a factory object that when called, allows to control which
221 authentication plugins are enabled.
169 authentication plugins are enabled.
222 """
170 """
223 def _enable_plugins(plugins_list, override=None):
171 def _enable_plugins(plugins_list, override=None):
224 override = override or {}
172 override = override or {}
225 params = {
173 params = {
226 'auth_plugins': ','.join(plugins_list),
174 'auth_plugins': ','.join(plugins_list),
227 }
175 }
228
176
229 # helper translate some names to others
177 # helper translate some names to others
230 name_map = {
178 name_map = {
231 'token': 'authtoken'
179 'token': 'authtoken'
232 }
180 }
233
181
234 for module in plugins_list:
182 for module in plugins_list:
235 plugin_name = module.partition('#')[-1]
183 plugin_name = module.partition('#')[-1]
236 if plugin_name in name_map:
184 if plugin_name in name_map:
237 plugin_name = name_map[plugin_name]
185 plugin_name = name_map[plugin_name]
238 enabled_plugin = 'auth_%s_enabled' % plugin_name
186 enabled_plugin = 'auth_%s_enabled' % plugin_name
239 cache_ttl = 'auth_%s_cache_ttl' % plugin_name
187 cache_ttl = 'auth_%s_cache_ttl' % plugin_name
240
188
241 # default params that are needed for each plugin,
189 # default params that are needed for each plugin,
242 # `enabled` and `cache_ttl`
190 # `enabled` and `cache_ttl`
243 params.update({
191 params.update({
244 enabled_plugin: True,
192 enabled_plugin: True,
245 cache_ttl: 0
193 cache_ttl: 0
246 })
194 })
247 if override.get:
195 if override.get:
248 params.update(override.get(module, {}))
196 params.update(override.get(module, {}))
249
197
250 validated_params = params
198 validated_params = params
251 for k, v in validated_params.items():
199 for k, v in validated_params.items():
252 setting = SettingsModel().create_or_update_setting(k, v)
200 setting = SettingsModel().create_or_update_setting(k, v)
253 Session().add(setting)
201 Session().add(setting)
254 Session().commit()
202 Session().commit()
255
203
256 def cleanup():
204 def cleanup():
257 _enable_plugins(['egg:rhodecode-enterprise-ce#rhodecode'])
205 _enable_plugins(['egg:rhodecode-enterprise-ce#rhodecode'])
258
206
259 request.addfinalizer(cleanup)
207 request.addfinalizer(cleanup)
260
208
261 return _enable_plugins
209 return _enable_plugins
262
210
263
211
264 @pytest.fixture
212 @pytest.fixture
265 def fs_repo_only(request, rhodecode_fixtures):
213 def fs_repo_only(request, rhodecode_fixtures):
266 def fs_repo_fabric(repo_name, repo_type):
214 def fs_repo_fabric(repo_name, repo_type):
267 rhodecode_fixtures.create_repo(repo_name, repo_type=repo_type)
215 rhodecode_fixtures.create_repo(repo_name, repo_type=repo_type)
268 rhodecode_fixtures.destroy_repo(repo_name, fs_remove=False)
216 rhodecode_fixtures.destroy_repo(repo_name, fs_remove=False)
269
217
270 def cleanup():
218 def cleanup():
271 rhodecode_fixtures.destroy_repo(repo_name, fs_remove=True)
219 rhodecode_fixtures.destroy_repo(repo_name, fs_remove=True)
272 rhodecode_fixtures.destroy_repo_on_filesystem(repo_name)
220 rhodecode_fixtures.destroy_repo_on_filesystem(repo_name)
273
221
274 request.addfinalizer(cleanup)
222 request.addfinalizer(cleanup)
275
223
276 return fs_repo_fabric
224 return fs_repo_fabric
225
226
227 @pytest.fixture
228 def enable_webhook_push_integration(request):
229 integration = Integration()
230 integration.integration_type = WebhookIntegrationType.key
231 Session().add(integration)
232
233 settings = dict(
234 url='http://httpbin.org',
235 secret_token='secret',
236 username=None,
237 password=None,
238 custom_header_key=None,
239 custom_header_val=None,
240 method_type='get',
241 events=[events.RepoPushEvent.name],
242 log_data=True
243 )
244
245 IntegrationModel().update_integration(
246 integration,
247 name='IntegrationWebhookTest',
248 enabled=True,
249 settings=settings,
250 repo=None,
251 repo_group=None,
252 child_repos_only=False,
253 )
254 Session().commit()
255 integration_id = integration.integration_id
256
257 @request.addfinalizer
258 def cleanup():
259 integration = Integration.get(integration_id)
260 Session().delete(integration)
261 Session().commit()
262
@@ -1,59 +1,57 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 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 Test suite for making push/pull operations, on specially modified INI files
22 Test suite for making push/pull operations, on specially modified INI files
23
23
24 .. important::
24 .. important::
25
25
26 You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
26 You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
27 to redirect things to stderr instead of stdout.
27 to redirect things to stderr instead of stdout.
28 """
28 """
29
29
30 import pytest
30 import pytest
31
31
32 from rhodecode.tests import (GIT_REPO, HG_REPO)
32 from rhodecode.tests import (GIT_REPO, HG_REPO)
33 from rhodecode.tests.vcs_operations import Command
33 from rhodecode.tests.vcs_operations import Command
34
34
35
35
36 # override rc_web_server_config fixture with custom INI
36 @pytest.fixture(scope="module")
37 @pytest.fixture(scope='module')
37 def rc_web_server_config_modification():
38 def rc_web_server_config(testini_factory):
38 return [
39 CUSTOM_PARAMS = [
40 {'app:main': {'auth_ret_code': '403'}},
39 {'app:main': {'auth_ret_code': '403'}},
41 {'app:main': {'auth_ret_code_detection': 'true'}},
40 {'app:main': {'auth_ret_code_detection': 'true'}},
42 ]
41 ]
43 return testini_factory(CUSTOM_PARAMS)
44
42
45
43
46 @pytest.mark.usefixtures("disable_locking", "disable_anonymous_user")
44 @pytest.mark.usefixtures("disable_locking", "disable_anonymous_user")
47 class TestVCSOperationsOnCustomIniConfig(object):
45 class TestVCSOperationsOnCustomIniConfig(object):
48
46
49 def test_clone_wrong_credentials_hg_ret_code(self, rc_web_server, tmpdir):
47 def test_clone_wrong_credentials_hg_ret_code(self, rc_web_server, tmpdir):
50 clone_url = rc_web_server.repo_clone_url(HG_REPO, passwd='bad!')
48 clone_url = rc_web_server.repo_clone_url(HG_REPO, passwd='bad!')
51 stdout, stderr = Command('/tmp').execute(
49 stdout, stderr = Command('/tmp').execute(
52 'hg clone', clone_url, tmpdir.strpath)
50 'hg clone', clone_url, tmpdir.strpath)
53 assert 'abort: HTTP Error 403: Forbidden' in stderr
51 assert 'abort: HTTP Error 403: Forbidden' in stderr
54
52
55 def test_clone_wrong_credentials_git_ret_code(self, rc_web_server, tmpdir):
53 def test_clone_wrong_credentials_git_ret_code(self, rc_web_server, tmpdir):
56 clone_url = rc_web_server.repo_clone_url(GIT_REPO, passwd='bad!')
54 clone_url = rc_web_server.repo_clone_url(GIT_REPO, passwd='bad!')
57 stdout, stderr = Command('/tmp').execute(
55 stdout, stderr = Command('/tmp').execute(
58 'git clone', clone_url, tmpdir.strpath)
56 'git clone', clone_url, tmpdir.strpath)
59 assert 'The requested URL returned error: 403' in stderr
57 assert 'The requested URL returned error: 403' in stderr
@@ -1,59 +1,57 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 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 Test suite for making push/pull operations, on specially modified INI files
22 Test suite for making push/pull operations, on specially modified INI files
23
23
24 .. important::
24 .. important::
25
25
26 You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
26 You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
27 to redirect things to stderr instead of stdout.
27 to redirect things to stderr instead of stdout.
28 """
28 """
29
29
30 import pytest
30 import pytest
31
31
32 from rhodecode.tests import (GIT_REPO, HG_REPO)
32 from rhodecode.tests import (GIT_REPO, HG_REPO)
33 from rhodecode.tests.vcs_operations import Command
33 from rhodecode.tests.vcs_operations import Command
34
34
35
35
36 # override rc_web_server_config fixture with custom INI
36 @pytest.fixture(scope="module")
37 @pytest.fixture(scope='module')
37 def rc_web_server_config_modification():
38 def rc_web_server_config(testini_factory):
38 return [
39 CUSTOM_PARAMS = [
40 {'app:main': {'auth_ret_code': '404'}},
39 {'app:main': {'auth_ret_code': '404'}},
41 {'app:main': {'auth_ret_code_detection': 'false'}},
40 {'app:main': {'auth_ret_code_detection': 'false'}},
42 ]
41 ]
43 return testini_factory(CUSTOM_PARAMS)
44
42
45
43
46 @pytest.mark.usefixtures("disable_locking", "disable_anonymous_user")
44 @pytest.mark.usefixtures("disable_locking", "disable_anonymous_user")
47 class TestVCSOperationsOnCustomIniConfig(object):
45 class TestVCSOperationsOnCustomIniConfig(object):
48
46
49 def test_clone_wrong_credentials_hg_ret_code(self, rc_web_server, tmpdir):
47 def test_clone_wrong_credentials_hg_ret_code(self, rc_web_server, tmpdir):
50 clone_url = rc_web_server.repo_clone_url(HG_REPO, passwd='bad!')
48 clone_url = rc_web_server.repo_clone_url(HG_REPO, passwd='bad!')
51 stdout, stderr = Command('/tmp').execute(
49 stdout, stderr = Command('/tmp').execute(
52 'hg clone', clone_url, tmpdir.strpath)
50 'hg clone', clone_url, tmpdir.strpath)
53 assert 'abort: HTTP Error 404: Not Found' in stderr
51 assert 'abort: HTTP Error 404: Not Found' in stderr
54
52
55 def test_clone_wrong_credentials_git_ret_code(self, rc_web_server, tmpdir):
53 def test_clone_wrong_credentials_git_ret_code(self, rc_web_server, tmpdir):
56 clone_url = rc_web_server.repo_clone_url(GIT_REPO, passwd='bad!')
54 clone_url = rc_web_server.repo_clone_url(GIT_REPO, passwd='bad!')
57 stdout, stderr = Command('/tmp').execute(
55 stdout, stderr = Command('/tmp').execute(
58 'git clone', clone_url, tmpdir.strpath)
56 'git clone', clone_url, tmpdir.strpath)
59 assert 'not found' in stderr
57 assert 'not found' in stderr
@@ -1,59 +1,57 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 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 Test suite for making push/pull operations, on specially modified INI files
22 Test suite for making push/pull operations, on specially modified INI files
23
23
24 .. important::
24 .. important::
25
25
26 You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
26 You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
27 to redirect things to stderr instead of stdout.
27 to redirect things to stderr instead of stdout.
28 """
28 """
29
29
30 import pytest
30 import pytest
31
31
32 from rhodecode.tests import (GIT_REPO, HG_REPO)
32 from rhodecode.tests import (GIT_REPO, HG_REPO)
33 from rhodecode.tests.vcs_operations import Command
33 from rhodecode.tests.vcs_operations import Command
34
34
35
35
36 # override rc_web_server_config fixture with custom INI
36 @pytest.fixture(scope="module")
37 @pytest.fixture(scope='module')
37 def rc_web_server_config_modification():
38 def rc_web_server_config(testini_factory):
38 return [
39 CUSTOM_PARAMS = [
40 {'app:main': {'auth_ret_code': '600'}},
39 {'app:main': {'auth_ret_code': '600'}},
41 {'app:main': {'auth_ret_code_detection': 'false'}},
40 {'app:main': {'auth_ret_code_detection': 'false'}},
42 ]
41 ]
43 return testini_factory(CUSTOM_PARAMS)
44
42
45
43
46 @pytest.mark.usefixtures("disable_locking", "disable_anonymous_user")
44 @pytest.mark.usefixtures("disable_locking", "disable_anonymous_user")
47 class TestVCSOperationsOnCustomIniConfig(object):
45 class TestVCSOperationsOnCustomIniConfig(object):
48
46
49 def test_clone_wrong_credentials_hg_ret_code(self, rc_web_server, tmpdir):
47 def test_clone_wrong_credentials_hg_ret_code(self, rc_web_server, tmpdir):
50 clone_url = rc_web_server.repo_clone_url(HG_REPO, passwd='bad!')
48 clone_url = rc_web_server.repo_clone_url(HG_REPO, passwd='bad!')
51 stdout, stderr = Command('/tmp').execute(
49 stdout, stderr = Command('/tmp').execute(
52 'hg clone', clone_url, tmpdir.strpath)
50 'hg clone', clone_url, tmpdir.strpath)
53 assert 'abort: HTTP Error 403: Forbidden' in stderr
51 assert 'abort: HTTP Error 403: Forbidden' in stderr
54
52
55 def test_clone_wrong_credentials_git_ret_code(self, rc_web_server, tmpdir):
53 def test_clone_wrong_credentials_git_ret_code(self, rc_web_server, tmpdir):
56 clone_url = rc_web_server.repo_clone_url(GIT_REPO, passwd='bad!')
54 clone_url = rc_web_server.repo_clone_url(GIT_REPO, passwd='bad!')
57 stdout, stderr = Command('/tmp').execute(
55 stdout, stderr = Command('/tmp').execute(
58 'git clone', clone_url, tmpdir.strpath)
56 'git clone', clone_url, tmpdir.strpath)
59 assert 'The requested URL returned error: 403' in stderr
57 assert 'The requested URL returned error: 403' in stderr
@@ -1,79 +1,67 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 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 Test suite for making push/pull operations, on specially modified INI files
22 Test suite for making push/pull operations, on specially modified INI files
23
23
24 .. important::
24 .. important::
25
25
26 You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
26 You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
27 to redirect things to stderr instead of stdout.
27 to redirect things to stderr instead of stdout.
28 """
28 """
29
29
30 import os
30 import os
31 import pytest
31 import pytest
32
32
33 from rhodecode.lib.vcs.backends.git.repository import GitRepository
33 from rhodecode.lib.vcs.backends.git.repository import GitRepository
34 from rhodecode.lib.vcs.nodes import FileNode
34 from rhodecode.lib.vcs.nodes import FileNode
35 from rhodecode.tests import GIT_REPO
35 from rhodecode.tests import GIT_REPO
36 from rhodecode.tests.vcs_operations import Command
36 from rhodecode.tests.vcs_operations import Command
37 from .test_vcs_operations import _check_proper_clone, _check_proper_git_push
37 from .test_vcs_operations import _check_proper_clone, _check_proper_git_push
38
38
39
39
40 # override rc_web_server_config fixture with custom INI
41 @pytest.fixture(scope="module")
42 def rc_web_server_config(testini_factory):
43 """
44 Configuration file used for the fixture `rc_web_server`.
45 """
46 CUSTOM_PARAMS = [
47 {'handler_console': {'level': 'DEBUG'}},
48 ]
49 return testini_factory(CUSTOM_PARAMS)
50
51
52 def test_git_clone_with_small_push_buffer(backend_git, rc_web_server, tmpdir):
40 def test_git_clone_with_small_push_buffer(backend_git, rc_web_server, tmpdir):
53 clone_url = rc_web_server.repo_clone_url(GIT_REPO)
41 clone_url = rc_web_server.repo_clone_url(GIT_REPO)
54 cmd = Command('/tmp')
42 cmd = Command('/tmp')
55 stdout, stderr = cmd.execute(
43 stdout, stderr = cmd.execute(
56 'git -c http.postBuffer=1024 clone', clone_url, tmpdir.strpath)
44 'git -c http.postBuffer=1024 clone', clone_url, tmpdir.strpath)
57 _check_proper_clone(stdout, stderr, 'git')
45 _check_proper_clone(stdout, stderr, 'git')
58 cmd.assert_returncode_success()
46 cmd.assert_returncode_success()
59
47
60
48
61 def test_git_push_with_small_push_buffer(backend_git, rc_web_server, tmpdir):
49 def test_git_push_with_small_push_buffer(backend_git, rc_web_server, tmpdir):
62 empty_repo = backend_git.create_repo()
50 empty_repo = backend_git.create_repo()
63
51
64 clone_url = rc_web_server.repo_clone_url(empty_repo.repo_name)
52 clone_url = rc_web_server.repo_clone_url(empty_repo.repo_name)
65
53
66 cmd = Command(tmpdir.strpath)
54 cmd = Command(tmpdir.strpath)
67 cmd.execute('git clone', clone_url)
55 cmd.execute('git clone', clone_url)
68
56
69 repo = GitRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
57 repo = GitRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
70 repo.in_memory_commit.add(FileNode('readme.md', content='## Hello'))
58 repo.in_memory_commit.add(FileNode('readme.md', content='## Hello'))
71 repo.in_memory_commit.commit(
59 repo.in_memory_commit.commit(
72 message='Commit on branch Master',
60 message='Commit on branch Master',
73 author='Automatic test',
61 author='Automatic test',
74 branch='master')
62 branch='master')
75
63
76 repo_cmd = Command(repo.path)
64 repo_cmd = Command(repo.path)
77 stdout, stderr = repo_cmd.execute(
65 stdout, stderr = repo_cmd.execute(
78 'git -c http.postBuffer=1024 push --verbose origin master')
66 'git -c http.postBuffer=1024 push --verbose origin master')
79 _check_proper_git_push(stdout, stderr, branch='master')
67 _check_proper_git_push(stdout, stderr, branch='master')
@@ -1,222 +1,220 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 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 Test suite for making push/pull operations, on specially modified INI files
22 Test suite for making push/pull operations, on specially modified INI files
23
23
24 .. important::
24 .. important::
25
25
26 You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
26 You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
27 to redirect things to stderr instead of stdout.
27 to redirect things to stderr instead of stdout.
28 """
28 """
29
29
30
30
31 import pytest
31 import pytest
32
32
33 from rhodecode.model.db import User, Repository
33 from rhodecode.model.db import User, Repository
34 from rhodecode.model.meta import Session
34 from rhodecode.model.meta import Session
35 from rhodecode.model.repo import RepoModel
35 from rhodecode.model.repo import RepoModel
36
36
37 from rhodecode.tests import (
37 from rhodecode.tests import (
38 GIT_REPO, HG_REPO, TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN,
38 GIT_REPO, HG_REPO, TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN,
39 TEST_USER_REGULAR_PASS)
39 TEST_USER_REGULAR_PASS)
40 from rhodecode.tests.vcs_operations import (
40 from rhodecode.tests.vcs_operations import (
41 Command, _check_proper_clone, _check_proper_git_push, _add_files_and_push)
41 Command, _check_proper_clone, _check_proper_git_push, _add_files_and_push)
42
42
43
43
44 # override rc_web_server_config fixture with custom INI
44 @pytest.fixture(scope="module")
45 @pytest.fixture(scope='module')
45 def rc_web_server_config_modification():
46 def rc_web_server_config(testini_factory):
46 return [
47 CUSTOM_PARAMS = [
48 {'app:main': {'lock_ret_code': '423'}},
47 {'app:main': {'lock_ret_code': '423'}},
49 ]
48 ]
50 return testini_factory(CUSTOM_PARAMS)
51
49
52
50
53 @pytest.mark.usefixtures("disable_locking", "disable_anonymous_user")
51 @pytest.mark.usefixtures("disable_locking", "disable_anonymous_user")
54 class TestVCSOperationsOnCustomIniConfig(object):
52 class TestVCSOperationsOnCustomIniConfig(object):
55
53
56 def test_clone_and_create_lock_hg(self, rc_web_server, tmpdir):
54 def test_clone_and_create_lock_hg(self, rc_web_server, tmpdir):
57 # enable locking
55 # enable locking
58 r = Repository.get_by_repo_name(HG_REPO)
56 r = Repository.get_by_repo_name(HG_REPO)
59 r.enable_locking = True
57 r.enable_locking = True
60 Session().add(r)
58 Session().add(r)
61 Session().commit()
59 Session().commit()
62 # clone
60 # clone
63 clone_url = rc_web_server.repo_clone_url(HG_REPO)
61 clone_url = rc_web_server.repo_clone_url(HG_REPO)
64 stdout, stderr = Command('/tmp').execute(
62 stdout, stderr = Command('/tmp').execute(
65 'hg clone', clone_url, tmpdir.strpath)
63 'hg clone', clone_url, tmpdir.strpath)
66
64
67 # check if lock was made
65 # check if lock was made
68 r = Repository.get_by_repo_name(HG_REPO)
66 r = Repository.get_by_repo_name(HG_REPO)
69 assert r.locked[0] == User.get_by_username(
67 assert r.locked[0] == User.get_by_username(
70 TEST_USER_ADMIN_LOGIN).user_id
68 TEST_USER_ADMIN_LOGIN).user_id
71
69
72 def test_clone_and_create_lock_git(self, rc_web_server, tmpdir):
70 def test_clone_and_create_lock_git(self, rc_web_server, tmpdir):
73 # enable locking
71 # enable locking
74 r = Repository.get_by_repo_name(GIT_REPO)
72 r = Repository.get_by_repo_name(GIT_REPO)
75 r.enable_locking = True
73 r.enable_locking = True
76 Session().add(r)
74 Session().add(r)
77 Session().commit()
75 Session().commit()
78 # clone
76 # clone
79 clone_url = rc_web_server.repo_clone_url(GIT_REPO)
77 clone_url = rc_web_server.repo_clone_url(GIT_REPO)
80 stdout, stderr = Command('/tmp').execute(
78 stdout, stderr = Command('/tmp').execute(
81 'git clone', clone_url, tmpdir.strpath)
79 'git clone', clone_url, tmpdir.strpath)
82
80
83 # check if lock was made
81 # check if lock was made
84 r = Repository.get_by_repo_name(GIT_REPO)
82 r = Repository.get_by_repo_name(GIT_REPO)
85 assert r.locked[0] == User.get_by_username(
83 assert r.locked[0] == User.get_by_username(
86 TEST_USER_ADMIN_LOGIN).user_id
84 TEST_USER_ADMIN_LOGIN).user_id
87
85
88 def test_clone_after_repo_was_locked_hg(self, rc_web_server, tmpdir):
86 def test_clone_after_repo_was_locked_hg(self, rc_web_server, tmpdir):
89 # lock repo
87 # lock repo
90 r = Repository.get_by_repo_name(HG_REPO)
88 r = Repository.get_by_repo_name(HG_REPO)
91 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
89 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
92 # pull fails since repo is locked
90 # pull fails since repo is locked
93 clone_url = rc_web_server.repo_clone_url(HG_REPO)
91 clone_url = rc_web_server.repo_clone_url(HG_REPO)
94 stdout, stderr = Command('/tmp').execute(
92 stdout, stderr = Command('/tmp').execute(
95 'hg clone', clone_url, tmpdir.strpath)
93 'hg clone', clone_url, tmpdir.strpath)
96 msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
94 msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
97 % (HG_REPO, TEST_USER_ADMIN_LOGIN))
95 % (HG_REPO, TEST_USER_ADMIN_LOGIN))
98 assert msg in stderr
96 assert msg in stderr
99
97
100 def test_clone_after_repo_was_locked_git(self, rc_web_server, tmpdir):
98 def test_clone_after_repo_was_locked_git(self, rc_web_server, tmpdir):
101 # lock repo
99 # lock repo
102 r = Repository.get_by_repo_name(GIT_REPO)
100 r = Repository.get_by_repo_name(GIT_REPO)
103 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
101 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
104 # pull fails since repo is locked
102 # pull fails since repo is locked
105 clone_url = rc_web_server.repo_clone_url(GIT_REPO)
103 clone_url = rc_web_server.repo_clone_url(GIT_REPO)
106 stdout, stderr = Command('/tmp').execute(
104 stdout, stderr = Command('/tmp').execute(
107 'git clone', clone_url, tmpdir.strpath)
105 'git clone', clone_url, tmpdir.strpath)
108
106
109 lock_msg = (
107 lock_msg = (
110 'remote: ERROR: Repository `vcs_test_git` locked by user ' +
108 'remote: ERROR: Repository `vcs_test_git` locked by user ' +
111 '`test_admin`. Reason:`lock_auto`')
109 '`test_admin`. Reason:`lock_auto`')
112 assert lock_msg in stderr
110 assert lock_msg in stderr
113 assert 'remote: Pre pull hook failed: aborting' in stderr
111 assert 'remote: Pre pull hook failed: aborting' in stderr
114 assert 'fatal: remote did not send all necessary objects' in stderr
112 assert 'fatal: remote did not send all necessary objects' in stderr
115
113
116 def test_push_on_locked_repo_by_other_user_hg(self, rc_web_server, tmpdir):
114 def test_push_on_locked_repo_by_other_user_hg(self, rc_web_server, tmpdir):
117 clone_url = rc_web_server.repo_clone_url(HG_REPO)
115 clone_url = rc_web_server.repo_clone_url(HG_REPO)
118 stdout, stderr = Command('/tmp').execute(
116 stdout, stderr = Command('/tmp').execute(
119 'hg clone', clone_url, tmpdir.strpath)
117 'hg clone', clone_url, tmpdir.strpath)
120
118
121 # lock repo
119 # lock repo
122 r = Repository.get_by_repo_name(HG_REPO)
120 r = Repository.get_by_repo_name(HG_REPO)
123 # let this user actually push !
121 # let this user actually push !
124 RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
122 RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
125 perm='repository.write')
123 perm='repository.write')
126 Session().commit()
124 Session().commit()
127 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
125 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
128
126
129 # push fails repo is locked by other user !
127 # push fails repo is locked by other user !
130 push_url = rc_web_server.repo_clone_url(
128 push_url = rc_web_server.repo_clone_url(
131 HG_REPO,
129 HG_REPO,
132 user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS)
130 user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS)
133 stdout, stderr = _add_files_and_push(
131 stdout, stderr = _add_files_and_push(
134 'hg', tmpdir.strpath, clone_url=push_url)
132 'hg', tmpdir.strpath, clone_url=push_url)
135 msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
133 msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
136 % (HG_REPO, TEST_USER_ADMIN_LOGIN))
134 % (HG_REPO, TEST_USER_ADMIN_LOGIN))
137 assert msg in stderr
135 assert msg in stderr
138
136
139 def test_push_on_locked_repo_by_other_user_git(
137 def test_push_on_locked_repo_by_other_user_git(
140 self, rc_web_server, tmpdir):
138 self, rc_web_server, tmpdir):
141 clone_url = rc_web_server.repo_clone_url(GIT_REPO)
139 clone_url = rc_web_server.repo_clone_url(GIT_REPO)
142 stdout, stderr = Command('/tmp').execute(
140 stdout, stderr = Command('/tmp').execute(
143 'git clone', clone_url, tmpdir.strpath)
141 'git clone', clone_url, tmpdir.strpath)
144
142
145 # lock repo
143 # lock repo
146 r = Repository.get_by_repo_name(GIT_REPO)
144 r = Repository.get_by_repo_name(GIT_REPO)
147 # let this user actually push !
145 # let this user actually push !
148 RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
146 RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
149 perm='repository.write')
147 perm='repository.write')
150 Session().commit()
148 Session().commit()
151 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
149 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
152
150
153 # push fails repo is locked by other user!
151 # push fails repo is locked by other user!
154 push_url = rc_web_server.repo_clone_url(
152 push_url = rc_web_server.repo_clone_url(
155 GIT_REPO,
153 GIT_REPO,
156 user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS)
154 user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS)
157 stdout, stderr = _add_files_and_push(
155 stdout, stderr = _add_files_and_push(
158 'git', tmpdir.strpath, clone_url=push_url)
156 'git', tmpdir.strpath, clone_url=push_url)
159
157
160 err = 'Repository `%s` locked by user `%s`' % (
158 err = 'Repository `%s` locked by user `%s`' % (
161 GIT_REPO, TEST_USER_ADMIN_LOGIN)
159 GIT_REPO, TEST_USER_ADMIN_LOGIN)
162 # err = 'RPC failed; result=22, HTTP code = 423'
160 # err = 'RPC failed; result=22, HTTP code = 423'
163 assert err in stderr
161 assert err in stderr
164
162
165 def test_push_unlocks_repository_hg(self, rc_web_server, tmpdir):
163 def test_push_unlocks_repository_hg(self, rc_web_server, tmpdir):
166 # enable locking
164 # enable locking
167 r = Repository.get_by_repo_name(HG_REPO)
165 r = Repository.get_by_repo_name(HG_REPO)
168 r.enable_locking = True
166 r.enable_locking = True
169 Session().add(r)
167 Session().add(r)
170 Session().commit()
168 Session().commit()
171
169
172 clone_url = rc_web_server.repo_clone_url(HG_REPO)
170 clone_url = rc_web_server.repo_clone_url(HG_REPO)
173 stdout, stderr = Command('/tmp').execute(
171 stdout, stderr = Command('/tmp').execute(
174 'hg clone', clone_url, tmpdir.strpath)
172 'hg clone', clone_url, tmpdir.strpath)
175 _check_proper_clone(stdout, stderr, 'hg')
173 _check_proper_clone(stdout, stderr, 'hg')
176
174
177 # check for lock repo after clone
175 # check for lock repo after clone
178 r = Repository.get_by_repo_name(HG_REPO)
176 r = Repository.get_by_repo_name(HG_REPO)
179 uid = User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
177 uid = User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
180 assert r.locked[0] == uid
178 assert r.locked[0] == uid
181
179
182 # push is ok and repo is now unlocked
180 # push is ok and repo is now unlocked
183 stdout, stderr = _add_files_and_push(
181 stdout, stderr = _add_files_and_push(
184 'hg', tmpdir.strpath, clone_url=clone_url)
182 'hg', tmpdir.strpath, clone_url=clone_url)
185 assert ('remote: Released lock on repo `%s`' % HG_REPO) in stdout
183 assert ('remote: Released lock on repo `%s`' % HG_REPO) in stdout
186 # we need to cleanup the Session Here !
184 # we need to cleanup the Session Here !
187 Session.remove()
185 Session.remove()
188 r = Repository.get_by_repo_name(HG_REPO)
186 r = Repository.get_by_repo_name(HG_REPO)
189 assert r.locked == [None, None, None]
187 assert r.locked == [None, None, None]
190
188
191 def test_push_unlocks_repository_git(self, rc_web_server, tmpdir):
189 def test_push_unlocks_repository_git(self, rc_web_server, tmpdir):
192
190
193 # Note: Did a first debugging session. Seems that
191 # Note: Did a first debugging session. Seems that
194 # Repository.get_locking_state is called twice. The second call
192 # Repository.get_locking_state is called twice. The second call
195 # has the action "pull" and does not reset the lock.
193 # has the action "pull" and does not reset the lock.
196
194
197 # enable locking
195 # enable locking
198 r = Repository.get_by_repo_name(GIT_REPO)
196 r = Repository.get_by_repo_name(GIT_REPO)
199 r.enable_locking = True
197 r.enable_locking = True
200 Session().add(r)
198 Session().add(r)
201 Session().commit()
199 Session().commit()
202
200
203 clone_url = rc_web_server.repo_clone_url(GIT_REPO)
201 clone_url = rc_web_server.repo_clone_url(GIT_REPO)
204 stdout, stderr = Command('/tmp').execute(
202 stdout, stderr = Command('/tmp').execute(
205 'git clone', clone_url, tmpdir.strpath)
203 'git clone', clone_url, tmpdir.strpath)
206 _check_proper_clone(stdout, stderr, 'git')
204 _check_proper_clone(stdout, stderr, 'git')
207
205
208 # check for lock repo after clone
206 # check for lock repo after clone
209 r = Repository.get_by_repo_name(GIT_REPO)
207 r = Repository.get_by_repo_name(GIT_REPO)
210 assert r.locked[0] == User.get_by_username(
208 assert r.locked[0] == User.get_by_username(
211 TEST_USER_ADMIN_LOGIN).user_id
209 TEST_USER_ADMIN_LOGIN).user_id
212
210
213 # push is ok and repo is now unlocked
211 # push is ok and repo is now unlocked
214 stdout, stderr = _add_files_and_push(
212 stdout, stderr = _add_files_and_push(
215 'git', tmpdir.strpath, clone_url=clone_url)
213 'git', tmpdir.strpath, clone_url=clone_url)
216 _check_proper_git_push(stdout, stderr)
214 _check_proper_git_push(stdout, stderr)
217
215
218 # assert ('remote: Released lock on repo `%s`' % GIT_REPO) in stdout
216 # assert ('remote: Released lock on repo `%s`' % GIT_REPO) in stdout
219 # we need to cleanup the Session Here !
217 # we need to cleanup the Session Here !
220 Session.remove()
218 Session.remove()
221 r = Repository.get_by_repo_name(GIT_REPO)
219 r = Repository.get_by_repo_name(GIT_REPO)
222 assert r.locked == [None, None, None]
220 assert r.locked == [None, None, None]
@@ -1,130 +1,128 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 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 Test suite for making push/pull operations, on specially modified INI files
22 Test suite for making push/pull operations, on specially modified INI files
23
23
24 .. important::
24 .. important::
25
25
26 You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
26 You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
27 to redirect things to stderr instead of stdout.
27 to redirect things to stderr instead of stdout.
28 """
28 """
29
29
30
30
31 import pytest
31 import pytest
32
32
33 from rhodecode.model.db import User, Repository
33 from rhodecode.model.db import User, Repository
34 from rhodecode.model.meta import Session
34 from rhodecode.model.meta import Session
35 from rhodecode.model.repo import RepoModel
35 from rhodecode.model.repo import RepoModel
36
36
37 from rhodecode.tests import (
37 from rhodecode.tests import (
38 GIT_REPO, HG_REPO, TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN,
38 GIT_REPO, HG_REPO, TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN,
39 TEST_USER_REGULAR_PASS)
39 TEST_USER_REGULAR_PASS)
40 from rhodecode.tests.vcs_operations import Command, _add_files_and_push
40 from rhodecode.tests.vcs_operations import Command, _add_files_and_push
41
41
42
42
43 # override rc_web_server_config fixture with custom INI
43 @pytest.fixture(scope="module")
44 @pytest.fixture(scope='module')
44 def rc_web_server_config_modification():
45 def rc_web_server_config(testini_factory):
45 return [
46 CUSTOM_PARAMS = [
47 {'app:main': {'lock_ret_code': '400'}},
46 {'app:main': {'lock_ret_code': '400'}},
48 ]
47 ]
49 return testini_factory(CUSTOM_PARAMS)
50
48
51
49
52 @pytest.mark.usefixtures("disable_locking", "disable_anonymous_user")
50 @pytest.mark.usefixtures("disable_locking", "disable_anonymous_user")
53 class TestVCSOperationsOnCustomIniConfig(object):
51 class TestVCSOperationsOnCustomIniConfig(object):
54
52
55 def test_clone_after_repo_was_locked_hg(self, rc_web_server, tmpdir):
53 def test_clone_after_repo_was_locked_hg(self, rc_web_server, tmpdir):
56 # lock repo
54 # lock repo
57 r = Repository.get_by_repo_name(HG_REPO)
55 r = Repository.get_by_repo_name(HG_REPO)
58 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
56 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
59 # pull fails since repo is locked
57 # pull fails since repo is locked
60 clone_url = rc_web_server.repo_clone_url(HG_REPO)
58 clone_url = rc_web_server.repo_clone_url(HG_REPO)
61 stdout, stderr = Command('/tmp').execute(
59 stdout, stderr = Command('/tmp').execute(
62 'hg clone', clone_url, tmpdir.strpath)
60 'hg clone', clone_url, tmpdir.strpath)
63 msg = ("""abort: HTTP Error 400: Repository `%s` locked by user `%s`"""
61 msg = ("""abort: HTTP Error 400: Repository `%s` locked by user `%s`"""
64 % (HG_REPO, TEST_USER_ADMIN_LOGIN))
62 % (HG_REPO, TEST_USER_ADMIN_LOGIN))
65 assert msg in stderr
63 assert msg in stderr
66
64
67 def test_clone_after_repo_was_locked_git(self, rc_web_server, tmpdir):
65 def test_clone_after_repo_was_locked_git(self, rc_web_server, tmpdir):
68 # lock repo
66 # lock repo
69 r = Repository.get_by_repo_name(GIT_REPO)
67 r = Repository.get_by_repo_name(GIT_REPO)
70 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
68 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
71 # pull fails since repo is locked
69 # pull fails since repo is locked
72 clone_url = rc_web_server.repo_clone_url(GIT_REPO)
70 clone_url = rc_web_server.repo_clone_url(GIT_REPO)
73 stdout, stderr = Command('/tmp').execute(
71 stdout, stderr = Command('/tmp').execute(
74 'git clone', clone_url, tmpdir.strpath)
72 'git clone', clone_url, tmpdir.strpath)
75
73
76 lock_msg = (
74 lock_msg = (
77 'remote: ERROR: Repository `vcs_test_git` locked by user ' +
75 'remote: ERROR: Repository `vcs_test_git` locked by user ' +
78 '`test_admin`. Reason:`lock_auto`')
76 '`test_admin`. Reason:`lock_auto`')
79 assert lock_msg in stderr
77 assert lock_msg in stderr
80 assert 'remote: Pre pull hook failed: aborting' in stderr
78 assert 'remote: Pre pull hook failed: aborting' in stderr
81 assert 'fatal: remote did not send all necessary objects' in stderr
79 assert 'fatal: remote did not send all necessary objects' in stderr
82
80
83 def test_push_on_locked_repo_by_other_user_hg(self, rc_web_server, tmpdir):
81 def test_push_on_locked_repo_by_other_user_hg(self, rc_web_server, tmpdir):
84 clone_url = rc_web_server.repo_clone_url(HG_REPO)
82 clone_url = rc_web_server.repo_clone_url(HG_REPO)
85 stdout, stderr = Command('/tmp').execute(
83 stdout, stderr = Command('/tmp').execute(
86 'hg clone', clone_url, tmpdir.strpath)
84 'hg clone', clone_url, tmpdir.strpath)
87
85
88 # lock repo
86 # lock repo
89 r = Repository.get_by_repo_name(HG_REPO)
87 r = Repository.get_by_repo_name(HG_REPO)
90 # let this user actually push !
88 # let this user actually push !
91 RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
89 RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
92 perm='repository.write')
90 perm='repository.write')
93 Session().commit()
91 Session().commit()
94 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
92 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
95
93
96 # push fails repo is locked by other user !
94 # push fails repo is locked by other user !
97 push_url = rc_web_server.repo_clone_url(
95 push_url = rc_web_server.repo_clone_url(
98 HG_REPO,
96 HG_REPO,
99 user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS)
97 user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS)
100 stdout, stderr = _add_files_and_push(
98 stdout, stderr = _add_files_and_push(
101 'hg', tmpdir.strpath, clone_url=push_url)
99 'hg', tmpdir.strpath, clone_url=push_url)
102 msg = ("""abort: HTTP Error 400: Repository `%s` locked by user `%s`"""
100 msg = ("""abort: HTTP Error 400: Repository `%s` locked by user `%s`"""
103 % (HG_REPO, TEST_USER_ADMIN_LOGIN))
101 % (HG_REPO, TEST_USER_ADMIN_LOGIN))
104 assert msg in stderr
102 assert msg in stderr
105
103
106 def test_push_on_locked_repo_by_other_user_git(
104 def test_push_on_locked_repo_by_other_user_git(
107 self, rc_web_server, tmpdir):
105 self, rc_web_server, tmpdir):
108 clone_url = rc_web_server.repo_clone_url(GIT_REPO)
106 clone_url = rc_web_server.repo_clone_url(GIT_REPO)
109 stdout, stderr = Command('/tmp').execute(
107 stdout, stderr = Command('/tmp').execute(
110 'git clone', clone_url, tmpdir.strpath)
108 'git clone', clone_url, tmpdir.strpath)
111
109
112 # lock repo
110 # lock repo
113 r = Repository.get_by_repo_name(GIT_REPO)
111 r = Repository.get_by_repo_name(GIT_REPO)
114 # let this user actually push !
112 # let this user actually push !
115 RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
113 RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
116 perm='repository.write')
114 perm='repository.write')
117 Session().commit()
115 Session().commit()
118 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
116 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
119
117
120 # push fails repo is locked by other user!
118 # push fails repo is locked by other user!
121 push_url = rc_web_server.repo_clone_url(
119 push_url = rc_web_server.repo_clone_url(
122 GIT_REPO,
120 GIT_REPO,
123 user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS)
121 user=TEST_USER_REGULAR_LOGIN, passwd=TEST_USER_REGULAR_PASS)
124 stdout, stderr = _add_files_and_push(
122 stdout, stderr = _add_files_and_push(
125 'git', tmpdir.strpath, clone_url=push_url)
123 'git', tmpdir.strpath, clone_url=push_url)
126
124
127 err = 'Repository `%s` locked by user `%s`' % (
125 err = 'Repository `%s` locked by user `%s`' % (
128 GIT_REPO, TEST_USER_ADMIN_LOGIN)
126 GIT_REPO, TEST_USER_ADMIN_LOGIN)
129
127
130 assert err in stderr
128 assert err in stderr
@@ -1,244 +1,244 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 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 os
21 import os
22
22
23 import pytest
23 import pytest
24
24
25 from rhodecode.lib.vcs.backends.git.repository import GitRepository
25 from rhodecode.lib.vcs.backends.git.repository import GitRepository
26 from rhodecode.lib.vcs.backends.hg.repository import MercurialRepository
26 from rhodecode.lib.vcs.backends.hg.repository import MercurialRepository
27 from rhodecode.lib.vcs.nodes import FileNode
27 from rhodecode.lib.vcs.nodes import FileNode
28 from rhodecode.model.meta import Session
28 from rhodecode.model.meta import Session
29
29
30 from rhodecode.tests.vcs_operations import (
30 from rhodecode.tests.vcs_operations import (
31 Command, _check_proper_clone, _check_proper_git_push, _check_proper_hg_push)
31 Command, _check_proper_clone, _check_proper_git_push, _check_proper_hg_push)
32
32
33
33
34 @pytest.mark.usefixtures("disable_locking")
34 @pytest.mark.usefixtures("disable_locking")
35 class TestVCSOperationsSpecial(object):
35 class TestVCSOperationsSpecial(object):
36
36
37 def test_git_sets_default_branch_if_not_master(
37 def test_git_sets_default_branch_if_not_master(
38 self, backend_git, tmpdir, rc_web_server):
38 self, backend_git, tmpdir, rc_web_server):
39 empty_repo = backend_git.create_repo()
39 empty_repo = backend_git.create_repo()
40 clone_url = rc_web_server.repo_clone_url(empty_repo.repo_name)
40 clone_url = rc_web_server.repo_clone_url(empty_repo.repo_name)
41
41
42 cmd = Command(tmpdir.strpath)
42 cmd = Command(tmpdir.strpath)
43 cmd.execute('git clone', clone_url)
43 cmd.execute('git clone', clone_url)
44
44
45 repo = GitRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
45 repo = GitRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
46 repo.in_memory_commit.add(FileNode('file', content=''))
46 repo.in_memory_commit.add(FileNode('file', content=''))
47 repo.in_memory_commit.commit(
47 repo.in_memory_commit.commit(
48 message='Commit on branch test',
48 message='Commit on branch test',
49 author='Automatic test',
49 author='Automatic test',
50 branch='test')
50 branch='test')
51
51
52 repo_cmd = Command(repo.path)
52 repo_cmd = Command(repo.path)
53 stdout, stderr = repo_cmd.execute('git push --verbose origin test')
53 stdout, stderr = repo_cmd.execute('git push --verbose origin test')
54 _check_proper_git_push(
54 _check_proper_git_push(
55 stdout, stderr, branch='test', should_set_default_branch=True)
55 stdout, stderr, branch='test', should_set_default_branch=True)
56
56
57 stdout, stderr = cmd.execute(
57 stdout, stderr = cmd.execute(
58 'git clone', clone_url, empty_repo.repo_name + '-clone')
58 'git clone', clone_url, empty_repo.repo_name + '-clone')
59 _check_proper_clone(stdout, stderr, 'git')
59 _check_proper_clone(stdout, stderr, 'git')
60
60
61 # Doing an explicit commit in order to get latest user logs on MySQL
61 # Doing an explicit commit in order to get latest user logs on MySQL
62 Session().commit()
62 Session().commit()
63
63
64 # def test_git_fetches_from_remote_repository_with_annotated_tags(
64 def test_git_fetches_from_remote_repository_with_annotated_tags(
65 # self, backend_git, rc_web_server):
65 self, backend_git, rc_web_server):
66 # # Note: This is a test specific to the git backend. It checks the
66 # Note: This is a test specific to the git backend. It checks the
67 # # integration of fetching from a remote repository which contains
67 # integration of fetching from a remote repository which contains
68 # # annotated tags.
68 # annotated tags.
69 #
69
70 # # Dulwich shows this specific behavior only when
70 # Dulwich shows this specific behavior only when
71 # # operating against a remote repository.
71 # operating against a remote repository.
72 # source_repo = backend_git['annotated-tag']
72 source_repo = backend_git['annotated-tag']
73 # target_vcs_repo = backend_git.create_repo().scm_instance()
73 target_vcs_repo = backend_git.create_repo().scm_instance()
74 # target_vcs_repo.fetch(rc_web_server.repo_clone_url(source_repo.repo_name))
74 target_vcs_repo.fetch(rc_web_server.repo_clone_url(source_repo.repo_name))
75
75
76 def test_git_push_shows_pull_request_refs(self, backend_git, rc_web_server, tmpdir):
76 def test_git_push_shows_pull_request_refs(self, backend_git, rc_web_server, tmpdir):
77 """
77 """
78 test if remote info about refs is visible
78 test if remote info about refs is visible
79 """
79 """
80 empty_repo = backend_git.create_repo()
80 empty_repo = backend_git.create_repo()
81
81
82 clone_url = rc_web_server.repo_clone_url(empty_repo.repo_name)
82 clone_url = rc_web_server.repo_clone_url(empty_repo.repo_name)
83
83
84 cmd = Command(tmpdir.strpath)
84 cmd = Command(tmpdir.strpath)
85 cmd.execute('git clone', clone_url)
85 cmd.execute('git clone', clone_url)
86
86
87 repo = GitRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
87 repo = GitRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
88 repo.in_memory_commit.add(FileNode('readme.md', content='## Hello'))
88 repo.in_memory_commit.add(FileNode('readme.md', content='## Hello'))
89 repo.in_memory_commit.commit(
89 repo.in_memory_commit.commit(
90 message='Commit on branch Master',
90 message='Commit on branch Master',
91 author='Automatic test',
91 author='Automatic test',
92 branch='master')
92 branch='master')
93
93
94 repo_cmd = Command(repo.path)
94 repo_cmd = Command(repo.path)
95 stdout, stderr = repo_cmd.execute('git push --verbose origin master')
95 stdout, stderr = repo_cmd.execute('git push --verbose origin master')
96 _check_proper_git_push(stdout, stderr, branch='master')
96 _check_proper_git_push(stdout, stderr, branch='master')
97
97
98 ref = '{}/{}/pull-request/new?branch=master'.format(
98 ref = '{}/{}/pull-request/new?branch=master'.format(
99 rc_web_server.host_url(), empty_repo.repo_name)
99 rc_web_server.host_url(), empty_repo.repo_name)
100 assert 'remote: RhodeCode: open pull request link: {}'.format(ref) in stderr
100 assert 'remote: RhodeCode: open pull request link: {}'.format(ref) in stderr
101 assert 'remote: RhodeCode: push completed' in stderr
101 assert 'remote: RhodeCode: push completed' in stderr
102
102
103 # push on the same branch
103 # push on the same branch
104 repo = GitRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
104 repo = GitRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
105 repo.in_memory_commit.add(FileNode('setup.py', content='print\n'))
105 repo.in_memory_commit.add(FileNode('setup.py', content='print\n'))
106 repo.in_memory_commit.commit(
106 repo.in_memory_commit.commit(
107 message='Commit2 on branch Master',
107 message='Commit2 on branch Master',
108 author='Automatic test2',
108 author='Automatic test2',
109 branch='master')
109 branch='master')
110
110
111 repo_cmd = Command(repo.path)
111 repo_cmd = Command(repo.path)
112 stdout, stderr = repo_cmd.execute('git push --verbose origin master')
112 stdout, stderr = repo_cmd.execute('git push --verbose origin master')
113 _check_proper_git_push(stdout, stderr, branch='master')
113 _check_proper_git_push(stdout, stderr, branch='master')
114
114
115 assert 'remote: RhodeCode: open pull request link: {}'.format(ref) in stderr
115 assert 'remote: RhodeCode: open pull request link: {}'.format(ref) in stderr
116 assert 'remote: RhodeCode: push completed' in stderr
116 assert 'remote: RhodeCode: push completed' in stderr
117
117
118 # new Branch
118 # new Branch
119 repo = GitRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
119 repo = GitRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
120 repo.in_memory_commit.add(FileNode('feature1.py', content='## Hello world'))
120 repo.in_memory_commit.add(FileNode('feature1.py', content='## Hello world'))
121 repo.in_memory_commit.commit(
121 repo.in_memory_commit.commit(
122 message='Commit on branch feature',
122 message='Commit on branch feature',
123 author='Automatic test',
123 author='Automatic test',
124 branch='feature')
124 branch='feature')
125
125
126 repo_cmd = Command(repo.path)
126 repo_cmd = Command(repo.path)
127 stdout, stderr = repo_cmd.execute('git push --verbose origin feature')
127 stdout, stderr = repo_cmd.execute('git push --verbose origin feature')
128 _check_proper_git_push(stdout, stderr, branch='feature')
128 _check_proper_git_push(stdout, stderr, branch='feature')
129
129
130 ref = '{}/{}/pull-request/new?branch=feature'.format(
130 ref = '{}/{}/pull-request/new?branch=feature'.format(
131 rc_web_server.host_url(), empty_repo.repo_name)
131 rc_web_server.host_url(), empty_repo.repo_name)
132 assert 'remote: RhodeCode: open pull request link: {}'.format(ref) in stderr
132 assert 'remote: RhodeCode: open pull request link: {}'.format(ref) in stderr
133 assert 'remote: RhodeCode: push completed' in stderr
133 assert 'remote: RhodeCode: push completed' in stderr
134
134
135 def test_hg_push_shows_pull_request_refs(self, backend_hg, rc_web_server, tmpdir):
135 def test_hg_push_shows_pull_request_refs(self, backend_hg, rc_web_server, tmpdir):
136 empty_repo = backend_hg.create_repo()
136 empty_repo = backend_hg.create_repo()
137
137
138 clone_url = rc_web_server.repo_clone_url(empty_repo.repo_name)
138 clone_url = rc_web_server.repo_clone_url(empty_repo.repo_name)
139
139
140 cmd = Command(tmpdir.strpath)
140 cmd = Command(tmpdir.strpath)
141 cmd.execute('hg clone', clone_url)
141 cmd.execute('hg clone', clone_url)
142
142
143 repo = MercurialRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
143 repo = MercurialRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
144 repo.in_memory_commit.add(FileNode(u'readme.md', content=u'## Hello'))
144 repo.in_memory_commit.add(FileNode(u'readme.md', content=u'## Hello'))
145 repo.in_memory_commit.commit(
145 repo.in_memory_commit.commit(
146 message=u'Commit on branch default',
146 message=u'Commit on branch default',
147 author=u'Automatic test',
147 author=u'Automatic test',
148 branch='default')
148 branch='default')
149
149
150 repo_cmd = Command(repo.path)
150 repo_cmd = Command(repo.path)
151 repo_cmd.execute('hg checkout default')
151 repo_cmd.execute('hg checkout default')
152
152
153 stdout, stderr = repo_cmd.execute('hg push --verbose', clone_url)
153 stdout, stderr = repo_cmd.execute('hg push --verbose', clone_url)
154 _check_proper_hg_push(stdout, stderr, branch='default')
154 _check_proper_hg_push(stdout, stderr, branch='default')
155
155
156 ref = '{}/{}/pull-request/new?branch=default'.format(
156 ref = '{}/{}/pull-request/new?branch=default'.format(
157 rc_web_server.host_url(), empty_repo.repo_name)
157 rc_web_server.host_url(), empty_repo.repo_name)
158 assert 'remote: RhodeCode: open pull request link: {}'.format(ref) in stdout
158 assert 'remote: RhodeCode: open pull request link: {}'.format(ref) in stdout
159 assert 'remote: RhodeCode: push completed' in stdout
159 assert 'remote: RhodeCode: push completed' in stdout
160
160
161 # push on the same branch
161 # push on the same branch
162 repo = MercurialRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
162 repo = MercurialRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
163 repo.in_memory_commit.add(FileNode(u'setup.py', content=u'print\n'))
163 repo.in_memory_commit.add(FileNode(u'setup.py', content=u'print\n'))
164 repo.in_memory_commit.commit(
164 repo.in_memory_commit.commit(
165 message=u'Commit2 on branch default',
165 message=u'Commit2 on branch default',
166 author=u'Automatic test2',
166 author=u'Automatic test2',
167 branch=u'default')
167 branch=u'default')
168
168
169 repo_cmd = Command(repo.path)
169 repo_cmd = Command(repo.path)
170 repo_cmd.execute('hg checkout default')
170 repo_cmd.execute('hg checkout default')
171
171
172 stdout, stderr = repo_cmd.execute('hg push --verbose', clone_url)
172 stdout, stderr = repo_cmd.execute('hg push --verbose', clone_url)
173 _check_proper_hg_push(stdout, stderr, branch='default')
173 _check_proper_hg_push(stdout, stderr, branch='default')
174
174
175 assert 'remote: RhodeCode: open pull request link: {}'.format(ref) in stdout
175 assert 'remote: RhodeCode: open pull request link: {}'.format(ref) in stdout
176 assert 'remote: RhodeCode: push completed' in stdout
176 assert 'remote: RhodeCode: push completed' in stdout
177
177
178 # new Branch
178 # new Branch
179 repo = MercurialRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
179 repo = MercurialRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
180 repo.in_memory_commit.add(FileNode(u'feature1.py', content=u'## Hello world'))
180 repo.in_memory_commit.add(FileNode(u'feature1.py', content=u'## Hello world'))
181 repo.in_memory_commit.commit(
181 repo.in_memory_commit.commit(
182 message=u'Commit on branch feature',
182 message=u'Commit on branch feature',
183 author=u'Automatic test',
183 author=u'Automatic test',
184 branch=u'feature')
184 branch=u'feature')
185
185
186 repo_cmd = Command(repo.path)
186 repo_cmd = Command(repo.path)
187 repo_cmd.execute('hg checkout feature')
187 repo_cmd.execute('hg checkout feature')
188
188
189 stdout, stderr = repo_cmd.execute('hg push --new-branch --verbose', clone_url)
189 stdout, stderr = repo_cmd.execute('hg push --new-branch --verbose', clone_url)
190 _check_proper_hg_push(stdout, stderr, branch='feature')
190 _check_proper_hg_push(stdout, stderr, branch='feature')
191
191
192 ref = '{}/{}/pull-request/new?branch=feature'.format(
192 ref = '{}/{}/pull-request/new?branch=feature'.format(
193 rc_web_server.host_url(), empty_repo.repo_name)
193 rc_web_server.host_url(), empty_repo.repo_name)
194 assert 'remote: RhodeCode: open pull request link: {}'.format(ref) in stdout
194 assert 'remote: RhodeCode: open pull request link: {}'.format(ref) in stdout
195 assert 'remote: RhodeCode: push completed' in stdout
195 assert 'remote: RhodeCode: push completed' in stdout
196
196
197 def test_hg_push_shows_pull_request_refs_book(self, backend_hg, rc_web_server, tmpdir):
197 def test_hg_push_shows_pull_request_refs_book(self, backend_hg, rc_web_server, tmpdir):
198 empty_repo = backend_hg.create_repo()
198 empty_repo = backend_hg.create_repo()
199
199
200 clone_url = rc_web_server.repo_clone_url(empty_repo.repo_name)
200 clone_url = rc_web_server.repo_clone_url(empty_repo.repo_name)
201
201
202 cmd = Command(tmpdir.strpath)
202 cmd = Command(tmpdir.strpath)
203 cmd.execute('hg clone', clone_url)
203 cmd.execute('hg clone', clone_url)
204
204
205 repo = MercurialRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
205 repo = MercurialRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
206 repo.in_memory_commit.add(FileNode(u'readme.md', content=u'## Hello'))
206 repo.in_memory_commit.add(FileNode(u'readme.md', content=u'## Hello'))
207 repo.in_memory_commit.commit(
207 repo.in_memory_commit.commit(
208 message=u'Commit on branch default',
208 message=u'Commit on branch default',
209 author=u'Automatic test',
209 author=u'Automatic test',
210 branch='default')
210 branch='default')
211
211
212 repo_cmd = Command(repo.path)
212 repo_cmd = Command(repo.path)
213 repo_cmd.execute('hg checkout default')
213 repo_cmd.execute('hg checkout default')
214
214
215 stdout, stderr = repo_cmd.execute('hg push --verbose', clone_url)
215 stdout, stderr = repo_cmd.execute('hg push --verbose', clone_url)
216 _check_proper_hg_push(stdout, stderr, branch='default')
216 _check_proper_hg_push(stdout, stderr, branch='default')
217
217
218 ref = '{}/{}/pull-request/new?branch=default'.format(
218 ref = '{}/{}/pull-request/new?branch=default'.format(
219 rc_web_server.host_url(), empty_repo.repo_name)
219 rc_web_server.host_url(), empty_repo.repo_name)
220 assert 'remote: RhodeCode: open pull request link: {}'.format(ref) in stdout
220 assert 'remote: RhodeCode: open pull request link: {}'.format(ref) in stdout
221 assert 'remote: RhodeCode: push completed' in stdout
221 assert 'remote: RhodeCode: push completed' in stdout
222
222
223 # add bookmark
223 # add bookmark
224 repo = MercurialRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
224 repo = MercurialRepository(os.path.join(tmpdir.strpath, empty_repo.repo_name))
225 repo.in_memory_commit.add(FileNode(u'setup.py', content=u'print\n'))
225 repo.in_memory_commit.add(FileNode(u'setup.py', content=u'print\n'))
226 repo.in_memory_commit.commit(
226 repo.in_memory_commit.commit(
227 message=u'Commit2 on branch default',
227 message=u'Commit2 on branch default',
228 author=u'Automatic test2',
228 author=u'Automatic test2',
229 branch=u'default')
229 branch=u'default')
230
230
231 repo_cmd = Command(repo.path)
231 repo_cmd = Command(repo.path)
232 repo_cmd.execute('hg checkout default')
232 repo_cmd.execute('hg checkout default')
233 repo_cmd.execute('hg bookmark feature2')
233 repo_cmd.execute('hg bookmark feature2')
234 stdout, stderr = repo_cmd.execute('hg push -B feature2 --verbose', clone_url)
234 stdout, stderr = repo_cmd.execute('hg push -B feature2 --verbose', clone_url)
235 _check_proper_hg_push(stdout, stderr, branch='default')
235 _check_proper_hg_push(stdout, stderr, branch='default')
236
236
237 ref = '{}/{}/pull-request/new?branch=default'.format(
237 ref = '{}/{}/pull-request/new?branch=default'.format(
238 rc_web_server.host_url(), empty_repo.repo_name)
238 rc_web_server.host_url(), empty_repo.repo_name)
239 assert 'remote: RhodeCode: open pull request link: {}'.format(ref) in stdout
239 assert 'remote: RhodeCode: open pull request link: {}'.format(ref) in stdout
240 ref = '{}/{}/pull-request/new?bookmark=feature2'.format(
240 ref = '{}/{}/pull-request/new?bookmark=feature2'.format(
241 rc_web_server.host_url(), empty_repo.repo_name)
241 rc_web_server.host_url(), empty_repo.repo_name)
242 assert 'remote: RhodeCode: open pull request link: {}'.format(ref) in stdout
242 assert 'remote: RhodeCode: open pull request link: {}'.format(ref) in stdout
243 assert 'remote: RhodeCode: push completed' in stdout
243 assert 'remote: RhodeCode: push completed' in stdout
244 assert 'exporting bookmark feature2' in stdout
244 assert 'exporting bookmark feature2' in stdout
@@ -1,141 +1,98 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 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 Test suite for making push/pull operations, on specially modified INI files
22 Test suite for making push/pull operations, on specially modified INI files
23
23
24 .. important::
24 .. important::
25
25
26 You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
26 You must have git >= 1.8.5 for tests to work fine. With 68b939b git started
27 to redirect things to stderr instead of stdout.
27 to redirect things to stderr instead of stdout.
28 """
28 """
29
29
30 import pytest
30 import pytest
31 import requests
31 import requests
32
32
33 from rhodecode import events
34 from rhodecode.model.db import Integration
35 from rhodecode.model.integration import IntegrationModel
36 from rhodecode.model.meta import Session
37
38 from rhodecode.tests import GIT_REPO, HG_REPO
33 from rhodecode.tests import GIT_REPO, HG_REPO
39 from rhodecode.tests.vcs_operations import Command, _add_files_and_push
34 from rhodecode.tests.vcs_operations import Command, _add_files_and_push
40 from rhodecode.integrations.types.webhook import WebhookIntegrationType
41
35
42
36
43 def check_connection():
37 def check_connection():
44 try:
38 try:
45 response = requests.get('http://httpbin.org')
39 response = requests.get('http://httpbin.org')
46 return response.status_code == 200
40 return response.status_code == 200
47 except Exception as e:
41 except Exception as e:
48 print(e)
42 print(e)
49
43
50 return False
44 return False
51
45
52
46
53 connection_available = pytest.mark.skipif(
47 connection_available = pytest.mark.skipif(
54 not check_connection(), reason="No outside internet connection available")
48 not check_connection(), reason="No outside internet connection available")
55
49
56
50
57 @pytest.fixture
58 def enable_webhook_push_integration(request):
59 integration = Integration()
60 integration.integration_type = WebhookIntegrationType.key
61 Session().add(integration)
62
63 settings = dict(
64 url='http://httpbin.org',
65 secret_token='secret',
66 username=None,
67 password=None,
68 custom_header_key=None,
69 custom_header_val=None,
70 method_type='get',
71 events=[events.RepoPushEvent.name],
72 log_data=True
73 )
74
75 IntegrationModel().update_integration(
76 integration,
77 name='IntegrationWebhookTest',
78 enabled=True,
79 settings=settings,
80 repo=None,
81 repo_group=None,
82 child_repos_only=False,
83 )
84 Session().commit()
85 integration_id = integration.integration_id
86
87 @request.addfinalizer
88 def cleanup():
89 integration = Integration.get(integration_id)
90 Session().delete(integration)
91 Session().commit()
92
93
94 @pytest.mark.usefixtures(
51 @pytest.mark.usefixtures(
95 "disable_locking", "disable_anonymous_user",
52 "disable_locking", "disable_anonymous_user",
96 "enable_webhook_push_integration")
53 "enable_webhook_push_integration")
97 class TestVCSOperationsOnCustomIniConfig(object):
54 class TestVCSOperationsOnCustomIniConfig(object):
98
55
99 def test_push_tag_with_commit_hg(self, rc_web_server, tmpdir):
56 def test_push_tag_with_commit_hg(self, rc_web_server, tmpdir):
100 clone_url = rc_web_server.repo_clone_url(HG_REPO)
57 clone_url = rc_web_server.repo_clone_url(HG_REPO)
101 stdout, stderr = Command('/tmp').execute(
58 stdout, stderr = Command('/tmp').execute(
102 'hg clone', clone_url, tmpdir.strpath)
59 'hg clone', clone_url, tmpdir.strpath)
103
60
104 push_url = rc_web_server.repo_clone_url(HG_REPO)
61 push_url = rc_web_server.repo_clone_url(HG_REPO)
105 _add_files_and_push(
62 _add_files_and_push(
106 'hg', tmpdir.strpath, clone_url=push_url,
63 'hg', tmpdir.strpath, clone_url=push_url,
107 tags=[{'name': 'v1.0.0', 'commit': 'added tag v1.0.0'}])
64 tags=[{'name': 'v1.0.0', 'commit': 'added tag v1.0.0'}])
108
65
109 rc_log = rc_web_server.get_rc_log()
66 rc_log = rc_web_server.get_rc_log()
110 assert 'ERROR' not in rc_log
67 assert 'ERROR' not in rc_log
111 assert "'name': u'v1.0.0'" in rc_log
68 assert "'name': u'v1.0.0'" in rc_log
112
69
113 def test_push_tag_with_commit_git(
70 def test_push_tag_with_commit_git(
114 self, rc_web_server, tmpdir):
71 self, rc_web_server, tmpdir):
115 clone_url = rc_web_server.repo_clone_url(GIT_REPO)
72 clone_url = rc_web_server.repo_clone_url(GIT_REPO)
116 stdout, stderr = Command('/tmp').execute(
73 stdout, stderr = Command('/tmp').execute(
117 'git clone', clone_url, tmpdir.strpath)
74 'git clone', clone_url, tmpdir.strpath)
118
75
119 push_url = rc_web_server.repo_clone_url(GIT_REPO)
76 push_url = rc_web_server.repo_clone_url(GIT_REPO)
120 _add_files_and_push(
77 _add_files_and_push(
121 'git', tmpdir.strpath, clone_url=push_url,
78 'git', tmpdir.strpath, clone_url=push_url,
122 tags=[{'name': 'v1.0.0', 'commit': 'added tag v1.0.0'}])
79 tags=[{'name': 'v1.0.0', 'commit': 'added tag v1.0.0'}])
123
80
124 rc_log = rc_web_server.get_rc_log()
81 rc_log = rc_web_server.get_rc_log()
125 assert 'ERROR' not in rc_log
82 assert 'ERROR' not in rc_log
126 assert "'name': u'v1.0.0'" in rc_log
83 assert "'name': u'v1.0.0'" in rc_log
127
84
128 def test_push_tag_with_no_commit_git(
85 def test_push_tag_with_no_commit_git(
129 self, rc_web_server, tmpdir):
86 self, rc_web_server, tmpdir):
130 clone_url = rc_web_server.repo_clone_url(GIT_REPO)
87 clone_url = rc_web_server.repo_clone_url(GIT_REPO)
131 stdout, stderr = Command('/tmp').execute(
88 stdout, stderr = Command('/tmp').execute(
132 'git clone', clone_url, tmpdir.strpath)
89 'git clone', clone_url, tmpdir.strpath)
133
90
134 push_url = rc_web_server.repo_clone_url(GIT_REPO)
91 push_url = rc_web_server.repo_clone_url(GIT_REPO)
135 _add_files_and_push(
92 _add_files_and_push(
136 'git', tmpdir.strpath, clone_url=push_url,
93 'git', tmpdir.strpath, clone_url=push_url,
137 tags=[{'name': 'v1.0.0', 'commit': 'added tag v1.0.0'}])
94 tags=[{'name': 'v1.0.0', 'commit': 'added tag v1.0.0'}])
138
95
139 rc_log = rc_web_server.get_rc_log()
96 rc_log = rc_web_server.get_rc_log()
140 assert 'ERROR' not in rc_log
97 assert 'ERROR' not in rc_log
141 assert "'name': u'v1.0.0'" in rc_log
98 assert "'name': u'v1.0.0'" in rc_log
General Comments 0
You need to be logged in to leave comments. Login now