Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / argument / test.py @ c0fbf04c

History | View | Annotate | Download (15.2 kB)

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, MagicMock
35
from unittest import TestCase
36
from StringIO import StringIO
37
from datetime import datetime
38
#from itertools import product
39

    
40
from kamaki.cli import argument, errors
41
from kamaki.cli.config import Config
42

    
43

    
44
def assert_dicts_are_equal(test_case, d1, d2):
45
    for k, v in d1.items():
46
        test_case.assertTrue(k in d2)
47
        if isinstance(v, dict):
48
            test_case.assert_dicts_are_equal(v, d2[k])
49
        else:
50
            test_case.assertEqual(unicode(v), unicode(d2[k]))
51

    
52

    
53
cnf_path = 'kamaki.cli.config.Config'
54

    
55

    
56
class Argument(TestCase):
57

    
58
    def test___init__(self):
59
        self.assertRaises(ValueError, argument.Argument, 'non-integer')
60
        self.assertRaises(AssertionError, argument.Argument, 1)
61
        self.assertRaises(AssertionError, argument.Argument, 0, 'noname')
62
        self.assertRaises(AssertionError, argument.Argument, 0, '--no name')
63
        self.assertRaises(AssertionError, argument.Argument, 0, ['-n', 'n m'])
64
        for arity, help, parsed_name, default in (
65
                (0, 'help 0', '--zero', None),
66
                (1, 'help 1', ['--one', '-o'], 'lala'),
67
                (-1, 'help -1', ['--help', '--or', '--more'], 0),
68
                (0, 'help 0 again', ['--again', ], True)):
69
            a = argument.Argument(arity, help, parsed_name, default)
70
            if arity:
71
                self.assertEqual(arity, a.arity)
72
            self.assertEqual(help, a.help)
73

    
74
            exp_name = parsed_name if (
75
                isinstance(parsed_name, list)) else [parsed_name, ]
76
            self.assertEqual(exp_name, a.parsed_name)
77

    
78
            exp_default = default or (None if arity else False)
79
            self.assertEqual(exp_default, a.default)
80

    
81
    def test_value(self):
82
        a = argument.Argument(1, parsed_name='--value')
83
        for value in (None, '', 0, 0.1, -12, [1, 'a', 2.8], (3, 'lala'), 'pi'):
84
            a.value = value
85
            self.assertEqual(value, a.value)
86

    
87
    def test_update_parser(self):
88
        for i, arity in enumerate((-1, 0, 1)):
89
            arp = argument.ArgumentParser()
90
            pname, aname = '--pname%s' % i, 'a_name_%s' % i
91
            a = argument.Argument(arity, 'args', pname, 42)
92
            a.update_parser(arp, aname)
93

    
94
            f = StringIO()
95
            arp.print_usage(file=f), f.seek(0)
96
            usage, exp = f.readline(), '[%s%s]\n' % (
97
                pname, (' %s' % aname.upper()) if arity else '')
98
            self.assertEqual(usage[-len(exp):], exp)
99
            del arp
100

    
101

    
102
class ConfigArgument(TestCase):
103

    
104
    def setUp(self):
105
        argument._config_arg = argument.ConfigArgument('Recovered Path')
106

    
107
    def test_value(self):
108
        c = argument._config_arg
109
        self.assertEqual(c.value, None)
110
        exp = '/some/random/path'
111
        c.value = exp
112
        self.assertTrue(isinstance(c.value, Config))
113
        self.assertEqual(c.file_path, exp)
114
        self.assertEqual(c.value.path, exp)
115

    
116
    def test_get(self):
117
        c = argument._config_arg
118
        c.value = None
119
        with patch('%s.get' % cnf_path, return_value='config') as get:
120
            self.assertEqual(c.value.get('global', 'config_cli'), 'config')
121
            self.assertEqual(get.mock_calls[-1], call('global', 'config_cli'))
122

    
123
    @patch('%s.keys' % cnf_path, return_value=(
124
        'image_cli', 'config_cli', 'history_cli', 'file'))
125
    def test_groups(self, keys):
126
        c = argument._config_arg
127
        c.value = None
128
        cset = set(c.groups)
129
        self.assertTrue(cset.issuperset(['image', 'config', 'history']))
