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