##// END OF EJS Templates
tests: added more tests into initials generator
super-admin -
r4980:f8bf1fa6 default
parent child Browse files
Show More
@@ -1,739 +1,743 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2020 RhodeCode GmbH
3 # Copyright (C) 2010-2020 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 """
22 """
23 Package for testing various lib/helper functions in rhodecode
23 Package for testing various lib/helper functions in rhodecode
24 """
24 """
25
25
26 import datetime
26 import datetime
27 import string
27 import string
28 import mock
28 import mock
29 import pytest
29 import pytest
30 import functools
30
31
31 from rhodecode.tests import no_newline_id_generator
32 from rhodecode.tests import no_newline_id_generator
32 from rhodecode.tests.utils import run_test_concurrently
33 from rhodecode.tests.utils import run_test_concurrently
33
34
34 from rhodecode.lib import rc_cache
35 from rhodecode.lib import rc_cache
35 from rhodecode.lib.helpers import InitialsGravatar
36 from rhodecode.lib.helpers import InitialsGravatar
36 from rhodecode.lib.utils2 import AttributeDict
37 from rhodecode.lib.utils2 import AttributeDict
37
38
38 from rhodecode.model.db import Repository, CacheKey
39 from rhodecode.model.db import Repository, CacheKey
39
40
40
41
41 TEST_URLS = [
42 TEST_URLS = [
42 ('127.0.0.1', '127.0.0.1'),
43 ('127.0.0.1', '127.0.0.1'),
43 ('marcink@127.0.0.1', '127.0.0.1'),
44 ('marcink@127.0.0.1', '127.0.0.1'),
44 ('marcink:pass@127.0.0.1', '127.0.0.1'),
45 ('marcink:pass@127.0.0.1', '127.0.0.1'),
45 ('marcink@domain.name:pass@127.0.0.1', '127.0.0.1'),
46 ('marcink@domain.name:pass@127.0.0.1', '127.0.0.1'),
46
47
47 ('127.0.0.1:8080', '127.0.0.1:8080'),
48 ('127.0.0.1:8080', '127.0.0.1:8080'),
48 ('marcink@127.0.0.1:8080', '127.0.0.1:8080'),
49 ('marcink@127.0.0.1:8080', '127.0.0.1:8080'),
49 ('marcink:pass@127.0.0.1:8080', '127.0.0.1:8080'),
50 ('marcink:pass@127.0.0.1:8080', '127.0.0.1:8080'),
50 ('marcink@domain.name:pass@127.0.0.1:8080', '127.0.0.1:8080'),
51 ('marcink@domain.name:pass@127.0.0.1:8080', '127.0.0.1:8080'),
51
52
52 ('domain.org', 'domain.org'),
53 ('domain.org', 'domain.org'),
53 ('user:pass@domain.org:8080', 'domain.org:8080'),
54 ('user:pass@domain.org:8080', 'domain.org:8080'),
54 ('user@domain.org:pass@domain.org:8080', 'domain.org:8080'),
55 ('user@domain.org:pass@domain.org:8080', 'domain.org:8080'),
55 ]
56 ]
56
57
57
58
58 @pytest.mark.parametrize("protocol", ['http://', 'https://'])
59 @pytest.mark.parametrize("protocol", ['http://', 'https://'])
59 @pytest.mark.parametrize("test_url, expected", TEST_URLS)
60 @pytest.mark.parametrize("test_url, expected", TEST_URLS)
60 def test_credentials_filter(protocol, test_url, expected):
61 def test_credentials_filter(protocol, test_url, expected):
61 from rhodecode.lib.utils2 import credentials_filter
62 from rhodecode.lib.utils2 import credentials_filter
62 test_url = protocol + test_url
63 test_url = protocol + test_url
63 assert credentials_filter(test_url) == protocol + expected
64 assert credentials_filter(test_url) == protocol + expected
64
65
65
66
66 @pytest.mark.parametrize("str_bool, expected", [
67 @pytest.mark.parametrize("str_bool, expected", [
67 ('t', True),
68 ('t', True),
68 ('true', True),
69 ('true', True),
69 ('y', True),
70 ('y', True),
70 ('yes', True),
71 ('yes', True),
71 ('on', True),
72 ('on', True),
72 ('1', True),
73 ('1', True),
73 ('Y', True),
74 ('Y', True),
74 ('yeS', True),
75 ('yeS', True),
75 ('Y', True),
76 ('Y', True),
76 ('TRUE', True),
77 ('TRUE', True),
77 ('T', True),
78 ('T', True),
78 ('False', False),
79 ('False', False),
79 ('F', False),
80 ('F', False),
80 ('FALSE', False),
81 ('FALSE', False),
81 ('0', False),
82 ('0', False),
82 ('-1', False),
83 ('-1', False),
83 ('', False)
84 ('', False)
84 ])
85 ])
85 def test_str2bool(str_bool, expected):
86 def test_str2bool(str_bool, expected):
86 from rhodecode.lib.utils2 import str2bool
87 from rhodecode.lib.utils2 import str2bool
87 assert str2bool(str_bool) == expected
88 assert str2bool(str_bool) == expected
88
89
89
90
90 @pytest.mark.parametrize("text, expected", reduce(lambda a1,a2:a1+a2, [
91 @pytest.mark.parametrize("text, expected", functools.reduce(lambda a1, a2: a1+a2, [
91 [
92 [
92 (pref+"", []),
93 (pref+"", []),
93 (pref+"Hi there @marcink", ['marcink']),
94 (pref+"Hi there @marcink", ['marcink']),
94 (pref+"Hi there @marcink and @bob", ['bob', 'marcink']),
95 (pref+"Hi there @marcink and @bob", ['bob', 'marcink']),
95 (pref+"Hi there @marcink\n", ['marcink']),
96 (pref+"Hi there @marcink\n", ['marcink']),
96 (pref+"Hi there @marcink and @bob\n", ['bob', 'marcink']),
97 (pref+"Hi there @marcink and @bob\n", ['bob', 'marcink']),
97 (pref+"Hi there marcin@rhodecode.com", []),
98 (pref+"Hi there marcin@rhodecode.com", []),
98 (pref+"Hi there @john.malcovic and @bob\n", ['bob', 'john.malcovic']),
99 (pref+"Hi there @john.malcovic and @bob\n", ['bob', 'john.malcovic']),
99 (pref+"This needs to be reviewed: (@marcink,@john)", ["john", "marcink"]),
100 (pref+"This needs to be reviewed: (@marcink,@john)", ["john", "marcink"]),
100 (pref+"This needs to be reviewed: (@marcink, @john)", ["john", "marcink"]),
101 (pref+"This needs to be reviewed: (@marcink, @john)", ["john", "marcink"]),
101 (pref+"This needs to be reviewed: [@marcink,@john]", ["john", "marcink"]),
102 (pref+"This needs to be reviewed: [@marcink,@john]", ["john", "marcink"]),
102 (pref+"This needs to be reviewed: (@marcink @john)", ["john", "marcink"]),
103 (pref+"This needs to be reviewed: (@marcink @john)", ["john", "marcink"]),
103 (pref+"@john @mary, please review", ["john", "mary"]),
104 (pref+"@john @mary, please review", ["john", "mary"]),
104 (pref+"@john,@mary, please review", ["john", "mary"]),
105 (pref+"@john,@mary, please review", ["john", "mary"]),
105 (pref+"Hej @123, @22john,@mary, please review", ['123', '22john', 'mary']),
106 (pref+"Hej @123, @22john,@mary, please review", ['123', '22john', 'mary']),
106 (pref+"@first hi there @marcink here's my email marcin@email.com "
107 (pref+"@first hi there @marcink here's my email marcin@email.com "
107 "@lukaszb check @one_more22 it pls @ ttwelve @D[] @one@two@three ", ['first', 'lukaszb', 'marcink', 'one', 'one_more22']),
108 "@lukaszb check @one_more22 it pls @ ttwelve @D[] @one@two@three ", ['first', 'lukaszb', 'marcink', 'one', 'one_more22']),
108 (pref+"@MARCIN @maRCiN @2one_more22 @john please see this http://org.pl", ['2one_more22', 'john', 'MARCIN', 'maRCiN']),
109 (pref+"@MARCIN @maRCiN @2one_more22 @john please see this http://org.pl", ['2one_more22', 'john', 'MARCIN', 'maRCiN']),
109 (pref+"@marian.user just do it @marco-polo and next extract @marco_polo", ['marco-polo', 'marco_polo', 'marian.user']),
110 (pref+"@marian.user just do it @marco-polo and next extract @marco_polo", ['marco-polo', 'marco_polo', 'marian.user']),
110 (pref+"user.dot hej ! not-needed maril@domain.org", []),
111 (pref+"user.dot hej ! not-needed maril@domain.org", []),
111 (pref+"\n@marcin", ['marcin']),
112 (pref+"\n@marcin", ['marcin']),
112 ]
113 ]
113 for pref in ['', '\n', 'hi !', '\t', '\n\n']]), ids=no_newline_id_generator)
114 for pref in ['', '\n', 'hi !', '\t', '\n\n']]), ids=no_newline_id_generator)
114 def test_mention_extractor(text, expected):
115 def test_mention_extractor(text, expected):
115 from rhodecode.lib.utils2 import extract_mentioned_users
116 from rhodecode.lib.utils2 import extract_mentioned_users
116 got = extract_mentioned_users(text)
117 got = extract_mentioned_users(text)
117 assert sorted(got, key=lambda x: x.lower()) == got
118 assert sorted(got, key=lambda x: x.lower()) == got
118 assert set(expected) == set(got)
119 assert set(expected) == set(got)
119
120
120 @pytest.mark.parametrize("age_args, expected, kw", [
121 @pytest.mark.parametrize("age_args, expected, kw", [
121 ({}, u'just now', {}),
122 ({}, u'just now', {}),
122 ({'seconds': -1}, u'1 second ago', {}),
123 ({'seconds': -1}, u'1 second ago', {}),
123 ({'seconds': -60 * 2}, u'2 minutes ago', {}),
124 ({'seconds': -60 * 2}, u'2 minutes ago', {}),
124 ({'hours': -1}, u'1 hour ago', {}),
125 ({'hours': -1}, u'1 hour ago', {}),
125 ({'hours': -24}, u'1 day ago', {}),
126 ({'hours': -24}, u'1 day ago', {}),
126 ({'hours': -24 * 5}, u'5 days ago', {}),
127 ({'hours': -24 * 5}, u'5 days ago', {}),
127 ({'months': -1}, u'1 month ago', {}),
128 ({'months': -1}, u'1 month ago', {}),
128 ({'months': -1, 'days': -2}, u'1 month and 2 days ago', {}),
129 ({'months': -1, 'days': -2}, u'1 month and 2 days ago', {}),
129 ({'years': -1, 'months': -1}, u'1 year and 1 month ago', {}),
130 ({'years': -1, 'months': -1}, u'1 year and 1 month ago', {}),
130 ({}, u'just now', {'short_format': True}),
131 ({}, u'just now', {'short_format': True}),
131 ({'seconds': -1}, u'1sec ago', {'short_format': True}),
132 ({'seconds': -1}, u'1sec ago', {'short_format': True}),
132 ({'seconds': -60 * 2}, u'2min ago', {'short_format': True}),
133 ({'seconds': -60 * 2}, u'2min ago', {'short_format': True}),
133 ({'hours': -1}, u'1h ago', {'short_format': True}),
134 ({'hours': -1}, u'1h ago', {'short_format': True}),
134 ({'hours': -24}, u'1d ago', {'short_format': True}),
135 ({'hours': -24}, u'1d ago', {'short_format': True}),
135 ({'hours': -24 * 5}, u'5d ago', {'short_format': True}),
136 ({'hours': -24 * 5}, u'5d ago', {'short_format': True}),
136 ({'months': -1}, u'1m ago', {'short_format': True}),
137 ({'months': -1}, u'1m ago', {'short_format': True}),
137 ({'months': -1, 'days': -2}, u'1m, 2d ago', {'short_format': True}),
138 ({'months': -1, 'days': -2}, u'1m, 2d ago', {'short_format': True}),
138 ({'years': -1, 'months': -1}, u'1y, 1m ago', {'short_format': True}),
139 ({'years': -1, 'months': -1}, u'1y, 1m ago', {'short_format': True}),
139 ])
140 ])
140 def test_age(age_args, expected, kw, baseapp):
141 def test_age(age_args, expected, kw, baseapp):
141 from rhodecode.lib.utils2 import age
142 from rhodecode.lib.utils2 import age
142 from dateutil import relativedelta
143 from dateutil import relativedelta
143 n = datetime.datetime(year=2012, month=5, day=17)
144 n = datetime.datetime(year=2012, month=5, day=17)
144 delt = lambda *args, **kwargs: relativedelta.relativedelta(*args, **kwargs)
145 delt = lambda *args, **kwargs: relativedelta.relativedelta(*args, **kwargs)
145
146
146 def translate(elem):
147 def translate(elem):
147 return elem.interpolate()
148 return elem.interpolate()
148
149
149 assert translate(age(n + delt(**age_args), now=n, **kw)) == expected
150 assert translate(age(n + delt(**age_args), now=n, **kw)) == expected
150
151
151
152
152 @pytest.mark.parametrize("age_args, expected, kw", [
153 @pytest.mark.parametrize("age_args, expected, kw", [
153 ({}, u'just now', {}),
154 ({}, u'just now', {}),
154 ({'seconds': 1}, u'in 1 second', {}),
155 ({'seconds': 1}, u'in 1 second', {}),
155 ({'seconds': 60 * 2}, u'in 2 minutes', {}),
156 ({'seconds': 60 * 2}, u'in 2 minutes', {}),
156 ({'hours': 1}, u'in 1 hour', {}),
157 ({'hours': 1}, u'in 1 hour', {}),
157 ({'hours': 24}, u'in 1 day', {}),
158 ({'hours': 24}, u'in 1 day', {}),
158 ({'hours': 24 * 5}, u'in 5 days', {}),
159 ({'hours': 24 * 5}, u'in 5 days', {}),
159 ({'months': 1}, u'in 1 month', {}),
160 ({'months': 1}, u'in 1 month', {}),
160 ({'months': 1, 'days': 1}, u'in 1 month and 1 day', {}),
161 ({'months': 1, 'days': 1}, u'in 1 month and 1 day', {}),
161 ({'years': 1, 'months': 1}, u'in 1 year and 1 month', {}),
162 ({'years': 1, 'months': 1}, u'in 1 year and 1 month', {}),
162 ({}, u'just now', {'short_format': True}),
163 ({}, u'just now', {'short_format': True}),
163 ({'seconds': 1}, u'in 1sec', {'short_format': True}),
164 ({'seconds': 1}, u'in 1sec', {'short_format': True}),
164 ({'seconds': 60 * 2}, u'in 2min', {'short_format': True}),
165 ({'seconds': 60 * 2}, u'in 2min', {'short_format': True}),
165 ({'hours': 1}, u'in 1h', {'short_format': True}),
166 ({'hours': 1}, u'in 1h', {'short_format': True}),
166 ({'hours': 24}, u'in 1d', {'short_format': True}),
167 ({'hours': 24}, u'in 1d', {'short_format': True}),
167 ({'hours': 24 * 5}, u'in 5d', {'short_format': True}),
168 ({'hours': 24 * 5}, u'in 5d', {'short_format': True}),
168 ({'months': 1}, u'in 1m', {'short_format': True}),
169 ({'months': 1}, u'in 1m', {'short_format': True}),
169 ({'months': 1, 'days': 1}, u'in 1m, 1d', {'short_format': True}),
170 ({'months': 1, 'days': 1}, u'in 1m, 1d', {'short_format': True}),
170 ({'years': 1, 'months': 1}, u'in 1y, 1m', {'short_format': True}),
171 ({'years': 1, 'months': 1}, u'in 1y, 1m', {'short_format': True}),
171 ])
172 ])
172 def test_age_in_future(age_args, expected, kw, baseapp):
173 def test_age_in_future(age_args, expected, kw, baseapp):
173 from rhodecode.lib.utils2 import age
174 from rhodecode.lib.utils2 import age
174 from dateutil import relativedelta
175 from dateutil import relativedelta
175 n = datetime.datetime(year=2012, month=5, day=17)
176 n = datetime.datetime(year=2012, month=5, day=17)
176 delt = lambda *args, **kwargs: relativedelta.relativedelta(*args, **kwargs)
177 delt = lambda *args, **kwargs: relativedelta.relativedelta(*args, **kwargs)
177
178
178 def translate(elem):
179 def translate(elem):
179 return elem.interpolate()
180 return elem.interpolate()
180
181
181 assert translate(age(n + delt(**age_args), now=n, **kw)) == expected
182 assert translate(age(n + delt(**age_args), now=n, **kw)) == expected
182
183
183
184
184 @pytest.mark.parametrize("sample, expected_tags", [
185 @pytest.mark.parametrize("sample, expected_tags", [
185 # entry
186 # entry
186 ((
187 ((
187 ""
188 ""
188 ),
189 ),
189 [
190 [
190
191
191 ]),
192 ]),
192 # entry
193 # entry
193 ((
194 ((
194 "hello world [stale]"
195 "hello world [stale]"
195 ),
196 ),
196 [
197 [
197 ('state', '[stale]'),
198 ('state', '[stale]'),
198 ]),
199 ]),
199 # entry
200 # entry
200 ((
201 ((
201 "hello world [v2.0.0] [v1.0.0]"
202 "hello world [v2.0.0] [v1.0.0]"
202 ),
203 ),
203 [
204 [
204 ('generic', '[v2.0.0]'),
205 ('generic', '[v2.0.0]'),
205 ('generic', '[v1.0.0]'),
206 ('generic', '[v1.0.0]'),
206 ]),
207 ]),
207 # entry
208 # entry
208 ((
209 ((
209 "he[ll]o wo[rl]d"
210 "he[ll]o wo[rl]d"
210 ),
211 ),
211 [
212 [
212 ('label', '[ll]'),
213 ('label', '[ll]'),
213 ('label', '[rl]'),
214 ('label', '[rl]'),
214 ]),
215 ]),
215 # entry
216 # entry
216 ((
217 ((
217 "hello world [stale]\n[featured]\n[stale] [dead] [dev]"
218 "hello world [stale]\n[featured]\n[stale] [dead] [dev]"
218 ),
219 ),
219 [
220 [
220 ('state', '[stale]'),
221 ('state', '[stale]'),
221 ('state', '[featured]'),
222 ('state', '[featured]'),
222 ('state', '[stale]'),
223 ('state', '[stale]'),
223 ('state', '[dead]'),
224 ('state', '[dead]'),
224 ('state', '[dev]'),
225 ('state', '[dev]'),
225 ]),
226 ]),
226 # entry
227 # entry
227 ((
228 ((
228 "hello world \n\n [stale] \n [url =&gt; [name](http://rc.com)]"
229 "hello world \n\n [stale] \n [url =&gt; [name](http://rc.com)]"
229 ),
230 ),
230 [
231 [
231 ('state', '[stale]'),
232 ('state', '[stale]'),
232 ('url', '[url =&gt; [name](http://rc.com)]'),
233 ('url', '[url =&gt; [name](http://rc.com)]'),
233 ]),
234 ]),
234 # entry
235 # entry
235 ((
236 ((
236 "[url =&gt; [linkNameJS](javascript:alert(document.domain))]\n"
237 "[url =&gt; [linkNameJS](javascript:alert(document.domain))]\n"
237 "[url =&gt; [linkNameHTTP](http://rhodecode.com)]\n"
238 "[url =&gt; [linkNameHTTP](http://rhodecode.com)]\n"
238 "[url =&gt; [linkNameHTTPS](https://rhodecode.com)]\n"
239 "[url =&gt; [linkNameHTTPS](https://rhodecode.com)]\n"
239 "[url =&gt; [linkNamePath](/repo_group)]\n"
240 "[url =&gt; [linkNamePath](/repo_group)]\n"
240 ),
241 ),
241 [
242 [
242 ('generic', '[linkNameJS]'),
243 ('generic', '[linkNameJS]'),
243 ('url', '[url =&gt; [linkNameHTTP](http://rhodecode.com)]'),
244 ('url', '[url =&gt; [linkNameHTTP](http://rhodecode.com)]'),
244 ('url', '[url =&gt; [linkNameHTTPS](https://rhodecode.com)]'),
245 ('url', '[url =&gt; [linkNameHTTPS](https://rhodecode.com)]'),
245 ('url', '[url =&gt; [linkNamePath](/repo_group)]'),
246 ('url', '[url =&gt; [linkNamePath](/repo_group)]'),
246 ]),
247 ]),
247 # entry
248 # entry
248 ((
249 ((
249 "hello pta[tag] gog [[]] [[] sda ero[or]d [me =&gt;>< sa]"
250 "hello pta[tag] gog [[]] [[] sda ero[or]d [me =&gt;>< sa]"
250 "[requires] [stale] [see<>=&gt;] [see =&gt; http://url.com]"
251 "[requires] [stale] [see<>=&gt;] [see =&gt; http://url.com]"
251 "[requires =&gt; url] [lang =&gt; python] [just a tag] "
252 "[requires =&gt; url] [lang =&gt; python] [just a tag] "
252 "<html_tag first='abc' attr=\"my.url?attr=&another=\"></html_tag>"
253 "<html_tag first='abc' attr=\"my.url?attr=&another=\"></html_tag>"
253 "[,d] [ =&gt; ULR ] [obsolete] [desc]]"
254 "[,d] [ =&gt; ULR ] [obsolete] [desc]]"
254 ),
255 ),
255 [
256 [
256 ('label', '[desc]'),
257 ('label', '[desc]'),
257 ('label', '[obsolete]'),
258 ('label', '[obsolete]'),
258 ('label', '[or]'),
259 ('label', '[or]'),
259 ('label', '[requires]'),
260 ('label', '[requires]'),
260 ('label', '[tag]'),
261 ('label', '[tag]'),
261 ('state', '[stale]'),
262 ('state', '[stale]'),
262 ('lang', '[lang =&gt; python]'),
263 ('lang', '[lang =&gt; python]'),
263 ('ref', '[requires =&gt; url]'),
264 ('ref', '[requires =&gt; url]'),
264 ('see', '[see =&gt; http://url.com]'),
265 ('see', '[see =&gt; http://url.com]'),
265
266
266 ]),
267 ]),
267
268
268 ], ids=no_newline_id_generator)
269 ], ids=no_newline_id_generator)
269 def test_metatag_extraction(sample, expected_tags):
270 def test_metatag_extraction(sample, expected_tags):
270 from rhodecode.lib.helpers import extract_metatags
271 from rhodecode.lib.helpers import extract_metatags
271 tags, value = extract_metatags(sample)
272 tags, value = extract_metatags(sample)
272 assert sorted(tags) == sorted(expected_tags)
273 assert sorted(tags) == sorted(expected_tags)
273
274
274
275
275 @pytest.mark.parametrize("tag_data, expected_html", [
276 @pytest.mark.parametrize("tag_data, expected_html", [
276
277
277 (('state', '[stable]'), '<div class="metatag" tag="state stable">stable</div>'),
278 (('state', '[stable]'), '<div class="metatag" tag="state stable">stable</div>'),
278 (('state', '[stale]'), '<div class="metatag" tag="state stale">stale</div>'),
279 (('state', '[stale]'), '<div class="metatag" tag="state stale">stale</div>'),
279 (('state', '[featured]'), '<div class="metatag" tag="state featured">featured</div>'),
280 (('state', '[featured]'), '<div class="metatag" tag="state featured">featured</div>'),
280 (('state', '[dev]'), '<div class="metatag" tag="state dev">dev</div>'),
281 (('state', '[dev]'), '<div class="metatag" tag="state dev">dev</div>'),
281 (('state', '[dead]'), '<div class="metatag" tag="state dead">dead</div>'),
282 (('state', '[dead]'), '<div class="metatag" tag="state dead">dead</div>'),
282
283
283 (('label', '[personal]'), '<div class="metatag" tag="label">personal</div>'),
284 (('label', '[personal]'), '<div class="metatag" tag="label">personal</div>'),
284 (('generic', '[v2.0.0]'), '<div class="metatag" tag="generic">v2.0.0</div>'),
285 (('generic', '[v2.0.0]'), '<div class="metatag" tag="generic">v2.0.0</div>'),
285
286
286 (('lang', '[lang =&gt; JavaScript]'), '<div class="metatag" tag="lang">JavaScript</div>'),
287 (('lang', '[lang =&gt; JavaScript]'), '<div class="metatag" tag="lang">JavaScript</div>'),
287 (('lang', '[lang =&gt; C++]'), '<div class="metatag" tag="lang">C++</div>'),
288 (('lang', '[lang =&gt; C++]'), '<div class="metatag" tag="lang">C++</div>'),
288 (('lang', '[lang =&gt; C#]'), '<div class="metatag" tag="lang">C#</div>'),
289 (('lang', '[lang =&gt; C#]'), '<div class="metatag" tag="lang">C#</div>'),
289 (('lang', '[lang =&gt; Delphi/Object]'), '<div class="metatag" tag="lang">Delphi/Object</div>'),
290 (('lang', '[lang =&gt; Delphi/Object]'), '<div class="metatag" tag="lang">Delphi/Object</div>'),
290 (('lang', '[lang =&gt; Objective-C]'), '<div class="metatag" tag="lang">Objective-C</div>'),
291 (('lang', '[lang =&gt; Objective-C]'), '<div class="metatag" tag="lang">Objective-C</div>'),
291 (('lang', '[lang =&gt; .NET]'), '<div class="metatag" tag="lang">.NET</div>'),
292 (('lang', '[lang =&gt; .NET]'), '<div class="metatag" tag="lang">.NET</div>'),
292
293
293 (('license', '[license =&gt; BSD 3-clause]'), '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/BSD 3-clause">BSD 3-clause</a></div>'),
294 (('license', '[license =&gt; BSD 3-clause]'), '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/BSD 3-clause">BSD 3-clause</a></div>'),
294 (('license', '[license =&gt; GPLv3]'), '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/GPLv3">GPLv3</a></div>'),
295 (('license', '[license =&gt; GPLv3]'), '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/GPLv3">GPLv3</a></div>'),
295 (('license', '[license =&gt; MIT]'), '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/MIT">MIT</a></div>'),
296 (('license', '[license =&gt; MIT]'), '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/MIT">MIT</a></div>'),
296 (('license', '[license =&gt; AGPLv3]'), '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/AGPLv3">AGPLv3</a></div>'),
297 (('license', '[license =&gt; AGPLv3]'), '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/AGPLv3">AGPLv3</a></div>'),
297
298
298 (('ref', '[requires =&gt; RepoName]'), '<div class="metatag" tag="ref requires">requires: <a href="/RepoName">RepoName</a></div>'),
299 (('ref', '[requires =&gt; RepoName]'), '<div class="metatag" tag="ref requires">requires: <a href="/RepoName">RepoName</a></div>'),
299 (('ref', '[recommends =&gt; GroupName]'), '<div class="metatag" tag="ref recommends">recommends: <a href="/GroupName">GroupName</a></div>'),
300 (('ref', '[recommends =&gt; GroupName]'), '<div class="metatag" tag="ref recommends">recommends: <a href="/GroupName">GroupName</a></div>'),
300 (('ref', '[conflicts =&gt; SomeName]'), '<div class="metatag" tag="ref conflicts">conflicts: <a href="/SomeName">SomeName</a></div>'),
301 (('ref', '[conflicts =&gt; SomeName]'), '<div class="metatag" tag="ref conflicts">conflicts: <a href="/SomeName">SomeName</a></div>'),
301 (('ref', '[base =&gt; SomeName]'), '<div class="metatag" tag="ref base">base: <a href="/SomeName">SomeName</a></div>'),
302 (('ref', '[base =&gt; SomeName]'), '<div class="metatag" tag="ref base">base: <a href="/SomeName">SomeName</a></div>'),
302
303
303 (('see', '[see =&gt; http://rhodecode.com]'), '<div class="metatag" tag="see">see: http://rhodecode.com </div>'),
304 (('see', '[see =&gt; http://rhodecode.com]'), '<div class="metatag" tag="see">see: http://rhodecode.com </div>'),
304
305
305 (('url', '[url =&gt; [linkName](https://rhodecode.com)]'), '<div class="metatag" tag="url"> <a href="https://rhodecode.com">linkName</a> </div>'),
306 (('url', '[url =&gt; [linkName](https://rhodecode.com)]'), '<div class="metatag" tag="url"> <a href="https://rhodecode.com">linkName</a> </div>'),
306 (('url', '[url =&gt; [example link](https://rhodecode.com)]'), '<div class="metatag" tag="url"> <a href="https://rhodecode.com">example link</a> </div>'),
307 (('url', '[url =&gt; [example link](https://rhodecode.com)]'), '<div class="metatag" tag="url"> <a href="https://rhodecode.com">example link</a> </div>'),
307 (('url', '[url =&gt; [v1.0.0](https://rhodecode.com)]'), '<div class="metatag" tag="url"> <a href="https://rhodecode.com">v1.0.0</a> </div>'),
308 (('url', '[url =&gt; [v1.0.0](https://rhodecode.com)]'), '<div class="metatag" tag="url"> <a href="https://rhodecode.com">v1.0.0</a> </div>'),
308
309
309 ])
310 ])
310 def test_metatags_stylize(tag_data, expected_html):
311 def test_metatags_stylize(tag_data, expected_html):
311 from rhodecode.lib.helpers import style_metatag
312 from rhodecode.lib.helpers import style_metatag
312 tag_type,value = tag_data
313 tag_type,value = tag_data
313 assert style_metatag(tag_type, value) == expected_html
314 assert style_metatag(tag_type, value) == expected_html
314
315
315
316
316 @pytest.mark.parametrize("tmpl_url, email, expected", [
317 @pytest.mark.parametrize("tmpl_url, email, expected", [
317 ('http://test.com/{email}', 'test@foo.com', 'http://test.com/test@foo.com'),
318 ('http://test.com/{email}', 'test@foo.com', 'http://test.com/test@foo.com'),
318
319
319 ('http://test.com/{md5email}', 'test@foo.com', 'http://test.com/3cb7232fcc48743000cb86d0d5022bd9'),
320 ('http://test.com/{md5email}', 'test@foo.com', 'http://test.com/3cb7232fcc48743000cb86d0d5022bd9'),
320 ('http://test.com/{md5email}', 'testΔ…Δ‡@foo.com', 'http://test.com/978debb907a3c55cd741872ab293ef30'),
321 ('http://test.com/{md5email}', 'testΔ…Δ‡@foo.com', 'http://test.com/978debb907a3c55cd741872ab293ef30'),
321
322
322 ('http://testX.com/{md5email}?s={size}', 'test@foo.com', 'http://testX.com/3cb7232fcc48743000cb86d0d5022bd9?s=24'),
323 ('http://testX.com/{md5email}?s={size}', 'test@foo.com', 'http://testX.com/3cb7232fcc48743000cb86d0d5022bd9?s=24'),
323 ('http://testX.com/{md5email}?s={size}', 'testΔ…Δ‡@foo.com', 'http://testX.com/978debb907a3c55cd741872ab293ef30?s=24'),
324 ('http://testX.com/{md5email}?s={size}', 'testΔ…Δ‡@foo.com', 'http://testX.com/978debb907a3c55cd741872ab293ef30?s=24'),
324
325
325 ('{scheme}://{netloc}/{md5email}/{size}', 'test@foo.com', 'https://server.com/3cb7232fcc48743000cb86d0d5022bd9/24'),
326 ('{scheme}://{netloc}/{md5email}/{size}', 'test@foo.com', 'https://server.com/3cb7232fcc48743000cb86d0d5022bd9/24'),
326 ('{scheme}://{netloc}/{md5email}/{size}', 'testΔ…Δ‡@foo.com', 'https://server.com/978debb907a3c55cd741872ab293ef30/24'),
327 ('{scheme}://{netloc}/{md5email}/{size}', 'testΔ…Δ‡@foo.com', 'https://server.com/978debb907a3c55cd741872ab293ef30/24'),
327
328
328 ('http://test.com/{email}', 'testΔ…Δ‡@foo.com', 'http://test.com/testΔ…Δ‡@foo.com'),
329 ('http://test.com/{email}', 'testΔ…Δ‡@foo.com', 'http://test.com/testΔ…Δ‡@foo.com'),
329 ('http://test.com/{email}?size={size}', 'test@foo.com', 'http://test.com/test@foo.com?size=24'),
330 ('http://test.com/{email}?size={size}', 'test@foo.com', 'http://test.com/test@foo.com?size=24'),
330 ('http://test.com/{email}?size={size}', 'testΔ…Δ‡@foo.com', 'http://test.com/testΔ…Δ‡@foo.com?size=24'),
331 ('http://test.com/{email}?size={size}', 'testΔ…Δ‡@foo.com', 'http://test.com/testΔ…Δ‡@foo.com?size=24'),
331 ])
332 ])
332 def test_gravatar_url_builder(tmpl_url, email, expected, request_stub):
333 def test_gravatar_url_builder(tmpl_url, email, expected, request_stub):
333 from rhodecode.lib.helpers import gravatar_url
334 from rhodecode.lib.helpers import gravatar_url
334
335
335 def fake_tmpl_context(_url):
336 def fake_tmpl_context(_url):
336 _c = AttributeDict()
337 _c = AttributeDict()
337 _c.visual = AttributeDict()
338 _c.visual = AttributeDict()
338 _c.visual.use_gravatar = True
339 _c.visual.use_gravatar = True
339 _c.visual.gravatar_url = _url
340 _c.visual.gravatar_url = _url
340 return _c
341 return _c
341
342
342 # mock pyramid.threadlocals
343 # mock pyramid.threadlocals
343 def fake_get_current_request():
344 def fake_get_current_request():
344 request_stub.scheme = 'https'
345 request_stub.scheme = 'https'
345 request_stub.host = 'server.com'
346 request_stub.host = 'server.com'
346
347
347 request_stub._call_context = fake_tmpl_context(tmpl_url)
348 request_stub._call_context = fake_tmpl_context(tmpl_url)
348 return request_stub
349 return request_stub
349
350
350 with mock.patch('rhodecode.lib.helpers.get_current_request',
351 with mock.patch('rhodecode.lib.helpers.get_current_request',
351 fake_get_current_request):
352 fake_get_current_request):
352
353
353 grav = gravatar_url(email_address=email, size=24)
354 grav = gravatar_url(email_address=email, size=24)
354 assert grav == expected
355 assert grav == expected
355
356
356
357
357 @pytest.mark.parametrize(
358 @pytest.mark.parametrize(
358 "email, first_name, last_name, expected_initials, expected_color", [
359 "email, first_name, last_name, expected_initials, expected_color", [
359
360
360 ('test@rhodecode.com', '', '', 'TR', '#8a994d'),
361 ('test@rhodecode.com', '', '', 'TR', '#8a994d'),
361 ('marcin.kuzminski@rhodecode.com', '', '', 'MK', '#6559b3'),
362 ('marcin.kuzminski@rhodecode.com', '', '', 'MK', '#6559b3'),
362 # special cases of email
363 # special cases of email
363 ('john.van.dam@rhodecode.com', '', '', 'JD', '#526600'),
364 ('john.van.dam@rhodecode.com', '', '', 'JD', '#526600'),
364 ('Guido.van.Rossum@rhodecode.com', '', '', 'GR', '#990052'),
365 ('Guido.van.Rossum@rhodecode.com', '', '', 'GR', '#990052'),
365 ('Guido.van.Rossum@rhodecode.com', 'Guido', 'Van Rossum', 'GR', '#990052'),
366 ('Guido.van.Rossum@rhodecode.com', 'Guido', 'Van Rossum', 'GR', '#990052'),
366
367
367 ('rhodecode+Guido.van.Rossum@rhodecode.com', '', '', 'RR', '#46598c'),
368 ('rhodecode+Guido.van.Rossum@rhodecode.com', '', '', 'RR', '#46598c'),
368 ('pclouds@rhodecode.com', 'Nguyα»…n ThΓ‘i', 'Tgọc Duy', 'ND', '#665200'),
369 ('pclouds@rhodecode.com', 'Nguyα»…n ThΓ‘i', 'Tgọc Duy', 'ND', '#665200'),
369
370
370 ('john-brown@foo.com', '', '', 'JF', '#73006b'),
371 ('john-brown@foo.com', '', '', 'JF', '#73006b'),
371 ('admin@rhodecode.com', 'Marcin', 'Kuzminski', 'MK', '#104036'),
372 ('admin@rhodecode.com', 'Marcin', 'Kuzminski', 'MK', '#104036'),
372 # partials
373 # partials
373 ('admin@rhodecode.com', 'Marcin', '', 'MR', '#104036'), # fn+email
374 ('admin@rhodecode.com', 'Marcin', '', 'MR', '#104036'), # fn+email
374 ('admin@rhodecode.com', '', 'Kuzminski', 'AK', '#104036'), # em+ln
375 ('admin@rhodecode.com', '', 'Kuzminski', 'AK', '#104036'), # em+ln
375 # non-ascii
376 # non-ascii
376 ('admin@rhodecode.com', 'Marcin', 'Śuzminski', 'MS', '#104036'),
377 ('admin@rhodecode.com', 'Marcin', 'Śuzminski', 'MS', '#104036'),
378 ('admin@rhodecode.com', 'Łukasz', 'Śuzminski', 'LS', '#104036'),
379 ('admin@rhodecode.com', 'Fabian', 'Łukaszewski', 'FL', '#104036'),
380
377 ('marcin.Ε›uzminski@rhodecode.com', '', '', 'MS', '#73000f'),
381 ('marcin.Ε›uzminski@rhodecode.com', '', '', 'MS', '#73000f'),
378
382
379 # special cases, LDAP can provide those...
383 # special cases, LDAP can provide those...
380 ('admin@', 'Marcin', 'Śuzminski', 'MS', '#aa00ff'),
384 ('admin@', 'Marcin', 'Śuzminski', 'MS', '#aa00ff'),
381 ('marcin.Ε›uzminski', '', '', 'MS', '#402020'),
385 ('marcin.Ε›uzminski', '', '', 'MS', '#402020'),
382 ('null', '', '', 'NL', '#8c4646'),
386 ('null', '', '', 'NL', '#8c4646'),
383 ('some.@abc.com', 'some', '', 'SA', '#664e33')
387 ('some.@abc.com', 'some', '', 'SA', '#664e33')
384 ])
388 ])
385 def test_initials_gravatar_pick_of_initials_and_color_algo(
389 def test_initials_gravatar_pick_of_initials_and_color_algo(
386 email, first_name, last_name, expected_initials, expected_color):
390 email, first_name, last_name, expected_initials, expected_color):
387 instance = InitialsGravatar(email, first_name, last_name)
391 instance = InitialsGravatar(email, first_name, last_name)
388 assert instance.get_initials() == expected_initials
392 assert instance.get_initials() == expected_initials
389 assert instance.str2color(email) == expected_color
393 assert instance.str2color(email) == expected_color
390
394
391
395
392 def test_initials_gravatar_mapping_algo():
396 def test_initials_gravatar_mapping_algo():
393 pos = set()
397 pos = set()
394 instance = InitialsGravatar('', '', '')
398 instance = InitialsGravatar('', '', '')
395 iterations = 0
399 iterations = 0
396
400
397 variations = []
401 variations = []
398 for letter1 in string.ascii_letters:
402 for letter1 in string.ascii_letters:
399 for letter2 in string.ascii_letters[::-1][:10]:
403 for letter2 in string.ascii_letters[::-1][:10]:
400 for letter3 in string.ascii_letters[:10]:
404 for letter3 in string.ascii_letters[:10]:
401 variations.append(
405 variations.append(
402 '%s@rhodecode.com' % (letter1+letter2+letter3))
406 '%s@rhodecode.com' % (letter1+letter2+letter3))
403
407
404 max_variations = 4096
408 max_variations = 4096
405 for email in variations[:max_variations]:
409 for email in variations[:max_variations]:
406 iterations += 1
410 iterations += 1
407 pos.add(
411 pos.add(
408 instance.pick_color_bank_index(email,
412 instance.pick_color_bank_index(email,
409 instance.get_color_bank()))
413 instance.get_color_bank()))
410
414
411 # we assume that we have match all 256 possible positions,
415 # we assume that we have match all 256 possible positions,
412 # in reasonable amount of different email addresses
416 # in reasonable amount of different email addresses
413 assert len(pos) == 256
417 assert len(pos) == 256
414 assert iterations == max_variations
418 assert iterations == max_variations
415
419
416
420
417 @pytest.mark.parametrize("tmpl, repo_name, overrides, prefix, expected", [
421 @pytest.mark.parametrize("tmpl, repo_name, overrides, prefix, expected", [
418 (Repository.DEFAULT_CLONE_URI, 'group/repo1', {}, '', 'http://vps1:8000/group/repo1'),
422 (Repository.DEFAULT_CLONE_URI, 'group/repo1', {}, '', 'http://vps1:8000/group/repo1'),
419 (Repository.DEFAULT_CLONE_URI, 'group/repo1', {'user': 'marcink'}, '', 'http://marcink@vps1:8000/group/repo1'),
423 (Repository.DEFAULT_CLONE_URI, 'group/repo1', {'user': 'marcink'}, '', 'http://marcink@vps1:8000/group/repo1'),
420 (Repository.DEFAULT_CLONE_URI, 'group/repo1', {}, '/rc', 'http://vps1:8000/rc/group/repo1'),
424 (Repository.DEFAULT_CLONE_URI, 'group/repo1', {}, '/rc', 'http://vps1:8000/rc/group/repo1'),
421 (Repository.DEFAULT_CLONE_URI, 'group/repo1', {'user': 'user'}, '/rc', 'http://user@vps1:8000/rc/group/repo1'),
425 (Repository.DEFAULT_CLONE_URI, 'group/repo1', {'user': 'user'}, '/rc', 'http://user@vps1:8000/rc/group/repo1'),
422 (Repository.DEFAULT_CLONE_URI, 'group/repo1', {'user': 'marcink'}, '/rc', 'http://marcink@vps1:8000/rc/group/repo1'),
426 (Repository.DEFAULT_CLONE_URI, 'group/repo1', {'user': 'marcink'}, '/rc', 'http://marcink@vps1:8000/rc/group/repo1'),
423 (Repository.DEFAULT_CLONE_URI, 'group/repo1', {'user': 'user'}, '/rc/', 'http://user@vps1:8000/rc/group/repo1'),
427 (Repository.DEFAULT_CLONE_URI, 'group/repo1', {'user': 'user'}, '/rc/', 'http://user@vps1:8000/rc/group/repo1'),
424 (Repository.DEFAULT_CLONE_URI, 'group/repo1', {'user': 'marcink'}, '/rc/', 'http://marcink@vps1:8000/rc/group/repo1'),
428 (Repository.DEFAULT_CLONE_URI, 'group/repo1', {'user': 'marcink'}, '/rc/', 'http://marcink@vps1:8000/rc/group/repo1'),
425 ('{scheme}://{user}@{netloc}/_{repoid}', 'group/repo1', {}, '', 'http://vps1:8000/_23'),
429 ('{scheme}://{user}@{netloc}/_{repoid}', 'group/repo1', {}, '', 'http://vps1:8000/_23'),
426 ('{scheme}://{user}@{netloc}/_{repoid}', 'group/repo1', {'user': 'marcink'}, '', 'http://marcink@vps1:8000/_23'),
430 ('{scheme}://{user}@{netloc}/_{repoid}', 'group/repo1', {'user': 'marcink'}, '', 'http://marcink@vps1:8000/_23'),
427 ('http://{user}@{netloc}/_{repoid}', 'group/repo1', {'user': 'marcink'}, '', 'http://marcink@vps1:8000/_23'),
431 ('http://{user}@{netloc}/_{repoid}', 'group/repo1', {'user': 'marcink'}, '', 'http://marcink@vps1:8000/_23'),
428 ('http://{netloc}/_{repoid}', 'group/repo1', {'user': 'marcink'}, '', 'http://vps1:8000/_23'),
432 ('http://{netloc}/_{repoid}', 'group/repo1', {'user': 'marcink'}, '', 'http://vps1:8000/_23'),
429 ('https://{user}@proxy1.server.com/{repo}', 'group/repo1', {'user': 'marcink'}, '', 'https://marcink@proxy1.server.com/group/repo1'),
433 ('https://{user}@proxy1.server.com/{repo}', 'group/repo1', {'user': 'marcink'}, '', 'https://marcink@proxy1.server.com/group/repo1'),
430 ('https://{user}@proxy1.server.com/{repo}', 'group/repo1', {}, '', 'https://proxy1.server.com/group/repo1'),
434 ('https://{user}@proxy1.server.com/{repo}', 'group/repo1', {}, '', 'https://proxy1.server.com/group/repo1'),
431 ('https://proxy1.server.com/{user}/{repo}', 'group/repo1', {'user': 'marcink'}, '', 'https://proxy1.server.com/marcink/group/repo1'),
435 ('https://proxy1.server.com/{user}/{repo}', 'group/repo1', {'user': 'marcink'}, '', 'https://proxy1.server.com/marcink/group/repo1'),
432 ])
436 ])
433 def test_clone_url_generator(tmpl, repo_name, overrides, prefix, expected):
437 def test_clone_url_generator(tmpl, repo_name, overrides, prefix, expected):
434 from rhodecode.lib.utils2 import get_clone_url
438 from rhodecode.lib.utils2 import get_clone_url
435
439
436 class RequestStub(object):
440 class RequestStub(object):
437 def request_url(self, name):
441 def request_url(self, name):
438 return 'http://vps1:8000' + prefix
442 return 'http://vps1:8000' + prefix
439
443
440 def route_url(self, name):
444 def route_url(self, name):
441 return self.request_url(name)
445 return self.request_url(name)
442
446
443 clone_url = get_clone_url(
447 clone_url = get_clone_url(
444 request=RequestStub(),
448 request=RequestStub(),
445 uri_tmpl=tmpl,
449 uri_tmpl=tmpl,
446 repo_name=repo_name, repo_id=23, repo_type='hg', **overrides)
450 repo_name=repo_name, repo_id=23, repo_type='hg', **overrides)
447 assert clone_url == expected
451 assert clone_url == expected
448
452
449
453
450 def test_clone_url_svn_ssh_generator():
454 def test_clone_url_svn_ssh_generator():
451 from rhodecode.lib.utils2 import get_clone_url
455 from rhodecode.lib.utils2 import get_clone_url
452
456
453 class RequestStub(object):
457 class RequestStub(object):
454 def request_url(self, name):
458 def request_url(self, name):
455 return 'http://vps1:8000'
459 return 'http://vps1:8000'
456
460
457 def route_url(self, name):
461 def route_url(self, name):
458 return self.request_url(name)
462 return self.request_url(name)
459
463
460 clone_url = get_clone_url(
464 clone_url = get_clone_url(
461 request=RequestStub(),
465 request=RequestStub(),
462 uri_tmpl=Repository.DEFAULT_CLONE_URI_SSH,
466 uri_tmpl=Repository.DEFAULT_CLONE_URI_SSH,
463 repo_name='svn-test', repo_id=23, repo_type='svn', **{'sys_user': 'rcdev'})
467 repo_name='svn-test', repo_id=23, repo_type='svn', **{'sys_user': 'rcdev'})
464 assert clone_url == 'svn+ssh://rcdev@vps1/svn-test'
468 assert clone_url == 'svn+ssh://rcdev@vps1/svn-test'
465
469
466
470
467 idx = 0
471 idx = 0
468
472
469
473
470 def _quick_url(text, tmpl="""<a class="tooltip-hovercard revision-link" href="%s" data-hovercard-alt="Commit: %s" data-hovercard-url="/some-url">%s</a>""", url_=None, commits=''):
474 def _quick_url(text, tmpl="""<a class="tooltip-hovercard revision-link" href="%s" data-hovercard-alt="Commit: %s" data-hovercard-url="/some-url">%s</a>""", url_=None, commits=''):
471 """
475 """
472 Changes `some text url[foo]` => `some text <a href="/">foo</a>
476 Changes `some text url[foo]` => `some text <a href="/">foo</a>
473
477
474 :param text:
478 :param text:
475 """
479 """
476 import re
480 import re
477 # quickly change expected url[] into a link
481 # quickly change expected url[] into a link
478 url_pat = re.compile(r'(?:url\[)(.+?)(?:\])')
482 url_pat = re.compile(r'(?:url\[)(.+?)(?:\])')
479 commits = commits or []
483 commits = commits or []
480
484
481 global idx
485 global idx
482 idx = 0
486 idx = 0
483
487
484 def url_func(match_obj):
488 def url_func(match_obj):
485 global idx
489 global idx
486 _url = match_obj.groups()[0]
490 _url = match_obj.groups()[0]
487 if commits:
491 if commits:
488 commit = commits[idx]
492 commit = commits[idx]
489 idx += 1
493 idx += 1
490 return tmpl % (url_ or '/some-url', _url, commit)
494 return tmpl % (url_ or '/some-url', _url, commit)
491 else:
495 else:
492 return tmpl % (url_ or '/some-url', _url)
496 return tmpl % (url_ or '/some-url', _url)
493
497
494 return url_pat.sub(url_func, text)
498 return url_pat.sub(url_func, text)
495
499
496
500
497 @pytest.mark.parametrize("sample, expected, commits", [
501 @pytest.mark.parametrize("sample, expected, commits", [
498 (
502 (
499 "",
503 "",
500 "",
504 "",
501 [""]
505 [""]
502 ),
506 ),
503 (
507 (
504 "git-svn-id: https://svn.apache.org/repos/asf/libcloud/trunk@1441655 13f79535-47bb-0310-9956-ffa450edef68",
508 "git-svn-id: https://svn.apache.org/repos/asf/libcloud/trunk@1441655 13f79535-47bb-0310-9956-ffa450edef68",
505 "git-svn-id: https://svn.apache.org/repos/asf/libcloud/trunk@1441655 13f79535-47bb-0310-9956-ffa450edef68",
509 "git-svn-id: https://svn.apache.org/repos/asf/libcloud/trunk@1441655 13f79535-47bb-0310-9956-ffa450edef68",
506 [""]
510 [""]
507 ),
511 ),
508 (
512 (
509 "from rev 000000000000",
513 "from rev 000000000000",
510 "from rev url[000000000000]",
514 "from rev url[000000000000]",
511 ["000000000000"]
515 ["000000000000"]
512 ),
516 ),
513
517
514 (
518 (
515 "from rev 000000000000123123 also rev 000000000000",
519 "from rev 000000000000123123 also rev 000000000000",
516 "from rev url[000000000000123123] also rev url[000000000000]",
520 "from rev url[000000000000123123] also rev url[000000000000]",
517 ["000000000000123123", "000000000000"]
521 ["000000000000123123", "000000000000"]
518 ),
522 ),
519 (
523 (
520 "this should-000 00",
524 "this should-000 00",
521 "this should-000 00",
525 "this should-000 00",
522 [""]
526 [""]
523 ),
527 ),
524 (
528 (
525 "longtextffffffffff rev 123123123123",
529 "longtextffffffffff rev 123123123123",
526 "longtextffffffffff rev url[123123123123]",
530 "longtextffffffffff rev url[123123123123]",
527 ["123123123123"]
531 ["123123123123"]
528 ),
532 ),
529 (
533 (
530 "rev ffffffffffffffffffffffffffffffffffffffffffffffffff",
534 "rev ffffffffffffffffffffffffffffffffffffffffffffffffff",
531 "rev ffffffffffffffffffffffffffffffffffffffffffffffffff",
535 "rev ffffffffffffffffffffffffffffffffffffffffffffffffff",
532 ["ffffffffffffffffffffffffffffffffffffffffffffffffff"]
536 ["ffffffffffffffffffffffffffffffffffffffffffffffffff"]
533 ),
537 ),
534 (
538 (
535 "ffffffffffff some text traalaa",
539 "ffffffffffff some text traalaa",
536 "url[ffffffffffff] some text traalaa",
540 "url[ffffffffffff] some text traalaa",
537 ["ffffffffffff"]
541 ["ffffffffffff"]
538 ),
542 ),
539 (
543 (
540 """Multi line
544 """Multi line
541 123123123123
545 123123123123
542 some text 000000000000
546 some text 000000000000
543 sometimes !
547 sometimes !
544 """,
548 """,
545 """Multi line
549 """Multi line
546 url[123123123123]
550 url[123123123123]
547 some text url[000000000000]
551 some text url[000000000000]
548 sometimes !
552 sometimes !
549 """,
553 """,
550 ["123123123123", "000000000000"]
554 ["123123123123", "000000000000"]
551 )
555 )
552 ], ids=no_newline_id_generator)
556 ], ids=no_newline_id_generator)
553 def test_urlify_commits(sample, expected, commits):
557 def test_urlify_commits(sample, expected, commits):
554 def fake_url(self, *args, **kwargs):
558 def fake_url(self, *args, **kwargs):
555 return '/some-url'
559 return '/some-url'
556
560
557 expected = _quick_url(expected, commits=commits)
561 expected = _quick_url(expected, commits=commits)
558
562
559 with mock.patch('rhodecode.lib.helpers.route_url', fake_url):
563 with mock.patch('rhodecode.lib.helpers.route_url', fake_url):
560 from rhodecode.lib.helpers import urlify_commits
564 from rhodecode.lib.helpers import urlify_commits
561 assert urlify_commits(sample, 'repo_name') == expected
565 assert urlify_commits(sample, 'repo_name') == expected
562
566
563
567
564 @pytest.mark.parametrize("sample, expected, url_", [
568 @pytest.mark.parametrize("sample, expected, url_", [
565 ("",
569 ("",
566 "",
570 "",
567 ""),
571 ""),
568 ("https://svn.apache.org/repos",
572 ("https://svn.apache.org/repos",
569 "url[https://svn.apache.org/repos]",
573 "url[https://svn.apache.org/repos]",
570 "https://svn.apache.org/repos"),
574 "https://svn.apache.org/repos"),
571 ("http://svn.apache.org/repos",
575 ("http://svn.apache.org/repos",
572 "url[http://svn.apache.org/repos]",
576 "url[http://svn.apache.org/repos]",
573 "http://svn.apache.org/repos"),
577 "http://svn.apache.org/repos"),
574 ("from rev a also rev http://google.com",
578 ("from rev a also rev http://google.com",
575 "from rev a also rev url[http://google.com]",
579 "from rev a also rev url[http://google.com]",
576 "http://google.com"),
580 "http://google.com"),
577 ("""Multi line
581 ("""Multi line
578 https://foo.bar.com
582 https://foo.bar.com
579 some text lalala""",
583 some text lalala""",
580 """Multi line
584 """Multi line
581 url[https://foo.bar.com]
585 url[https://foo.bar.com]
582 some text lalala""",
586 some text lalala""",
583 "https://foo.bar.com")
587 "https://foo.bar.com")
584 ], ids=no_newline_id_generator)
588 ], ids=no_newline_id_generator)
585 def test_urlify_test(sample, expected, url_):
589 def test_urlify_test(sample, expected, url_):
586 from rhodecode.lib.helpers import urlify_text
590 from rhodecode.lib.helpers import urlify_text
587 expected = _quick_url(expected, tmpl="""<a href="%s">%s</a>""", url_=url_)
591 expected = _quick_url(expected, tmpl="""<a href="%s">%s</a>""", url_=url_)
588 assert urlify_text(sample) == expected
592 assert urlify_text(sample) == expected
589
593
590
594
591 @pytest.mark.parametrize("test, expected", [
595 @pytest.mark.parametrize("test, expected", [
592 ("", None),
596 ("", None),
593 ("/_2", '2'),
597 ("/_2", '2'),
594 ("_2", '2'),
598 ("_2", '2'),
595 ("/_2/", '2'),
599 ("/_2/", '2'),
596 ("_2/", '2'),
600 ("_2/", '2'),
597
601
598 ("/_21", '21'),
602 ("/_21", '21'),
599 ("_21", '21'),
603 ("_21", '21'),
600 ("/_21/", '21'),
604 ("/_21/", '21'),
601 ("_21/", '21'),
605 ("_21/", '21'),
602
606
603 ("/_21/foobar", '21'),
607 ("/_21/foobar", '21'),
604 ("_21/121", '21'),
608 ("_21/121", '21'),
605 ("/_21/_12", '21'),
609 ("/_21/_12", '21'),
606 ("_21/rc/foo", '21'),
610 ("_21/rc/foo", '21'),
607
611
608 ])
612 ])
609 def test_get_repo_by_id(test, expected):
613 def test_get_repo_by_id(test, expected):
610 from rhodecode.model.repo import RepoModel
614 from rhodecode.model.repo import RepoModel
611 _test = RepoModel()._extract_id_from_repo_name(test)
615 _test = RepoModel()._extract_id_from_repo_name(test)
612 assert _test == expected
616 assert _test == expected
613
617
614
618
615 def test_invalidation_context(baseapp):
619 def test_invalidation_context(baseapp):
616 repo_id = 9999
620 repo_id = 9999
617
621
618 cache_namespace_uid = 'cache_repo_instance.{}_{}'.format(
622 cache_namespace_uid = 'cache_repo_instance.{}_{}'.format(
619 repo_id, CacheKey.CACHE_TYPE_FEED)
623 repo_id, CacheKey.CACHE_TYPE_FEED)
620 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
624 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
621 repo_id=repo_id)
625 repo_id=repo_id)
622 region = rc_cache.get_or_create_region('cache_repo_longterm', cache_namespace_uid)
626 region = rc_cache.get_or_create_region('cache_repo_longterm', cache_namespace_uid)
623
627
624 calls = [1, 2]
628 calls = [1, 2]
625
629
626 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid)
630 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid)
627 def _dummy_func(cache_key):
631 def _dummy_func(cache_key):
628 val = calls.pop(0)
632 val = calls.pop(0)
629 return 'result:{}'.format(val)
633 return 'result:{}'.format(val)
630
634
631 inv_context_manager = rc_cache.InvalidationContext(
635 inv_context_manager = rc_cache.InvalidationContext(
632 uid=cache_namespace_uid, invalidation_namespace=invalidation_namespace)
636 uid=cache_namespace_uid, invalidation_namespace=invalidation_namespace)
633
637
634 # 1st call, fresh caches
638 # 1st call, fresh caches
635 with inv_context_manager as invalidation_context:
639 with inv_context_manager as invalidation_context:
636 should_invalidate = invalidation_context.should_invalidate()
640 should_invalidate = invalidation_context.should_invalidate()
637 if should_invalidate:
641 if should_invalidate:
638 result = _dummy_func.refresh('some-key')
642 result = _dummy_func.refresh('some-key')
639 else:
643 else:
640 result = _dummy_func('some-key')
644 result = _dummy_func('some-key')
641
645
642 assert isinstance(invalidation_context, rc_cache.FreshRegionCache)
646 assert isinstance(invalidation_context, rc_cache.FreshRegionCache)
643 assert should_invalidate is True
647 assert should_invalidate is True
644
648
645 assert 'result:1' == result
649 assert 'result:1' == result
646 # should be cached so calling it twice will give the same result !
650 # should be cached so calling it twice will give the same result !
647 result = _dummy_func('some-key')
651 result = _dummy_func('some-key')
648 assert 'result:1' == result
652 assert 'result:1' == result
649
653
650 # 2nd call, we create a new context manager, this should be now key aware, and
654 # 2nd call, we create a new context manager, this should be now key aware, and
651 # return an active cache region
655 # return an active cache region
652 with inv_context_manager as invalidation_context:
656 with inv_context_manager as invalidation_context:
653 should_invalidate = invalidation_context.should_invalidate()
657 should_invalidate = invalidation_context.should_invalidate()
654 assert isinstance(invalidation_context, rc_cache.ActiveRegionCache)
658 assert isinstance(invalidation_context, rc_cache.ActiveRegionCache)
655 assert should_invalidate is False
659 assert should_invalidate is False
656
660
657 # Mark invalidation
661 # Mark invalidation
658 CacheKey.set_invalidate(invalidation_namespace)
662 CacheKey.set_invalidate(invalidation_namespace)
659
663
660 # 3nd call, fresh caches
664 # 3nd call, fresh caches
661 with inv_context_manager as invalidation_context:
665 with inv_context_manager as invalidation_context:
662 should_invalidate = invalidation_context.should_invalidate()
666 should_invalidate = invalidation_context.should_invalidate()
663 if should_invalidate:
667 if should_invalidate:
664 result = _dummy_func.refresh('some-key')
668 result = _dummy_func.refresh('some-key')
665 else:
669 else:
666 result = _dummy_func('some-key')
670 result = _dummy_func('some-key')
667
671
668 assert isinstance(invalidation_context, rc_cache.FreshRegionCache)
672 assert isinstance(invalidation_context, rc_cache.FreshRegionCache)
669 assert should_invalidate is True
673 assert should_invalidate is True
670
674
671 assert 'result:2' == result
675 assert 'result:2' == result
672
676
673 # cached again, same result
677 # cached again, same result
674 result = _dummy_func('some-key')
678 result = _dummy_func('some-key')
675 assert 'result:2' == result
679 assert 'result:2' == result
676
680
677
681
678 def test_invalidation_context_exception_in_compute(baseapp):
682 def test_invalidation_context_exception_in_compute(baseapp):
679 repo_id = 888
683 repo_id = 888
680
684
681 cache_namespace_uid = 'cache_repo_instance.{}_{}'.format(
685 cache_namespace_uid = 'cache_repo_instance.{}_{}'.format(
682 repo_id, CacheKey.CACHE_TYPE_FEED)
686 repo_id, CacheKey.CACHE_TYPE_FEED)
683 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
687 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
684 repo_id=repo_id)
688 repo_id=repo_id)
685 region = rc_cache.get_or_create_region('cache_repo_longterm', cache_namespace_uid)
689 region = rc_cache.get_or_create_region('cache_repo_longterm', cache_namespace_uid)
686
690
687 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid)
691 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid)
688 def _dummy_func(cache_key):
692 def _dummy_func(cache_key):
689 raise Exception('Error in cache func')
693 raise Exception('Error in cache func')
690
694
691 with pytest.raises(Exception):
695 with pytest.raises(Exception):
692 inv_context_manager = rc_cache.InvalidationContext(
696 inv_context_manager = rc_cache.InvalidationContext(
693 uid=cache_namespace_uid, invalidation_namespace=invalidation_namespace)
697 uid=cache_namespace_uid, invalidation_namespace=invalidation_namespace)
694
698
695 # 1st call, fresh caches
699 # 1st call, fresh caches
696 with inv_context_manager as invalidation_context:
700 with inv_context_manager as invalidation_context:
697 should_invalidate = invalidation_context.should_invalidate()
701 should_invalidate = invalidation_context.should_invalidate()
698 if should_invalidate:
702 if should_invalidate:
699 _dummy_func.refresh('some-key-2')
703 _dummy_func.refresh('some-key-2')
700 else:
704 else:
701 _dummy_func('some-key-2')
705 _dummy_func('some-key-2')
702
706
703
707
704 @pytest.mark.parametrize('execution_number', range(5))
708 @pytest.mark.parametrize('execution_number', range(5))
705 def test_cache_invalidation_race_condition(execution_number, baseapp):
709 def test_cache_invalidation_race_condition(execution_number, baseapp):
706 import time
710 import time
707
711
708 repo_id = 777
712 repo_id = 777
709
713
710 cache_namespace_uid = 'cache_repo_instance.{}_{}'.format(
714 cache_namespace_uid = 'cache_repo_instance.{}_{}'.format(
711 repo_id, CacheKey.CACHE_TYPE_FEED)
715 repo_id, CacheKey.CACHE_TYPE_FEED)
712 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
716 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
713 repo_id=repo_id)
717 repo_id=repo_id)
714 region = rc_cache.get_or_create_region('cache_repo_longterm', cache_namespace_uid)
718 region = rc_cache.get_or_create_region('cache_repo_longterm', cache_namespace_uid)
715
719
716 @run_test_concurrently(25)
720 @run_test_concurrently(25)
717 def test_create_and_delete_cache_keys():
721 def test_create_and_delete_cache_keys():
718 time.sleep(0.2)
722 time.sleep(0.2)
719
723
720 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid)
724 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid)
721 def _dummy_func(cache_key):
725 def _dummy_func(cache_key):
722 val = 'async'
726 val = 'async'
723 return 'result:{}'.format(val)
727 return 'result:{}'.format(val)
724
728
725 inv_context_manager = rc_cache.InvalidationContext(
729 inv_context_manager = rc_cache.InvalidationContext(
726 uid=cache_namespace_uid, invalidation_namespace=invalidation_namespace)
730 uid=cache_namespace_uid, invalidation_namespace=invalidation_namespace)
727
731
728 # 1st call, fresh caches
732 # 1st call, fresh caches
729 with inv_context_manager as invalidation_context:
733 with inv_context_manager as invalidation_context:
730 should_invalidate = invalidation_context.should_invalidate()
734 should_invalidate = invalidation_context.should_invalidate()
731 if should_invalidate:
735 if should_invalidate:
732 _dummy_func.refresh('some-key-3')
736 _dummy_func.refresh('some-key-3')
733 else:
737 else:
734 _dummy_func('some-key-3')
738 _dummy_func('some-key-3')
735
739
736 # Mark invalidation
740 # Mark invalidation
737 CacheKey.set_invalidate(invalidation_namespace)
741 CacheKey.set_invalidate(invalidation_namespace)
738
742
739 test_create_and_delete_cache_keys()
743 test_create_and_delete_cache_keys()
General Comments 0
You need to be logged in to leave comments. Login now