130
        self.assertEqual(keys.mock_calls[-1], call('global'))
131
        self.assertFalse('file' in cset)
132
        self.assertEqual(keys.mock_calls[-1], call('global'))
133

    
134
    @patch('%s.items' % cnf_path, return_value=(
135
        ('image_cli', 'image'), ('file', 'pithos'),
136
        ('config_cli', 'config'), ('history_cli', 'history')))
137
    def test_cli_specs(self, items):
138
        c = argument._config_arg
139
        c.value = None
140
        cset = set(c.cli_specs)
141
        self.assertTrue(cset.issuperset([
142
            ('image', 'image'), ('config', 'config'), ('history', 'history')]))
143
        self.assertEqual(items.mock_calls[-1], call('global'))
144
        self.assertFalse(cset.issuperset([('file', 'pithos'), ]))
145
        self.assertEqual(items.mock_calls[-1], call('global'))
146

    
147
    def test_get_global(self):
148
        c = argument._config_arg
149
        c.value = None
150
        for k, v in (
151
                ('config_cli', 'config'),
152
                ('image_cli', 'image'),
153
                ('history_cli', 'history')):
154
            with patch('%s.get_global' % cnf_path, return_value=v) as gg:
155
                self.assertEqual(c.get_global(k), v)
156
                self.assertEqual(gg.mock_calls[-1], call(k))
157

    
158
    def test_get_cloud(self):
159
        c = argument._config_arg
160
        c.value = None
161
        with patch(
162
                '%s.get_cloud' % cnf_path,
163
                return_value='http://cloud') as get_cloud:
164
            self.assertTrue(len(c.get_cloud('mycloud', 'url')) > 0)
165
            self.assertEqual(get_cloud.mock_calls[-1],  call('mycloud', 'url'))
166
        with patch(
167
                '%s.get_cloud' % cnf_path,
168
                side_effect=KeyError('no token')) as get_cloud:
169
            self.assertRaises(KeyError, c.get_cloud, 'mycloud', 'token')
170
        invalidcloud = 'PLEASE_DO_NOT_EVER_NAME_YOUR_CLOUD_LIKE_THIS111'
171
        self.assertRaises(KeyError, c.get_cloud, invalidcloud, 'url')
172

    
173

    
174
class RuntimeConfigArgument(TestCase):
175

    
176
    def setUp(self):
177
        argument._config_arg = argument.ConfigArgument('Recovered Path')
178

    
179
    @patch('kamaki.cli.argument.Argument.__init__')
180
    def test___init__(self, arg):
181
        config, help, pname, default = 'config', 'help', 'pname', 'default'
182
        rca = argument.RuntimeConfigArgument(config, help, pname, default)
183
        self.assertTrue(isinstance(rca, argument.RuntimeConfigArgument))
184
        self.assertEqual(rca._config_arg, config)
185
        self.assertEqual(arg.mock_calls[-1], call(1, help, pname, default))
186

    
187
    @patch('%s.override' % cnf_path)
188
    def test_value(self, override):
189
        config, help, pname, default = argument._config_arg, 'help', '-n', 'df'
190
        config.value = None
191
        rca = argument.RuntimeConfigArgument(config, help, pname, default)
192
        self.assertEqual(rca.value, default)
193

    
194
        for options in ('grp', 'grp.opt', 'k v', '=nokey', 2.8, None, 42, ''):
195
            self.assertRaises(TypeError, rca.value, options)
196

    
197
        for options in ('key=val', 'grp.key=val', 'dotted.opt.key=val'):
198
            rca.value = options
199
            option, sep, val = options.partition('=')
200
            grp, sep, key = option.partition('.')
201
            grp, key = (grp, key) if key else ('global', grp)
202
            self.assertEqual(override.mock_calls[-1], call(grp, key, val))
203

    
204

    
205
class FlagArgument(TestCase):
206

    
207
    @patch('kamaki.cli.argument.Argument.__init__')
208
    def test___init__(self, arg):
209
        help, pname, default = 'help', 'pname', 'default'
210
        fa = argument.FlagArgument(help, pname, default)
211
        self.assertTrue(isinstance(fa, argument.FlagArgument))
