1# pylint: disable-msg=C0111
2#!/usr/bin/python
3#
4# Copyright 2008 Google Inc. All Rights Reserved.
5
6"""Test for atest."""
7
8import unittest, os, sys, urllib2
9
10import common
11from autotest_lib.cli import cli_mock, topic_common, rpc
12
13
14class topic_common_misc_tests(unittest.TestCase):
15    def test_get_item_key(self):
16        get_item_key = topic_common._get_item_key
17        self.assertRaises(ValueError, get_item_key, {}, '')
18        self.assertRaises(ValueError, get_item_key, {}, '.')
19        self.assertRaises(KeyError, get_item_key, {}, 'a')
20        self.assertRaises(KeyError, get_item_key, {}, 'a.')
21        self.assertRaises(ValueError, get_item_key, {'a': {}}, 'a.')
22        self.assertRaises(KeyError, get_item_key, {'a': {}}, 'a.b')
23        self.assertEquals(2, get_item_key({'a.b': 2, 'a': {}}, 'a.b'))
24        self.assertEquals(9, get_item_key({'a': {'b': 9}}, 'a.b'))
25        self.assertEquals(3, get_item_key({'a': {'b': {'c': 3}}}, 'a.b.c'))
26        self.assertEquals(5, get_item_key({'a': 5}, 'a'))
27        self.assertEquals({'b': 9}, get_item_key({'a': {'b': 9}}, 'a'))
28
29
30class item_parse_info_unittest(cli_mock.cli_unittest):
31    def __test_parsing_flist_bad(self, options):
32        parse_info = topic_common.item_parse_info
33        test_parse_info = parse_info(attribute_name='testing',
34                                     filename_option='flist')
35        self.assertRaises(topic_common.CliError,
36                          test_parse_info.get_values, options, [])
37
38
39    def __test_parsing_flist_good(self, options, expected):
40        parse_info = topic_common.item_parse_info
41        test_parse_info = parse_info(attribute_name='testing',
42                                     filename_option='flist')
43        result, leftover = test_parse_info.get_values(options, [])
44
45        self.assertEqualNoOrder(expected, result)
46        os.unlink(options.flist)
47
48
49    def __test_parsing_inline_good(self, options, expected):
50        parse_info = topic_common.item_parse_info
51        test_parse_info = parse_info(attribute_name='testing',
52                                     inline_option='inline')
53        result, leftover = test_parse_info.get_values(options, [])
54
55        self.assertEqualNoOrder(expected, result)
56
57
58    def __test_parsing_leftover_good(self, leftover, expected):
59        class opt(object):
60            pass
61        parse_info = topic_common.item_parse_info
62        test_parse_info = parse_info(attribute_name='testing',
63                                     inline_option='inline',
64                                     use_leftover=True)
65        result, leftover = test_parse_info.get_values(opt(), leftover)
66
67        self.assertEqualNoOrder(expected, result)
68
69
70    def __test_parsing_all_good(self, options, leftover, expected):
71        parse_info = topic_common.item_parse_info
72        test_parse_info = parse_info(attribute_name='testing',
73                                     inline_option='inline',
74                                     filename_option='flist',
75                                     use_leftover=True)
76        result, leftover = test_parse_info.get_values(options, leftover)
77
78        self.assertEqualNoOrder(expected, result)
79        os.unlink(options.flist)
80
81
82    def __test_parsing_all_bad(self, options, leftover):
83        parse_info = topic_common.item_parse_info
84        test_parse_info = parse_info(attribute_name='testing',
85                                     inline_option='inline',
86                                     filename_option='flist',
87                                     use_leftover=True)
88        self.assertRaises(topic_common.CliError,
89                          test_parse_info.get_values, options, leftover)
90
91
92    def test_file_list_wrong_file(self):
93        class opt(object):
94            flist = './does_not_exist'
95        self.__test_parsing_flist_bad(opt())
96
97
98    def test_file_list_empty_file(self):
99        class opt(object):
100            flist_obj = cli_mock.create_file('')
101            flist = flist_obj.name
102        self.__test_parsing_flist_bad(opt())
103
104
105    def test_file_list_ok(self):
106        class opt(object):
107            flist_obj = cli_mock.create_file('a\nb\nc\n')
108            flist = flist_obj.name
109        self.__test_parsing_flist_good(opt(), ['a', 'b', 'c'])
110
111
112    def test_file_list_one_line_space(self):
113        class opt(object):
114            flist_obj = cli_mock.create_file('a b c\nd e\nf\n')
115            flist = flist_obj.name
116        self.__test_parsing_flist_good(opt(), ['a', 'b', 'c', 'd', 'e', 'f'])
117
118
119    def test_file_list_one_line_comma(self):
120        class opt(object):
121            flist_obj = cli_mock.create_file('a,b,c\nd,e\nf\n')
122            flist = flist_obj.name
123        self.__test_parsing_flist_good(opt(), ['a', 'b', 'c', 'd', 'e', 'f'])
124
125
126    def test_file_list_one_line_mix(self):
127        class opt(object):
128            flist_obj = cli_mock.create_file('a,b c\nd,e\nf\ng h,i')
129            flist = flist_obj.name
130        self.__test_parsing_flist_good(opt(), ['a', 'b', 'c', 'd', 'e',
131                                         'f', 'g', 'h', 'i'])
132
133
134    def test_file_list_one_line_comma_space(self):
135        class opt(object):
136            flist_obj = cli_mock.create_file('a, b c\nd,e\nf\ng h,i')
137            flist = flist_obj.name
138        self.__test_parsing_flist_good(opt(), ['a', 'b', 'c', 'd', 'e',
139                                         'f', 'g', 'h', 'i'])
140
141
142    def test_file_list_line_end_comma_space(self):
143        class opt(object):
144            flist_obj = cli_mock.create_file('a, b c\nd,e, \nf,\ng h,i ,')
145            flist = flist_obj.name
146        self.__test_parsing_flist_good(opt(), ['a', 'b', 'c', 'd', 'e',
147                                         'f', 'g', 'h', 'i'])
148
149
150    def test_file_list_no_eof(self):
151        class opt(object):
152            flist_obj = cli_mock.create_file('a\nb\nc')
153            flist = flist_obj.name
154        self.__test_parsing_flist_good(opt(), ['a', 'b', 'c'])
155
156
157    def test_file_list_blank_line(self):
158        class opt(object):
159            flist_obj = cli_mock.create_file('\na\nb\n\nc\n')
160            flist = flist_obj.name
161        self.__test_parsing_flist_good(opt(), ['a', 'b', 'c'])
162
163
164    def test_file_list_escaped_commas(self):
165        class opt(object):
166            flist_obj = cli_mock.create_file('a\nb\\,c\\,d\nef\\,g')
167            flist = flist_obj.name
168        self.__test_parsing_flist_good(opt(), ['a', 'b,c,d', 'ef,g'])
169
170
171    def test_file_list_escaped_commas_slashes(self):
172        class opt(object):
173            flist_obj = cli_mock.create_file('a\nb\\\\\\,c\\,d\nef\\\\,g')
174            flist = flist_obj.name
175        self.__test_parsing_flist_good(opt(), ['a', 'b\\,c,d', 'ef\\', 'g'])
176
177
178    def test_file_list_opt_list_one(self):
179        class opt(object):
180            inline = 'a'
181        self.__test_parsing_inline_good(opt(), ['a'])
182
183
184    def test_file_list_opt_list_space(self):
185        class opt(object):
186            inline = 'a b c'
187        self.__test_parsing_inline_good(opt(), ['a', 'b', 'c'])
188
189
190    def test_file_list_opt_list_mix_space_comma(self):
191        class opt(object):
192            inline = 'a b,c,d e'
193        self.__test_parsing_inline_good(opt(), ['a', 'b', 'c', 'd', 'e'])
194
195
196    def test_file_list_opt_list_mix_comma_space(self):
197        class opt(object):
198            inline = 'a b,c, d e'
199        self.__test_parsing_inline_good(opt(), ['a', 'b', 'c', 'd', 'e'])
200
201
202    def test_file_list_opt_list_end_comma_space(self):
203        class opt(object):
204            inline = 'a b, ,c,, d e, '
205        self.__test_parsing_inline_good(opt(), ['a', 'b', 'c', 'd', 'e'])
206
207
208    def test_file_list_opt_list_escaped_commas(self):
209        class opt(object):
210            inline = 'a\\,b,c, d'
211        self.__test_parsing_inline_good(opt(), ['a,b', 'c', 'd'])
212
213
214    def test_file_list_opt_list_escaped_commas_slashes(self):
215        class opt(object):
216            inline = 'a\\,b\\\\\\,c,d,e'
217        self.__test_parsing_inline_good(opt(), ['a,b\\,c', 'd', 'e'])
218
219
220    def test_file_list_add_on_space(self):
221        self.__test_parsing_leftover_good(['a','c','b'],
222                                          ['a', 'b', 'c'])
223
224
225    def test_file_list_add_on_mix_space_comma(self):
226        self.__test_parsing_leftover_good(['a', 'c','b,d'],
227                                          ['a', 'b', 'c', 'd'])
228
229
230    def test_file_list_add_on_mix_comma_space(self):
231        self.__test_parsing_leftover_good(['a', 'c', 'b,', 'd'],
232                                          ['a', 'b', 'c', 'd'])
233
234
235    def test_file_list_add_on_end_comma_space(self):
236        self.__test_parsing_leftover_good(['a', 'c', 'b,', 'd,', ','],
237                                          ['a', 'b', 'c', 'd'])
238
239
240    def test_file_list_add_on_escaped_commas(self):
241        self.__test_parsing_leftover_good(['a', 'c', 'b,', 'd\\,e\\,f'],
242                                          ['a', 'b', 'c', 'd,e,f'])
243
244
245    def test_file_list_add_on_escaped_commas_slashes(self):
246        self.__test_parsing_leftover_good(['a', 'c', 'b,', 'd\\\\\\,e,f'],
247                                          ['a', 'b', 'c', 'd\\,e', 'f'])
248
249
250    def test_file_list_all_opt(self):
251        class opt(object):
252            flist_obj = cli_mock.create_file('f\ng\nh\n')
253            flist = flist_obj.name
254            inline = 'a b,c,d e'
255        self.__test_parsing_all_good(opt(), ['i', 'j'],
256                                     ['a', 'b', 'c', 'd', 'e',
257                                      'f', 'g', 'h', 'i', 'j'])
258
259
260    def test_file_list_all_opt_empty_file(self):
261        class opt(object):
262            flist_obj = cli_mock.create_file('')
263            flist = flist_obj.name
264            inline = 'a b,c,d e'
265        self.__test_parsing_all_bad(opt(), ['i', 'j'])
266
267
268    def test_file_list_all_opt_in_common(self):
269        class opt(object):
270            flist_obj = cli_mock.create_file('f\nc\na\n')
271            flist = flist_obj.name
272            inline = 'a b,c,d e'
273        self.__test_parsing_all_good(opt(), ['i','j,d'],
274                                     ['a', 'b', 'c', 'd', 'e', 'f', 'i', 'j'])
275
276
277    def test_file_list_all_opt_in_common_space(self):
278        class opt(object):
279            flist_obj = cli_mock.create_file('a b c\nd,e\nf\ng')
280            flist = flist_obj.name
281            inline = 'a b,c,d h'
282        self.__test_parsing_all_good(opt(), ['i','j,d'],
283                                     ['a', 'b', 'c', 'd', 'e',
284                                      'f', 'g', 'h', 'i', 'j'])
285
286
287    def test_file_list_all_opt_in_common_weird(self):
288        class opt(object):
289            flist_obj = cli_mock.create_file('a b c\nd,e\nf\ng, \n, ,,')
290            flist = flist_obj.name
291            inline = 'a b,c,d h, ,  ,,  '
292        self.__test_parsing_all_good(opt(), ['i','j,d'],
293                                     ['a', 'b', 'c', 'd', 'e',
294                                      'f', 'g', 'h', 'i', 'j'])
295
296
297    def test_file_list_all_opt_in_common_escaped_commas(self):
298        class opt(object):
299            flist_obj = cli_mock.create_file('a\\,b\\,c\nd,e\nf\ng')
300            flist = flist_obj.name
301            inline = 'a\\,b\\,c,d h'
302        self.__test_parsing_all_good(opt(), ['i','j,d'],
303                                     ['a,b,c', 'd', 'e', 'f', 'g', 'h',
304                                      'i', 'j'])
305
306
307    def test_file_list_all_opt_in_common_escaped_commas_slashes(self):
308        class opt(object):
309            flist_obj = cli_mock.create_file('a\\,b\\\\\\,c\nd,e\nf,ghi, ,, j,')
310            flist = flist_obj.name
311            inline = 'a\\,b\\\\\\,c,d h,ijk'
312        self.__test_parsing_all_good(opt(), ['i','j,d'],
313                                     ['a,b\\,c', 'd', 'e', 'f', 'ghi', 'h',
314                                      'i', 'j', 'ijk'])
315
316
317class atest_unittest(cli_mock.cli_unittest):
318    def setUp(self):
319        super(atest_unittest, self).setUp()
320        self.atest = topic_common.atest()
321        self.atest.afe = rpc.afe_comm()
322        if 'AUTOTEST_WEB' in os.environ:
323            del os.environ['AUTOTEST_WEB']
324
325
326    def tearDown(self):
327        self.atest = None
328        super(atest_unittest, self).tearDown()
329
330
331    def test_invalid_arg_kill(self):
332        self.atest.kill_on_failure = True
333        self.god.mock_io()
334        sys.exit.expect_call(1).and_raises(cli_mock.ExitException)
335        self.assertRaises(cli_mock.ExitException,
336                          self.atest.invalid_arg, 'This is bad')
337        (output, err) = self.god.unmock_io()
338        self.god.check_playback()
339        self.assert_(err.find('This is bad') >= 0)
340
341
342    def test_invalid_arg_continue(self):
343        self.god.mock_io()
344        self.atest.invalid_arg('This is sort of ok')
345        (output, err) = self.god.unmock_io()
346        self.assert_(err.find('This is sort of ok') >= 0)
347
348
349    def test_failure_continue(self):
350        self.atest.failure('This is partly bad', item='item0',
351                           what_failed='something important')
352        err = self.atest.failed['something important']
353        self.assert_('This is partly bad' in err.keys())
354
355
356    def test_failure_continue_multiple_different_errors(self):
357        self.atest.failure('This is partly bad', item='item0',
358                           what_failed='something important')
359        self.atest.failure('This is really bad', item='item0',
360                           what_failed='something really important')
361        err = self.atest.failed['something important']
362        self.assert_('This is partly bad' in err)
363        self.assert_('This is really bad' not in err)
364        err = self.atest.failed['something really important']
365        self.assert_('This is partly bad' not in err)
366        self.assert_('This is really bad' in err)
367
368
369    def test_failure_continue_multiple_same_errors(self):
370        self.atest.failure('This is partly bad', item='item0',
371                           what_failed='something important')
372        self.atest.failure('This is really bad', item='item1',
373                           what_failed='something important')
374        errs = self.atest.failed['something important']
375        self.assert_('This is partly bad' in errs)
376        self.assert_('This is really bad' in errs)
377        self.assert_(set(['item0']) in errs.values())
378        self.assert_(set(['item1']) in errs.values())
379
380
381    def test_failure_continue_multiple_errors_mixed(self):
382        self.atest.failure('This is partly bad', item='item0',
383                           what_failed='something important')
384        self.atest.failure('This is really bad', item='item0',
385                           what_failed='something really important')
386        self.atest.failure('This is really bad', item='item1',
387                           what_failed='something important')
388        errs = self.atest.failed['something important']
389        self.assert_('This is partly bad' in errs)
390        self.assert_('This is really bad' in errs)
391        self.assert_(set(['item0']) in errs.values())
392        self.assert_(set(['item1']) in errs.values())
393
394        errs = self.atest.failed['something really important']
395        self.assert_('This is really bad' in errs)
396        self.assert_('This is partly bad' not in errs)
397        self.assert_(set(['item0']) in errs.values())
398        self.assert_(set(['item1']) not in errs.values())
399
400
401    def test_failure_continue_multiple_errors_mixed_same_error(self):
402        self.atest.failure('This is partly bad', item='item0',
403                           what_failed='something important')
404        self.atest.failure('This is really bad', item='item0',
405                           what_failed='something really important')
406        self.atest.failure('This is partly bad', item='item1',
407                           what_failed='something important')
408        errs = self.atest.failed['something important']
409        self.assert_('This is partly bad' in errs)
410        self.assert_('This is really bad' not in errs)
411        self.assert_(set(['item0', 'item1']) in errs.values())
412
413        errs = self.atest.failed['something really important']
414        self.assert_('This is really bad' in errs)
415        self.assert_('This is partly bad' not in errs)
416        self.assert_(set(['item0']) in errs.values())
417        self.assert_(set(['item1']) not in errs.values())
418
419
420    def test_failure_exit(self):
421        self.atest.kill_on_failure = True
422        self.god.mock_io()
423        sys.exit.expect_call(1).and_raises(cli_mock.ExitException)
424        self.assertRaises(cli_mock.ExitException,
425                          self.atest.failure, 'This is partly bad')
426        (output, err) = self.god.unmock_io()
427        self.god.check_playback()
428        self.assert_(err.find('This is partly bad') >= 0)
429
430
431    def test_failure_exit_item(self):
432        self.atest.kill_on_failure = True
433        self.god.mock_io()
434        sys.exit.expect_call(1).and_raises(cli_mock.ExitException)
435        self.assertRaises(cli_mock.ExitException,
436                          self.atest.failure, 'This is partly bad',
437                          item='item0')
438        (output, err) = self.god.unmock_io()
439        self.god.check_playback()
440        self.assertWords(err, ['This is partly bad'], ['item0'])
441
442
443    def test_show_all_failures_common(self):
444        self.atest.failure('This is partly bad', item='item0',
445                           what_failed='something important')
446        self.atest.failure('This is partly bad', item='item1',
447                           what_failed='something important')
448        self.god.mock_io()
449        self.atest.show_all_failures()
450        (output, err) = self.god.unmock_io()
451        self.assertWords(err, ['something important',
452                               'This is partly bad', 'item0', 'item1'])
453
454
455    def test_parse_add_on(self):
456        flist = cli_mock.create_file('host1\nhost2\nleft2')
457        sys.argv = ['atest', '--web', 'fooweb', '--parse',
458                    '--kill-on-failure', 'left1', 'left2', '-M', flist.name]
459        self.atest.parser.add_option('-M', '--mlist', type='string')
460        item_info = topic_common.item_parse_info(attribute_name='hosts',
461                                                 filename_option='mlist',
462                                                 use_leftover=True)
463        (options, leftover) = self.atest.parse([item_info])
464        self.assertEqualNoOrder(self.atest.hosts,
465                                ['left1', 'left2', 'host1', 'host2'])
466
467        self.assertEqual({'mlist': flist.name,
468                          'web_server': 'fooweb',
469                          'parse': True,
470                          'parse_delim': '|',
471                          'kill_on_failure': True,
472                          'verbose': False,
473                          'no_confirmation': False,
474                          'debug': False,
475                          'log_level':'ERROR'}, options)
476        self.assertEqual(leftover, [])
477        flist.clean()
478
479
480    def test_parse_no_add_on(self):
481        flist = cli_mock.create_file('host1\nhost2\nleft2')
482        sys.argv = ['atest', '--web', 'fooweb', '--parse', '-g',
483                    '--kill-on-failure', 'left1', 'left2', '-M', flist.name]
484        self.atest.parser.add_option('-M', '--mlist', type='string')
485        item_info = topic_common.item_parse_info(attribute_name='hosts',
486                                                 filename_option='mlist')
487        (options, leftover) = self.atest.parse([item_info])
488        self.assertEqualNoOrder(self.atest.hosts,
489                                ['left2', 'host1', 'host2'])
490
491        self.assertEqual({'mlist': flist.name,
492                          'web_server': 'fooweb',
493                          'parse': True,
494                          'parse_delim': '|',
495                          'kill_on_failure': True,
496                          'verbose': False,
497                          'no_confirmation': False,
498                          'debug': True,
499                          'log_level':'ERROR'}, options)
500        self.assertEqual(leftover, ['left1', 'left2'])
501        flist.clean()
502
503
504    def test_parse_add_on_first(self):
505        flist = cli_mock.create_file('host1\nhost2\nleft2')
506        ulist = cli_mock.create_file('user1\nuser2\nuser3\n')
507        sys.argv = ['atest', '-g', '--parse', '--ulist', ulist.name,
508                    '-u', 'myuser,youruser',
509                    '--kill-on-failure', 'left1', 'left2', '-M', flist.name]
510        self.atest.parser.add_option('-M', '--mlist', type='string')
511        self.atest.parser.add_option('-U', '--ulist', type='string')
512        self.atest.parser.add_option('-u', '--user', type='string')
513        host_info = topic_common.item_parse_info(attribute_name='hosts',
514                                                 filename_option='mlist',
515                                                 use_leftover=True)
516        user_info = topic_common.item_parse_info(attribute_name='users',
517                                                 inline_option='user',
518                                                 filename_option='ulist')
519
520        (options, leftover) = self.atest.parse([host_info, user_info])
521        self.assertEqualNoOrder(self.atest.hosts,
522                                ['left1', 'left2', 'host1', 'host2'])
523        self.assertEqualNoOrder(self.atest.users,
524                                ['user1', 'user2', 'user3',
525                                 'myuser', 'youruser'])
526
527        self.assertEqual({'mlist': flist.name,
528                          'ulist': ulist.name,
529                          'user': 'myuser,youruser',
530                          'web_server': None,
531                          'parse': True,
532                          'parse_delim': '|',
533                          'kill_on_failure': True,
534                          'verbose': False,
535                          'no_confirmation': False,
536                          'debug': True,
537                          'log_level':'ERROR'}, options)
538        self.assertEqual(leftover, [])
539        flist.clean()
540        ulist.clean()
541
542
543    def test_parse_add_on_second(self):
544        flist = cli_mock.create_file('host1\nhost2\nleft2')
545        ulist = cli_mock.create_file('user1\nuser2\nuser3\n')
546        sys.argv = ['atest', '-g', '--parse', '-U', ulist.name,
547                    '-u', 'myuser,youruser',
548                    '--kill-on-failure', 'left1', 'left2', '-M', flist.name]
549        self.atest.parser.add_option('-M', '--mlist', type='string')
550        self.atest.parser.add_option('-U', '--ulist', type='string')
551        self.atest.parser.add_option('-u', '--user', type='string')
552        host_info = topic_common.item_parse_info(attribute_name='hosts',
553                                                 filename_option='mlist',
554                                                 use_leftover=True)
555        user_info = topic_common.item_parse_info(attribute_name='users',
556                                                 inline_option='user',
557                                                 filename_option='ulist')
558        (options, leftover) = self.atest.parse([host_info, user_info])
559
560        self.assertEqualNoOrder(self.atest.hosts,
561                                ['left1', 'left2', 'host1', 'host2'])
562        self.assertEqualNoOrder(self.atest.users,
563                                ['user1', 'user2', 'user3',
564                                 'myuser', 'youruser'])
565
566        self.assertEqual({'mlist': flist.name,
567                          'ulist': ulist.name,
568                          'user': 'myuser,youruser',
569                          'web_server': None,
570                          'parse': True,
571                          'parse_delim': '|',
572                          'kill_on_failure': True,
573                          'verbose': False,
574                          'no_confirmation': False,
575                          'debug': True,
576                          'log_level':'ERROR'}, options)
577        self.assertEqual(leftover, [])
578        flist.clean()
579        ulist.clean()
580
581
582    def test_parse_all_opts(self):
583        flist = cli_mock.create_file('host1\nhost2\nleft2')
584        ulist = cli_mock.create_file('user1\nuser2\nuser3\n')
585        sys.argv = ['atest', '-g', '--parse', '--ulist', ulist.name,
586                    '-u', 'myuser,youruser',
587                    '--kill-on-failure', '-M', flist.name, 'left1', 'left2']
588        self.atest.parser.add_option('-M', '--mlist', type='string')
589        self.atest.parser.add_option('-U', '--ulist', type='string')
590        self.atest.parser.add_option('-u', '--user', type='string')
591        host_info = topic_common.item_parse_info(attribute_name='hosts',
592                                                 filename_option='mlist',
593                                                 use_leftover=True)
594        user_info = topic_common.item_parse_info(attribute_name='users',
595                                                 inline_option='user',
596                                                 filename_option='ulist')
597        (options, leftover) = self.atest.parse([host_info, user_info])
598        self.assertEqualNoOrder(self.atest.hosts,
599                                ['left1', 'left2', 'host1', 'host2'])
600        self.assertEqualNoOrder(self.atest.users,
601                                ['user1', 'user2', 'user3',
602                                 'myuser', 'youruser'])
603
604        self.assertEqual({'mlist': flist.name,
605                          'ulist': ulist.name,
606                          'user': 'myuser,youruser',
607                          'web_server': None,
608                          'parse': True,
609                          'parse_delim': '|',
610                          'kill_on_failure': True,
611                          'verbose': False,
612                          'no_confirmation': False,
613                          'debug': True,
614                          'log_level':'ERROR'}, options)
615        self.assertEqual(leftover, [])
616        flist.clean()
617        ulist.clean()
618
619
620    def test_parse_no_add_on_2(self):
621        flist = cli_mock.create_file('host1\nhost2\nleft2')
622        ulist = cli_mock.create_file('user1\nuser2\nuser3\n')
623        sys.argv = ['atest', '-U', ulist.name,
624                    '--kill-on-failure', '-M', flist.name]
625        self.atest.parser.add_option('-M', '--mlist', type='string')
626        self.atest.parser.add_option('-U', '--ulist', type='string')
627        self.atest.parser.add_option('-u', '--user', type='string')
628        host_info = topic_common.item_parse_info(attribute_name='hosts',
629                                                 filename_option='mlist',
630                                                 use_leftover=True)
631        user_info = topic_common.item_parse_info(attribute_name='users',
632                                                 inline_option='user',
633                                                 filename_option='ulist')
634        (options, leftover) = self.atest.parse([host_info, user_info])
635        self.assertEqualNoOrder(self.atest.hosts,
636                                ['left2', 'host1', 'host2'])
637        self.assertEqualNoOrder(self.atest.users,
638                                ['user1', 'user2', 'user3'])
639
640        self.assertEqual({'mlist': flist.name,
641                          'ulist': ulist.name,
642                          'user': None,
643                          'web_server': None,
644                          'parse': False,
645                          'parse_delim': '|',
646                          'kill_on_failure': True,
647                          'verbose': False,
648                          'no_confirmation': False,
649                          'debug': False,
650                          'log_level':'ERROR'}, options)
651        self.assertEqual(leftover, [])
652        flist.clean()
653        ulist.clean()
654
655
656    def test_parse_no_flist_add_on(self):
657        sys.argv = ['atest', '-g', '--parse', '-u', 'myuser,youruser',
658                    '--kill-on-failure', 'left1', 'left2']
659        self.atest.parser.add_option('-M', '--mlist', type='string')
660        self.atest.parser.add_option('-U', '--ulist', type='string')
661        self.atest.parser.add_option('-u', '--user', type='string')
662        host_info = topic_common.item_parse_info(attribute_name='hosts',
663                                                 use_leftover=True)
664        user_info = topic_common.item_parse_info(attribute_name='users',
665                                                 inline_option='user')
666        (options, leftover) = self.atest.parse([host_info, user_info])
667        self.assertEqualNoOrder(self.atest.hosts,
668                                ['left1', 'left2'])
669        self.assertEqualNoOrder(self.atest.users,
670                                ['myuser', 'youruser'])
671
672        self.assertEqual({'mlist': None,
673                          'ulist': None,
674                          'user': 'myuser,youruser',
675                          'web_server': None,
676                          'parse': True,
677                          'parse_delim': '|',
678                          'kill_on_failure': True,
679                          'verbose': False,
680                          'no_confirmation': False,
681                          'debug': True,
682                          'log_level':'ERROR'}, options)
683        self.assertEqual(leftover, [])
684
685
686    def test_parse_no_flist_no_add_on(self):
687        sys.argv = ['atest', '-u', 'myuser,youruser', '--kill-on-failure',
688                    '-a', 'acl1,acl2']
689        self.atest.parser.add_option('-u', '--user', type='string')
690        self.atest.parser.add_option('-a', '--acl', type='string')
691        acl_info = topic_common.item_parse_info(attribute_name='acls',
692                                                inline_option='acl')
693        user_info = topic_common.item_parse_info(attribute_name='users',
694                                                 inline_option='user')
695        (options, leftover) = self.atest.parse([user_info, acl_info])
696        self.assertEqualNoOrder(self.atest.acls,
697                                ['acl1', 'acl2'])
698        self.assertEqualNoOrder(self.atest.users,
699                                ['myuser', 'youruser'])
700
701        self.assertEqual({'user': 'myuser,youruser',
702                          'acl': 'acl1,acl2',
703                          'web_server': None,
704                          'parse': False,
705                          'parse_delim': '|',
706                          'kill_on_failure': True,
707                          'verbose': False,
708                          'no_confirmation': False,
709                          'debug': False,
710                          'log_level':'ERROR'}, options)
711        self.assertEqual(leftover, [])
712
713
714    def test_parse_req_items_ok(self):
715        sys.argv = ['atest', '-u', 'myuser,youruser']
716        self.atest.parser.add_option('-u', '--user', type='string')
717        user_info = topic_common.item_parse_info(attribute_name='users',
718                                                 inline_option='user')
719        (options, leftover) = self.atest.parse([user_info],
720                                               req_items='users')
721        self.assertEqualNoOrder(self.atest.users,
722                                ['myuser', 'youruser'])
723
724        self.assertEqual({'user': 'myuser,youruser',
725                          'web_server': None,
726                          'parse': False,
727                          'parse_delim': '|',
728                          'kill_on_failure': False,
729                          'verbose': False,
730                          'no_confirmation': False,
731                          'debug': False,
732                          'log_level':'ERROR'}, options)
733        self.assertEqual(leftover, [])
734
735
736    def test_parse_req_items_missing(self):
737        sys.argv = ['atest', '-u', 'myuser,youruser', '--kill-on-failure']
738        self.atest.parser.add_option('-u', '--user', type='string')
739        acl_info = topic_common.item_parse_info(attribute_name='acls',
740                                                inline_option='acl')
741        user_info = topic_common.item_parse_info(attribute_name='users',
742                                                 inline_option='user')
743        self.god.mock_io()
744        sys.exit.expect_call(1).and_raises(cli_mock.ExitException)
745        self.assertRaises(cli_mock.ExitException,
746                          self.atest.parse,
747                          [user_info, acl_info],
748                          'acls')
749        self.assertEqualNoOrder(self.atest.users,
750                                ['myuser', 'youruser'])
751
752        self.assertEqualNoOrder(self.atest.acls, [])
753        self.god.check_playback()
754        self.god.unmock_io()
755
756
757    def test_parse_bad_option(self):
758        sys.argv = ['atest', '--unknown']
759        self.god.stub_function(self.atest.parser, 'error')
760        self.atest.parser.error.expect_call('no such option: --unknown').and_return(None)
761        self.atest.parse()
762        self.god.check_playback()
763
764
765    def test_parse_all_set(self):
766        sys.argv = ['atest', '--web', 'fooweb', '--parse', '--debug',
767                    '--kill-on-failure', '--verbose', 'left1', 'left2',
768                    '--parse-delim', '?']
769        (options, leftover) = self.atest.parse()
770        self.assertEqual({'web_server': 'fooweb',
771                          'parse': True,
772                          'parse_delim': '?',
773                          'kill_on_failure': True,
774                          'verbose': True,
775                          'no_confirmation': False,
776                          'debug': True,
777                          'log_level':'ERROR'}, options)
778        self.assertEqual(leftover, ['left1', 'left2'])
779
780
781    def test_execute_rpc_bad_server(self):
782        self.atest.afe = rpc.afe_comm('http://does_not_exist')
783        self.god.mock_io()
784        rpc.afe_comm.run.expect_call('myop').and_raises(urllib2.URLError("<urlopen error (-2, 'Name or service not known')>"))
785        sys.exit.expect_call(1).and_raises(cli_mock.ExitException)
786        self.assertRaises(cli_mock.ExitException,
787                          self.atest.execute_rpc, 'myop')
788        (output, err) = self.god.unmock_io()
789        self.god.check_playback()
790        self.assert_(err.find('http://does_not_exist') >= 0)
791
792
793    #
794    # Print Unit tests
795    #
796    def __test_print_fields(self, func, expected, **dargs):
797        if not dargs.has_key('items'):
798            dargs['items']=[{'hostname': 'h0',
799                            'platform': 'p0',
800                            'labels': [u'l0', u'l1'],
801                            'locked': 1,
802                            'id': 'id0',
803                            'name': 'name0'},
804                           {'hostname': 'h1',
805                            'platform': 'p1',
806                            'labels': [u'l2', u'l3'],
807                            'locked': 0,
808                            'id': 'id1',
809                            'name': 'name1'}]
810        self.god.mock_io()
811        func(**dargs)
812        (output, err) = self.god.unmock_io()
813        self.assertEqual(expected, output)
814
815
816    #
817    # Print fields Standard
818    #
819    def __test_print_fields_std(self, keys, expected):
820        self.__test_print_fields(self.atest.print_fields_std,
821                                 expected, keys=keys)
822
823
824    def test_print_fields_std_one_str(self):
825        self.__test_print_fields_std(['hostname'],
826                                     'Host: h0\n'
827                                     'Host: h1\n')
828
829
830    def test_print_fields_std_conv_bool(self):
831        """Make sure the conversion functions are called"""
832        self.__test_print_fields_std(['locked'],
833                                     'Locked: True\n'
834                                     'Locked: False\n')
835
836
837    def test_print_fields_std_conv_label(self):
838        """Make sure the conversion functions are called"""
839        self.__test_print_fields_std(['labels'],
840                                     'Labels: l0, l1\n'
841                                     'Labels: l2, l3\n')
842
843
844    def test_print_fields_std_all_fields(self):
845        """Make sure the conversion functions are called"""
846        self.__test_print_fields_std(['hostname', 'platform','locked'],
847                                     'Host: h0\n'
848                                     'Platform: p0\n'
849                                     'Locked: True\n'
850                                     'Host: h1\n'
851                                     'Platform: p1\n'
852                                     'Locked: False\n')
853
854
855    #
856    # Print fields parse
857    #
858    def __test_print_fields_parse(self, keys, expected):
859        self.__test_print_fields(self.atest.print_fields_parse,
860                                 expected, keys=keys)
861
862
863    def test_print_fields_parse_one_str(self):
864        self.__test_print_fields_parse(['hostname'],
865                                       'Host=h0\n'
866                                       'Host=h1\n')
867
868
869    def test_print_fields_parse_conv_bool(self):
870        self.__test_print_fields_parse(['locked'],
871                                       'Locked=True\n'
872                                       'Locked=False\n')
873
874
875    def test_print_fields_parse_conv_label(self):
876        self.__test_print_fields_parse(['labels'],
877                                       'Labels=l0, l1\n'
878                                       'Labels=l2, l3\n')
879
880
881    def test_print_fields_parse_all_fields(self):
882        self.__test_print_fields_parse(['hostname', 'platform', 'locked'],
883                                       'Host=h0|Platform=p0|'
884                                       'Locked=True\n'
885                                       'Host=h1|Platform=p1|'
886                                       'Locked=False\n')
887
888
889    #
890    # Print table standard
891    #
892    def __test_print_table_std(self, keys, expected):
893        self.__test_print_fields(self.atest.print_table_std,
894                                 expected, keys_header=keys)
895
896
897    def test_print_table_std_all_fields(self):
898        self.__test_print_table_std(['hostname', 'platform','locked'],
899                                    'Host  Platform  Locked\n'
900                                    'h0    p0        True\n'
901                                    'h1    p1        False\n')
902
903    # TODO JME - add long fields tests
904
905
906    #
907    # Print table parse
908    #
909    def __test_print_table_parse(self, keys, expected):
910        self.__test_print_fields(self.atest.print_table_parse,
911                                 expected, keys_header=keys)
912
913
914    def test_print_table_parse_all_fields(self):
915        self.__test_print_table_parse(['hostname', 'platform',
916                                       'locked'],
917                                      'Host=h0|Platform=p0|Locked=True\n'
918                                      'Host=h1|Platform=p1|Locked=False\n')
919
920
921    def test_print_table_parse_all_fields_2(self):
922        self.atest.parse_delim = '?'
923        self.__test_print_table_parse(['hostname', 'platform',
924                                       'locked'],
925                                      'Host=h0?Platform=p0?Locked=True\n'
926                                      'Host=h1?Platform=p1?Locked=False\n')
927
928
929    def test_print_table_parse_empty_fields(self):
930        self.__test_print_fields(self.atest.print_table_parse,
931                                 'Host=h0|Platform=p0\n'
932                                 'Host=h1|Platform=p1|Labels=l2, l3\n',
933                                 items=[{'hostname': 'h0',
934                                         'platform': 'p0',
935                                         'labels': [],
936                                         'locked': 1,
937                                         'id': 'id0',
938                                         'name': 'name0'},
939                                        {'hostname': 'h1',
940                                         'platform': 'p1',
941                                         'labels': [u'l2', u'l3'],
942                                         'locked': 0,
943                                         'id': 'id1',
944                                         'name': 'name1'}],
945                                 keys_header=['hostname', 'platform',
946                                              'labels'])
947
948
949    #
950    # Print mix table standard
951    #
952    def __test_print_mix_table_std(self, keys_header, sublist_keys,
953                                   expected):
954        self.__test_print_fields(self.atest.print_table_std,
955                                 expected,
956                                 keys_header=keys_header,
957                                 sublist_keys=sublist_keys)
958
959
960    def test_print_mix_table(self):
961        self.__test_print_mix_table_std(['name', 'hostname'], [],
962                                        'Name   Host\n'
963                                        'name0  h0\n'
964                                        'name1  h1\n')
965
966
967    def test_print_mix_table_sublist(self):
968        self.__test_print_mix_table_std(['name', 'hostname'], ['labels'],
969                                        'Name   Host\n'
970                                        'name0  h0\n'
971                                        'Labels: \n'
972                                        '\tl0, l1\n\n\n'
973                                        'name1  h1\n'
974                                        'Labels: \n'
975                                        '\tl2, l3\n\n\n')
976
977
978    #
979    # Print by ID standard
980    #
981    def __test_print_by_ids_std(self, expected):
982        self.__test_print_fields(self.atest.print_by_ids_std,
983                                 expected)
984
985
986    def test_print_by_ids_std_all_fields(self):
987        self.__test_print_by_ids_std('Id   Name\n'
988                                     'id0  name0\n'
989                                     'id1  name1\n')
990
991
992    #
993    # Print by ID parse
994    #
995    def __test_print_by_ids_parse(self, expected):
996        self.__test_print_fields(self.atest.print_by_ids_parse,
997                                 expected)
998
999
1000    def test_print_by_ids_parse_all_fields(self):
1001        self.__test_print_by_ids_parse('Id=id0|Name=name0|'
1002                                       'Id=id1|Name=name1\n')
1003
1004
1005if __name__ == '__main__':
1006    unittest.main()
1007