Revision 480585cd
b/kamaki/clients/test.py | ||
---|---|---|
35 | 35 |
from time import sleep |
36 | 36 |
from inspect import getmembers, isclass |
37 | 37 |
|
38 |
from kamaki.clients.utils.test import Utils |
|
38 | 39 |
from kamaki.clients.astakos.test import Astakos |
39 | 40 |
from kamaki.clients.compute.test import Compute, ComputeRest |
40 | 41 |
from kamaki.clients.cyclades.test import Cyclades, CycladesRest |
/dev/null | ||
---|---|---|
1 |
# Copyright 2011-2012 GRNET S.A. All rights reserved. |
|
2 |
# |
|
3 |
# Redistribution and use in source and binary forms, with or |
|
4 |
# without modification, are permitted provided that the following |
|
5 |
# conditions are met: |
|
6 |
# |
|
7 |
# 1. Redistributions of source code must retain the above |
|
8 |
# copyright notice, this list of conditions and the following |
|
9 |
# disclaimer. |
|
10 |
# |
|
11 |
# 2. Redistributions in binary form must reproduce the above |
|
12 |
# copyright notice, this list of conditions and the following |
|
13 |
# disclaimer in the documentation and/or other materials |
|
14 |
# provided with the distribution. |
|
15 |
# |
|
16 |
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS |
|
17 |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
18 |
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
19 |
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR |
|
20 |
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
21 |
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
22 |
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
|
23 |
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
|
24 |
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
25 |
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
|
26 |
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
27 |
# POSSIBILITY OF SUCH DAMAGE. |
|
28 |
# |
|
29 |
# The views and conclusions contained in the software and |
|
30 |
# documentation are those of the authors and should not be |
|
31 |
# interpreted as representing official policies, either expressed |
|
32 |
# or implied, of GRNET S.A. |
|
33 |
|
|
34 |
|
|
35 |
def _matches(val1, val2, exactMath=True): |
|
36 |
"""Case Insensitive match""" |
|
37 |
|
|
38 |
if exactMath: |
|
39 |
return True if val1.lower() == val2.lower() else False |
|
40 |
else: |
|
41 |
return True if val1.lower().startswith(val2.lower()) else False |
|
42 |
|
|
43 |
|
|
44 |
def filter_out(d, prefix, exactMatch=False): |
|
45 |
"""Remove entries that are prefixed with prefix (case insensitive) |
|
46 |
|
|
47 |
:param d: (dict) input |
|
48 |
|
|
49 |
:param prefix: (str) prefix to match input keys against |
|
50 |
|
|
51 |
:param exactMatch: (bool) key should fully match if True, just prefixed |
|
52 |
with prefix if False |
|
53 |
|
|
54 |
:returns: (dict) the updated d |
|
55 |
""" |
|
56 |
|
|
57 |
ret = {} |
|
58 |
for key, val in d.items(): |
|
59 |
if not _matches(key, prefix, exactMath=exactMatch): |
|
60 |
ret[key] = val |
|
61 |
return ret |
|
62 |
|
|
63 |
|
|
64 |
def filter_in(d, prefix, exactMatch=False): |
|
65 |
"""Keep only entries of d prefixed with prefix |
|
66 |
|
|
67 |
:param d: (dict) input |
|
68 |
|
|
69 |
:param prefix: (str) prefix to match input keys against |
|
70 |
|
|
71 |
:param exactMatch: (bool) key should fully match if True, just prefixed |
|
72 |
with prefix if False |
|
73 |
|
|
74 |
:returns: (dict) the updated d |
|
75 |
""" |
|
76 |
ret = {} |
|
77 |
for key, val in d.items(): |
|
78 |
if _matches(key, prefix, exactMath=exactMatch): |
|
79 |
ret[key] = val |
|
80 |
return ret |
|
81 |
|
|
82 |
|
|
83 |
def path4url(*args): |
|
84 |
""" |
|
85 |
:param args: (list of str) |
|
86 |
|
|
87 |
:returns: (str) a path in the form /args[0]/args[1]/... |
|
88 |
""" |
|
89 |
|
|
90 |
r = '/'.join([''] + [arg.decode('utf-8') if ( |
|
91 |
isinstance(arg, str)) else '%s' % arg for arg in args]) |
|
92 |
while '//' in r: |
|
93 |
r = r.replace('//', '/') |
|
94 |
return ('/%s' % r.strip('/')) if r else '' |
|
95 |
|
|
96 |
|
|
97 |
def params4url(params): |
|
98 |
"""{'key1':'val1', 'key2':None, 'key3':15} --> "?key1=val1&key2&key3=15" |
|
99 |
|
|
100 |
:param params: (dict) request parameters in the form key:val |
|
101 |
|
|
102 |
:returns: (str) http-request friendly in the form ?key1=val1&key2=val2&... |
|
103 |
""" |
|
104 |
|
|
105 |
assert(type(params) is dict) |
|
106 |
result = '' |
|
107 |
dlmtr = '?' |
|
108 |
for name in params: |
|
109 |
result += '%s%s' % (dlmtr, name) |
|
110 |
result += '=%s' % params[name] or result |
|
111 |
dlmtr = '&' |
|
112 |
return result |
b/kamaki/clients/utils/__init__.py | ||
---|---|---|
1 |
# Copyright 2011-2012 GRNET S.A. All rights reserved. |
|
2 |
# |
|
3 |
# Redistribution and use in source and binary forms, with or |
|
4 |
# without modification, are permitted provided that the following |
|
5 |
# conditions are met: |
|
6 |
# |
|
7 |
# 1. Redistributions of source code must retain the above |
|
8 |
# copyright notice, this list of conditions and the following |
|
9 |
# disclaimer. |
|
10 |
# |
|
11 |
# 2. Redistributions in binary form must reproduce the above |
|
12 |
# copyright notice, this list of conditions and the following |
|
13 |
# disclaimer in the documentation and/or other materials |
|
14 |
# provided with the distribution. |
|
15 |
# |
|
16 |
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS |
|
17 |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
18 |
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
19 |
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR |
|
20 |
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
21 |
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
22 |
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
|
23 |
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
|
24 |
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
25 |
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
|
26 |
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
27 |
# POSSIBILITY OF SUCH DAMAGE. |
|
28 |
# |
|
29 |
# The views and conclusions contained in the software and |
|
30 |
# documentation are those of the authors and should not be |
|
31 |
# interpreted as representing official policies, either expressed |
|
32 |
# or implied, of GRNET S.A. |
|
33 |
|
|
34 |
|
|
35 |
def _matches(val1, val2, exactMath=True): |
|
36 |
"""Case Insensitive match""" |
|
37 |
|
|
38 |
return (val1.lower() == val2.lower()) if ( |
|
39 |
exactMath) else val1.lower().startswith(val2.lower()) |
|
40 |
|
|
41 |
|
|
42 |
def filter_out(d, prefix, exactMatch=False): |
|
43 |
"""Remove entries that are prefixed with prefix (case insensitive) |
|
44 |
|
|
45 |
:param d: (dict) input |
|
46 |
|
|
47 |
:param prefix: (str) prefix to match input keys against |
|
48 |
|
|
49 |
:param exactMatch: (bool) key should fully match if True, just prefixed |
|
50 |
with prefix if False |
|
51 |
|
|
52 |
:returns: (dict) the updated d |
|
53 |
""" |
|
54 |
|
|
55 |
ret = dict() |
|
56 |
for key, val in d.items(): |
|
57 |
if not _matches(key, prefix, exactMath=exactMatch): |
|
58 |
ret[key] = val |
|
59 |
return ret |
|
60 |
|
|
61 |
|
|
62 |
def filter_in(d, prefix, exactMatch=False): |
|
63 |
"""Keep only entries of d prefixed with prefix |
|
64 |
|
|
65 |
:param d: (dict) input |
|
66 |
|
|
67 |
:param prefix: (str) prefix to match input keys against |
|
68 |
|
|
69 |
:param exactMatch: (bool) key should fully match if True, just prefixed |
|
70 |
with prefix if False |
|
71 |
|
|
72 |
:returns: (dict) the updated d |
|
73 |
""" |
|
74 |
ret = dict() |
|
75 |
for key, val in d.items(): |
|
76 |
if _matches(key, prefix, exactMath=exactMatch): |
|
77 |
ret[key] = val |
|
78 |
return ret |
|
79 |
|
|
80 |
|
|
81 |
def path4url(*args): |
|
82 |
""" |
|
83 |
:param args: (list of str) |
|
84 |
|
|
85 |
:returns: (str) a path in the form /args[0]/args[1]/... |
|
86 |
""" |
|
87 |
|
|
88 |
r = '/'.join([''] + [arg.decode('utf-8') if ( |
|
89 |
isinstance(arg, str)) else '%s' % arg for arg in args]) |
|
90 |
while '//' in r: |
|
91 |
r = r.replace('//', '/') |
|
92 |
return ('/%s' % r.strip('/')) if r else '' |
|
93 |
|
|
94 |
|
|
95 |
def params4url(params): |
|
96 |
"""{'key1':'val1', 'key2':None, 'key3':15} --> "?key1=val1&key2&key3=15" |
|
97 |
|
|
98 |
:param params: (dict) request parameters in the form key:val |
|
99 |
|
|
100 |
:returns: (str) http-request friendly in the form ?key1=val1&key2=val2&... |
|
101 |
""" |
|
102 |
|
|
103 |
assert(type(params) is dict) |
|
104 |
result = '' |
|
105 |
dlmtr = '?' |
|
106 |
for name in params: |
|
107 |
result += '%s%s' % (dlmtr, name) |
|
108 |
result += '=%s' % params[name] or result |
|
109 |
dlmtr = '&' |
|
110 |
return result |
b/kamaki/clients/utils/test.py | ||
---|---|---|
1 |
# Copyright 2013 GRNET S.A. All rights reserved. |
|
2 |
# |
|
3 |
# Redistribution and use in source and binary forms, with or |
|
4 |
# without modification, are permitted provided that the following |
|
5 |
# conditions are met: |
|
6 |
# |
|
7 |
# 1. Redistributions of source code must retain the above |
|
8 |
# copyright notice, this list of conditions and the following |
|
9 |
# disclaimer. |
|
10 |
# |
|
11 |
# 2. Redistributions in binary form must reproduce the above |
|
12 |
# copyright notice, this list of conditions and the following |
|
13 |
# disclaimer in the documentation and/or other materials |
|
14 |
# provided with the distribution. |
|
15 |
# |
|
16 |
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS |
|
17 |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
18 |
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
19 |
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR |
|
20 |
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
21 |
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
22 |
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
|
23 |
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
|
24 |
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
25 |
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
|
26 |
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
27 |
# POSSIBILITY OF SUCH DAMAGE. |
|
28 |
# |
|
29 |
# The views and conclusions contained in the software and |
|
30 |
# documentation are those of the authors and should not be |
|
31 |
# interpreted as representing official policies, either expressed |
|
32 |
# or implied, of GRNET S.A. |
|
33 |
|
|
34 |
#from mock import patch, call |
|
35 |
|
|
36 |
from unittest import TestCase |
|
37 |
from kamaki.clients import utils |
|
38 |
|
|
39 |
|
|
40 |
def _try(assertfoo, foo, *args): |
|
41 |
try: |
|
42 |
return assertfoo(foo(*args)) |
|
43 |
except AssertionError: |
|
44 |
argstr = '( ' |
|
45 |
for arg in args: |
|
46 |
argstr += '"%s" ' % arg |
|
47 |
argstr += ')' |
|
48 |
print('::: Method %s failed with args %s' % (foo, argstr)) |
|
49 |
raise |
|
50 |
|
|
51 |
filter_examples = [ |
|
52 |
('', dict(), dict(), dict()), |
|
53 |
( |
|
54 |
'key', |
|
55 |
dict(key1='v1', key2='v2', v=dict(key='v'), val1='k1', val2='k2'), |
|
56 |
dict(key1='v1', key2='v2'), |
|
57 |
dict(v=dict(key='v'), val1='k1', val2='k2')), |
|
58 |
( |
|
59 |
'val', |
|
60 |
dict(key1='v1', key2='v2', val=dict(key='v'), val1='k1', val2='k2'), |
|
61 |
dict(val1='k1', val2='k2', val=dict(key='v')), |
|
62 |
dict(key1='v1', key2='v2')), |
|
63 |
( |
|
64 |
'kv', |
|
65 |
dict(kvm='in', mkv='out', kv=''), |
|
66 |
dict(kvm='in', kv=''), |
|
67 |
dict(mkv='out'))] |
|
68 |
|
|
69 |
|
|
70 |
class Utils(TestCase): |
|
71 |
|
|
72 |
def assert_dicts_are_equal(self, d1, d2): |
|
73 |
for k, v in d1.items(): |
|
74 |
self.assertTrue(k in d2) |
|
75 |
if isinstance(v, dict): |
|
76 |
self.assert_dicts_are_equal(v, d2[k]) |
|
77 |
else: |
|
78 |
self.assertEqual(unicode(v), unicode(d2[k])) |
|
79 |
|
|
80 |
def setUp(self): |
|
81 |
pass |
|
82 |
|
|
83 |
def tearDown(self): |
|
84 |
pass |
|
85 |
|
|
86 |
def test__matches(self): |
|
87 |
for args in ( |
|
88 |
('example', 'example'), ('example', 'example', True), |
|
89 |
('example', 'example', False), ('example0', 'example', False), |
|
90 |
('example', '', False), ('', ''), |
|
91 |
('', '', True), ('', '', False)): |
|
92 |
_try(self.assertTrue, utils._matches, *args) |
|
93 |
for args in ( |
|
94 |
('', 'example'), ('example', ''), |
|
95 |
('example', 'example0'), ('example0', 'example'), |
|
96 |
('example', 'example0', True), ('example', 'example0', False), |
|
97 |
('example0', 'example'), ('example0', 'example', True)): |
|
98 |
_try(self.assertFalse, utils._matches, *args) |
|
99 |
|
|
100 |
def test_filter_out(self): |
|
101 |
for key, src, exp_in, exp_out in filter_examples: |
|
102 |
r = utils.filter_out(src, key) |
|
103 |
self.assert_dicts_are_equal(r, exp_out) |
|
104 |
for k in exp_in: |
|
105 |
self.assertFalse(k in r) |
|
106 |
r = utils.filter_out(src, key, True) |
|
107 |
if key in src: |
|
108 |
expected = dict(src) |
|
109 |
expected.pop(key) |
|
110 |
self.assert_dicts_are_equal(r, expected) |
|
111 |
else: |
|
112 |
self.assert_dicts_are_equal(r, src) |
|
113 |
|
|
114 |
def test_filter_in(self): |
|
115 |
for key, src, exp_in, exp_out in filter_examples: |
|
116 |
r = utils.filter_in(src, key) |
|
117 |
self.assert_dicts_are_equal(r, exp_in) |
|
118 |
for k in exp_out: |
|
119 |
self.assertFalse(k in r) |
|
120 |
r = utils.filter_in(src, key, True) |
|
121 |
if key in src: |
|
122 |
self.assert_dicts_are_equal(r, {key: src[key]}) |
|
123 |
else: |
|
124 |
self.assert_dicts_are_equal(r, dict()) |
|
125 |
|
|
126 |
|
|
127 |
if __name__ == '__main__': |
|
128 |
from sys import argv |
|
129 |
from kamaki.clients.test import runTestCase |
|
130 |
runTestCase(Utils, 'clients.utils methods', argv[1:]) |
b/setup.py | ||
---|---|---|
63 | 63 |
'kamaki.cli', |
64 | 64 |
'kamaki.cli.commands', |
65 | 65 |
'kamaki.clients', |
66 |
'kamaki.clients.utils', |
|
66 | 67 |
'kamaki.clients.livetest', |
67 | 68 |
'kamaki.clients.image', |
68 | 69 |
'kamaki.clients.storage', |
Also available in: Unified diff