212
        arg.assert_called_once(0, help, pname, default)
213

    
214

    
215
class ValueArgument(TestCase):
216

    
217
    @patch('kamaki.cli.argument.Argument.__init__')
218
    def test___init__(self, arg):
219
        help, pname, default = 'help', 'pname', 'default'
220
        fa = argument.ValueArgument(help, pname, default)
221
        self.assertTrue(isinstance(fa, argument.ValueArgument))
222
        arg.assert_called_once(1, help, pname, default)
223

    
224

    
225
class IntArgument(TestCase):
226

    
227
    def test_value(self):
228
        ia = argument.IntArgument(parsed_name='--ia')
229
        self.assertEqual(ia.value, None)
230
        for v in (1, 0, -1, 923455555555555555555555555555555):
231
            ia.value = v
232
            self.assertEqual(ia.value, v)
233
        for v in ('1', '-1', 2.8):
234
            ia.value = v
235
            self.assertEqual(ia.value, int(v))
236
        for v, err in (
237
                ('invalid', errors.CLIError),
238
                (None, TypeError), (False, TypeError), ([1, 2, 3], TypeError)):
239
            try:
240
                ia.value = v
241
            except Exception as e:
242
                self.assertTrue(isinstance(e, err))
243

    
244

    
245
class DateArgument(TestCase):
246

    
247
    def test_timestamp(self):
248
        da = argument.DateArgument(parsed_name='--date')
249
        self.assertEqual(da.timestamp, None)
250
        date, format, exp = '24-10-1917', '%d-%m-%Y', -1646964000.0
251
        da._value = argument.dtm.strptime(date, format)
252
        self.assertEqual(da.timestamp, exp)
253

    
254
    def test_formated(self):
255
        da = argument.DateArgument(parsed_name='--date')
256
        self.assertEqual(da.formated, None)
257
        date, format, exp = (
258
            '24-10-1917', '%d-%m-%Y', 'Wed Oct 24 00:00:00 1917')
259
        da._value = argument.dtm.strptime(date, format)
260
        self.assertEqual(da.formated, exp)
261

    
262
    @patch('kamaki.cli.argument.DateArgument.timestamp')
263
    @patch('kamaki.cli.argument.DateArgument.format_date')
264
    def test_value(self, format_date, timestamp):
265
        da = argument.DateArgument(parsed_name='--date')
266
        self.assertTrue(isinstance(da.value, MagicMock))
267
        da.value = 'Something'
268
        format_date.assert_called_once(call('Something'))
269

    
270
    def test_format_date(self):
271
        da = argument.DateArgument(parsed_name='--date')
272
        for datestr, exp in (
273
                ('Wed Oct 24 01:02:03 1917', datetime(1917, 10, 24, 1, 2, 3)),
274
                ('24-10-1917', datetime(1917, 10, 24)),
275
                ('01:02:03 24-10-1917', datetime(1917, 10, 24, 1, 2, 3))):
276
            self.assertEqual(da.format_date(datestr), exp)
277
        for datestr, err in (
278
                ('32-40-20134', errors.CLIError),
279
                ('Wednesday, 24 Oct 2017', errors.CLIError),
280
                (None, TypeError), (0.8, TypeError)):
281
            self.assertRaises(err, da.format_date, datestr)
282

    
283

    
284
class VersionArgument(TestCase):
285

    
286
    def test_value(self):
287
        va = argument.VersionArgument(parsed_name='--version')
288
        self.assertTrue(va, argument.VersionArgument)
289
        va.value = 'some value'
290
        self.assertEqual(va.value, 'some value')
291

    
292

    
293
class KeyValueArgument(TestCase):
294

    
295
    @patch('kamaki.cli.argument.Argument.__init__')
296
    def test___init__(self, init):
297
        help, pname, default = 'help', 'pname', 'default'
298
        kva = argument.KeyValueArgument(help, pname, default)
299
        self.assertTrue(isinstance(kva, argument.KeyValueArgument))
300
        self.assertEqual(init.mock_calls[-1], call(-1, help, pname, default))
301

    
302
    def test_value(self):
303
        kva = argument.KeyValueArgument(parsed_name='--keyval')
304
        self.assertEqual(kva.value, None)
