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