305
        for kvpairs in (
306
                'strval', 'key=val', 2.8, 42, None,
307
                ('key', 'val'), ('key val'), ['=val', 'key=val'],
308
                ['key1=val1', 'key2 val2'], ('key1 = val1', )):
309
            self.assertRaises(errors.CLIError, kva.value, kvpairs)
310
        for kvpairs, exp in (
311
                (('key=val', ), {'key': 'val'}),
312
                (['key1=val1', 'key2=val2'], {'key1': 'val1', 'key2': 'val2'}),
313
                (
314
                    ('k1=v1 v2', 'k3=', 'k 4=v4'),
315
                    {'k1': 'v1 v2', 'k3': '', 'k 4': 'v4'}),
316
                (('k=v1', 'k=v2', 'k=v3'), {'k': 'v3'})
317
            ):
318
            kva.value = kvpairs
319
            assert_dicts_are_equal(self, kva.value, exp)
320

    
321

    
322
class ProgressBarArgument(TestCase):
323

    
324
    class PseudoBar(object):
325
            message = ''
326
            suffix = ''
327

    
328
            def start():
329
                pass
330

    
331
    @patch('kamaki.cli.argument.FlagArgument.__init__')
332
    def test___init__(self, init):
333
        help, pname, default = 'help', '--progress', 'default'
334
        pba = argument.ProgressBarArgument(help, pname, default)
335
        self.assertTrue(isinstance(pba, argument.ProgressBarArgument))
336
        self.assertEqual(pba.suffix, '%(percent)d%%')
337
        init.assert_called_once(help, pname, default)
338

    
339
    def test_clone(self):
340
        pba = argument.ProgressBarArgument(parsed_name='--progress')
341
        pba.value = None
342
        pba_clone = pba.clone()
343
        self.assertTrue(isinstance(pba, argument.ProgressBarArgument))
344
        self.assertTrue(isinstance(pba_clone, argument.ProgressBarArgument))
345
        self.assertNotEqual(pba, pba_clone)
346
        self.assertEqual(pba.parsed_name, pba_clone.parsed_name)
347

    
348
    def test_get_generator(self):
349
        pba = argument.ProgressBarArgument(parsed_name='--progress')
350
        pba.value = None
351
        msg, msg_len = 'message', 40
352
        with patch('kamaki.cli.argument.KamakiProgressBar.start') as start:
353
            pba.get_generator(msg, msg_len)
354
            self.assertTrue(isinstance(pba.bar, argument.KamakiProgressBar))
355
            self.assertNotEqual(pba.bar.message, msg)
356
            self.assertEqual(
357
                pba.bar.message, '%s%s' % (msg, ' ' * (msg_len - len(msg))))
358
            self.assertEqual(pba.bar.suffix, '%(percent)d%% - %(eta)ds')
359
            start.assert_called_once()
360

    
361
    def test_finish(self):
362
        pba = argument.ProgressBarArgument(parsed_name='--progress')
363
        pba.value = None
364
        self.assertEqual(pba.finish(), None)
365
        pba.bar = argument.KamakiProgressBar()
366
        with patch('kamaki.cli.argument.KamakiProgressBar.finish') as finish:
367
            pba.finish()
368
            finish.assert_called_once()
369

    
370

    
371
if __name__ == '__main__':
372
    from sys import argv
373
    from kamaki.cli.test import runTestCase
374
    runTestCase(Argument, 'Argument', argv[1:])
375
    runTestCase(ConfigArgument, 'ConfigArgument', argv[1:])
376
    runTestCase(RuntimeConfigArgument, 'RuntimeConfigArgument', argv[1:])
377
    runTestCase(FlagArgument, 'FlagArgument', argv[1:])
378
    runTestCase(FlagArgument, 'ValueArgument', argv[1:])
379
    runTestCase(IntArgument, 'IntArgument', argv[1:])
380
    runTestCase(DateArgument, 'DateArgument', argv[1:])
381
    runTestCase(VersionArgument, 'VersionArgument', argv[1:])
382
    runTestCase(KeyValueArgument, 'KeyValueArgument', argv[1:])
383
    runTestCase(ProgressBarArgument, 'ProgressBarArgument', argv[1:])