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}, options)
475        self.assertEqual(leftover, [])
476        flist.clean()
477
478
479    def test_parse_no_add_on(self):
480        flist = cli_mock.create_file('host1\nhost2\nleft2')
481        sys.argv = ['atest', '--web', 'fooweb', '--parse', '-g',
482                    '--kill-on-failure', 'left1', 'left2', '-M', flist.name]
483        self.atest.parser.add_option('-M', '--mlist', type='string')
484        item_info = topic_common.item_parse_info(attribute_name='hosts',
485                                                 filename_option='mlist')
486        (options, leftover) = self.atest.parse([item_info])
487        self.assertEqualNoOrder(self.atest.hosts,
488                                ['left2', 'host1', 'host2'])
489
490        self.assertEqual({'mlist': flist.name,
491                          'web_server': 'fooweb',
492                          'parse': True,
493                          'parse_delim': '|',
494                          'kill_on_failure': True,
495                          'verbose': False,
496                          'no_confirmation': False,
497                          'debug': True}, options)
498        self.assertEqual(leftover, ['left1', 'left2'])
499        flist.clean()
500
501
502    def test_parse_add_on_first(self):
503        flist = cli_mock.create_file('host1\nhost2\nleft2')
504        ulist = cli_mock.create_file('user1\nuser2\nuser3\n')
505        sys.argv = ['atest', '-g', '--parse', '--ulist', ulist.name,
506                    '-u', 'myuser,youruser',
507                    '--kill-on-failure', 'left1', 'left2', '-M', flist.name]
508        self.atest.parser.add_option('-M', '--mlist', type='string')
509        self.atest.parser.add_option('-U', '--ulist', type='string')
510        self.atest.parser.add_option('-u', '--user', type='string')
511        host_info = topic_common.item_parse_info(attribute_name='hosts',
512                                                 filename_option='mlist',
513                                                 use_leftover=True)
514        user_info = topic_common.item_parse_info(attribute_name='users',
515                                                 inline_option='user',
516                                                 filename_option='ulist')
517
518        (options, leftover) = self.atest.parse([host_info, user_info])
519        self.assertEqualNoOrder(self.atest.hosts,
520                                ['left1', 'left2', 'host1', 'host2'])
521        self.assertEqualNoOrder(self.atest.users,
522                                ['user1', 'user2', 'user3',
523                                 'myuser', 'youruser'])
524
525        self.assertEqual({'mlist': flist.name,
526                          'ulist': ulist.name,
527                          'user': 'myuser,youruser',
528                          'web_server': None,
529                          'parse': True,
530                          'parse_delim': '|',
531                          'kill_on_failure': True,
532                          'verbose': False,
533                          'no_confirmation': False,
534                          'debug': True}, options)
535        self.assertEqual(leftover, [])
536        flist.clean()
537        ulist.clean()
538
539
540    def test_parse_add_on_second(self):
541        flist = cli_mock.create_file('host1\nhost2\nleft2')
542        ulist = cli_mock.create_file('user1\nuser2\nuser3\n')
543        sys.argv = ['atest', '-g', '--parse', '-U', ulist.name,
544                    '-u', 'myuser,youruser',
545                    '--kill-on-failure', 'left1', 'left2', '-M', flist.name]
546        self.atest.parser.add_option('-M', '--mlist', type='string')
547        self.atest.parser.add_option('-U', '--ulist', type='string')
548        self.atest.parser.add_option('-u', '--user', type='string')
549        host_info = topic_common.item_parse_info(attribute_name='hosts',
550                                                 filename_option='mlist',
551                                                 use_leftover=True)
552        user_info = topic_common.item_parse_info(attribute_name='users',
553                                                 inline_option='user',
554                                                 filename_option='ulist')
555        (options, leftover) = self.atest.parse([host_info, user_info])
556
557        self.assertEqualNoOrder(self.atest.hosts,
558                                ['left1', 'left2', 'host1', 'host2'])
559        self.assertEqualNoOrder(self.atest.users,
560                                ['user1', 'user2', 'user3',
561                                 'myuser', 'youruser'])
562
563        self.assertEqual({'mlist': flist.name,
564                          'ulist': ulist.name,
565                          'user': 'myuser,youruser',
566                          'web_server': None,
567                          'parse': True,
568                          'parse_delim': '|',
569                          'kill_on_failure': True,
570                          'verbose': False,
571                          'no_confirmation': False,
572                          'debug': True}, options)
573        self.assertEqual(leftover, [])
574        flist.clean()
575        ulist.clean()
576
577
578    def test_parse_all_opts(self):
579        flist = cli_mock.create_file('host1\nhost2\nleft2')
580        ulist = cli_mock.create_file('user1\nuser2\nuser3\n')
581        sys.argv = ['atest', '-g', '--parse', '--ulist', ulist.name,
582                    '-u', 'myuser,youruser',
583                    '--kill-on-failure', '-M', flist.name, 'left1', 'left2']
584        self.atest.parser.add_option('-M', '--mlist', type='string')
585        self.atest.parser.add_option('-U', '--ulist', type='string')
586        self.atest.parser.add_option('-u', '--user', type='string')
587        host_info = topic_common.item_parse_info(attribute_name='hosts',
588                                                 filename_option='mlist',
589                                                 use_leftover=True)
590        user_info = topic_common.item_parse_info(attribute_name='users',
591                                                 inline_option='user',
592                                                 filename_option='ulist')
593        (options, leftover) = self.atest.parse([host_info, user_info])
594        self.assertEqualNoOrder(self.atest.hosts,
595                                ['left1', 'left2', 'host1', 'host2'])
596        self.assertEqualNoOrder(self.atest.users,
597                                ['user1', 'user2', 'user3',
598                                 'myuser', 'youruser'])
599
600        self.assertEqual({'mlist': flist.name,
601                          'ulist': ulist.name,
602                          'user': 'myuser,youruser',
603                          'web_server': None,
604                          'parse': True,
605                          'parse_delim': '|',
606                          'kill_on_failure': True,
607                          'verbose': False,
608                          'no_confirmation': False,
609                          'debug': True}, options)
610        self.assertEqual(leftover, [])
611        flist.clean()
612        ulist.clean()
613
614
615    def test_parse_no_add_on_2(self):
616        flist = cli_mock.create_file('host1\nhost2\nleft2')
617        ulist = cli_mock.create_file('user1\nuser2\nuser3\n')
618        sys.argv = ['atest', '-U', ulist.name,
619                    '--kill-on-failure', '-M', flist.name]
620        self.atest.parser.add_option('-M', '--mlist', type='string')
621        self.atest.parser.add_option('-U', '--ulist', type='string')
622        self.atest.parser.add_option('-u', '--user', type='string')
623        host_info = topic_common.item_parse_info(attribute_name='hosts',
624                                                 filename_option='mlist',
625                                                 use_leftover=True)
626        user_info = topic_common.item_parse_info(attribute_name='users',
627                                                 inline_option='user',
628                                                 filename_option='ulist')
629        (options, leftover) = self.atest.parse([host_info, user_info])
630        self.assertEqualNoOrder(self.atest.hosts,
631                                ['left2', 'host1', 'host2'])
632        self.assertEqualNoOrder(self.atest.users,
633                                ['user1', 'user2', 'user3'])
634
635        self.assertEqual({'mlist': flist.name,
636                          'ulist': ulist.name,
637                          'user': None,
638                          'web_server': None,
639                          'parse': False,
640                          'parse_delim': '|',
641                          'kill_on_failure': True,
642                          'verbose': False,
643                          'no_confirmation': False,
644                          'debug': False}, options)
645        self.assertEqual(leftover, [])
646        flist.clean()
647        ulist.clean()
648
649
650    def test_parse_no_flist_add_on(self):
651        sys.argv = ['atest', '-g', '--parse', '-u', 'myuser,youruser',
652                    '--kill-on-failure', 'left1', 'left2']
653        self.atest.parser.add_option('-M', '--mlist', type='string')
654        self.atest.parser.add_option('-U', '--ulist', type='string')
655        self.atest.parser.add_option('-u', '--user', type='string')
656        host_info = topic_common.item_parse_info(attribute_name='hosts',
657                                                 use_leftover=True)
658        user_info = topic_common.item_parse_info(attribute_name='users',
659                                                 inline_option='user')
660        (options, leftover) = self.atest.parse([host_info, user_info])
661        self.assertEqualNoOrder(self.atest.hosts,
662                                ['left1', 'left2'])
663        self.assertEqualNoOrder(self.atest.users,
664                                ['myuser', 'youruser'])
665
666        self.assertEqual({'mlist': None,
667                          'ulist': None,
668                          'user': 'myuser,youruser',
669                          'web_server': None,
670                          'parse': True,
671                          'parse_delim': '|',
672                          'kill_on_failure': True,
673                          'verbose': False,
674                          'no_confirmation': False,
675                          'debug': True}, options)
676        self.assertEqual(leftover, [])
677
678
679    def test_parse_no_flist_no_add_on(self):
680        sys.argv = ['atest', '-u', 'myuser,youruser', '--kill-on-failure',
681                    '-a', 'acl1,acl2']
682        self.atest.parser.add_option('-u', '--user', type='string')
683        self.atest.parser.add_option('-a', '--acl', type='string')
684        acl_info = topic_common.item_parse_info(attribute_name='acls',
685                                                inline_option='acl')
686        user_info = topic_common.item_parse_info(attribute_name='users',
687                                                 inline_option='user')
688        (options, leftover) = self.atest.parse([user_info, acl_info])
689        self.assertEqualNoOrder(self.atest.acls,
690                                ['acl1', 'acl2'])
691        self.assertEqualNoOrder(self.atest.users,
692                                ['myuser', 'youruser'])
693
694        self.assertEqual({'user': 'myuser,youruser',
695                          'acl': 'acl1,acl2',
696                          'web_server': None,
697                          'parse': False,
698                          'parse_delim': '|',
699                          'kill_on_failure': True,
700                          'verbose': False,
701                          'no_confirmation': False,
702                          'debug': False}, options)
703        self.assertEqual(leftover, [])
704
705
706    def test_parse_req_items_ok(self):
707        sys.argv = ['atest', '-u', 'myuser,youruser']
708        self.atest.parser.add_option('-u', '--user', type='string')
709        user_info = topic_common.item_parse_info(attribute_name='users',
710                                                 inline_option='user')
711        (options, leftover) = self.atest.parse([user_info],
712                                               req_items='users')
713        self.assertEqualNoOrder(self.atest.users,
714                                ['myuser', 'youruser'])
715
716        self.assertEqual({'user': 'myuser,youruser',
717                          'web_server': None,
718                          'parse': False,
719                          'parse_delim': '|',
720                          'kill_on_failure': False,
721                          'verbose': False,
722                          'no_confirmation': False,
723                          'debug': False}, options)
724        self.assertEqual(leftover, [])
725
726
727    def test_parse_req_items_missing(self):
728        sys.argv = ['atest', '-u', 'myuser,youruser', '--kill-on-failure']
729        self.atest.parser.add_option('-u', '--user', type='string')
730        acl_info = topic_common.item_parse_info(attribute_name='acls',
731                                                inline_option='acl')
732        user_info = topic_common.item_parse_info(attribute_name='users',
733                                                 inline_option='user')
734        self.god.mock_io()
735        sys.exit.expect_call(1).and_raises(cli_mock.ExitException)
736        self.assertRaises(cli_mock.ExitException,
737                          self.atest.parse,
738                          [user_info, acl_info],
739                          'acls')
740        self.assertEqualNoOrder(self.atest.users,
741                                ['myuser', 'youruser'])
742
743        self.assertEqualNoOrder(self.atest.acls, [])
744        self.god.check_playback()
745        self.god.unmock_io()
746
747
748    def test_parse_bad_option(self):
749        sys.argv = ['atest', '--unknown']
750        self.god.stub_function(self.atest.parser, 'error')
751        self.atest.parser.error.expect_call('no such option: --unknown').and_return(None)
752        self.atest.parse()
753        self.god.check_playback()
754
755
756    def test_parse_all_set(self):
757        sys.argv = ['atest', '--web', 'fooweb', '--parse', '--debug',
758                    '--kill-on-failure', '--verbose', 'left1', 'left2',
759                    '--parse-delim', '?']
760        (options, leftover) = self.atest.parse()
761        self.assertEqual({'web_server': 'fooweb',
762                          'parse': True,
763                          'parse_delim': '?',
764                          'kill_on_failure': True,
765                          'verbose': True,
766                          'no_confirmation': False,
767                          'debug': True}, options)
768        self.assertEqual(leftover, ['left1', 'left2'])
769
770
771    def test_execute_rpc_bad_server(self):
772        self.atest.afe = rpc.afe_comm('http://does_not_exist')
773        self.god.mock_io()
774        rpc.afe_comm.run.expect_call('myop').and_raises(urllib2.URLError("<urlopen error (-2, 'Name or service not known')>"))
775        sys.exit.expect_call(1).and_raises(cli_mock.ExitException)
776        self.assertRaises(cli_mock.ExitException,
777                          self.atest.execute_rpc, 'myop')
778        (output, err) = self.god.unmock_io()
779        self.god.check_playback()
780        self.assert_(err.find('http://does_not_exist') >= 0)
781
782
783    #
784    # Print Unit tests
785    #
786    def __test_print_fields(self, func, expected, **dargs):
787        if not dargs.has_key('items'):
788            dargs['items']=[{'hostname': 'h0',
789                            'platform': 'p0',
790                            'labels': [u'l0', u'l1'],
791                            'locked': 1,
792                            'id': 'id0',
793                            'name': 'name0'},
794                           {'hostname': 'h1',
795                            'platform': 'p1',
796                            'labels': [u'l2', u'l3'],
797                            'locked': 0,
798                            'id': 'id1',
799                            'name': 'name1'}]
800        self.god.mock_io()
801        func(**dargs)
802        (output, err) = self.god.unmock_io()
803        self.assertEqual(expected, output)
804
805
806    #
807    # Print fields Standard
808    #
809    def __test_print_fields_std(self, keys, expected):
810        self.__test_print_fields(self.atest.print_fields_std,
811                                 expected, keys=keys)
812
813
814    def test_print_fields_std_one_str(self):
815        self.__test_print_fields_std(['hostname'],
816                                     'Host: h0\n'
817                                     'Host: h1\n')
818
819
820    def test_print_fields_std_conv_bool(self):
821        """Make sure the conversion functions are called"""
822        self.__test_print_fields_std(['locked'],
823                                     'Locked: True\n'
824                                     'Locked: False\n')
825
826
827    def test_print_fields_std_conv_label(self):
828        """Make sure the conversion functions are called"""
829        self.__test_print_fields_std(['labels'],
830                                     'Labels: l0, l1\n'
831                                     'Labels: l2, l3\n')
832
833
834    def test_print_fields_std_all_fields(self):
835        """Make sure the conversion functions are called"""
836        self.__test_print_fields_std(['hostname', 'platform','locked'],
837                                     'Host: h0\n'
838                                     'Platform: p0\n'
839                                     'Locked: True\n'
840                                     'Host: h1\n'
841                                     'Platform: p1\n'
842                                     'Locked: False\n')
843
844
845    #
846    # Print fields parse
847    #
848    def __test_print_fields_parse(self, keys, expected):
849        self.__test_print_fields(self.atest.print_fields_parse,
850                                 expected, keys=keys)
851
852
853    def test_print_fields_parse_one_str(self):
854        self.__test_print_fields_parse(['hostname'],
855                                       'Host=h0\n'
856                                       'Host=h1\n')
857
858
859    def test_print_fields_parse_conv_bool(self):
860        self.__test_print_fields_parse(['locked'],
861                                       'Locked=True\n'
862                                       'Locked=False\n')
863
864
865    def test_print_fields_parse_conv_label(self):
866        self.__test_print_fields_parse(['labels'],
867                                       'Labels=l0, l1\n'
868                                       'Labels=l2, l3\n')
869
870
871    def test_print_fields_parse_all_fields(self):
872        self.__test_print_fields_parse(['hostname', 'platform', 'locked'],
873                                       'Host=h0|Platform=p0|'
874                                       'Locked=True\n'
875                                       'Host=h1|Platform=p1|'
876                                       'Locked=False\n')
877
878
879    #
880    # Print table standard
881    #
882    def __test_print_table_std(self, keys, expected):
883        self.__test_print_fields(self.atest.print_table_std,
884                                 expected, keys_header=keys)
885
886
887    def test_print_table_std_all_fields(self):
888        self.__test_print_table_std(['hostname', 'platform','locked'],
889                                    'Host  Platform  Locked\n'
890                                    'h0    p0        True\n'
891                                    'h1    p1        False\n')
892
893    # TODO JME - add long fields tests
894
895
896    #
897    # Print table parse
898    #
899    def __test_print_table_parse(self, keys, expected):
900        self.__test_print_fields(self.atest.print_table_parse,
901                                 expected, keys_header=keys)
902
903
904    def test_print_table_parse_all_fields(self):
905        self.__test_print_table_parse(['hostname', 'platform',
906                                       'locked'],
907                                      'Host=h0|Platform=p0|Locked=True\n'
908                                      'Host=h1|Platform=p1|Locked=False\n')
909
910
911    def test_print_table_parse_all_fields_2(self):
912        self.atest.parse_delim = '?'
913        self.__test_print_table_parse(['hostname', 'platform',
914                                       'locked'],
915                                      'Host=h0?Platform=p0?Locked=True\n'
916                                      'Host=h1?Platform=p1?Locked=False\n')
917
918
919    def test_print_table_parse_empty_fields(self):
920        self.__test_print_fields(self.atest.print_table_parse,
921                                 'Host=h0|Platform=p0\n'
922                                 'Host=h1|Platform=p1|Labels=l2, l3\n',
923                                 items=[{'hostname': 'h0',
924                                         'platform': 'p0',
925                                         'labels': [],
926                                         'locked': 1,
927                                         'id': 'id0',
928                                         'name': 'name0'},
929                                        {'hostname': 'h1',
930                                         'platform': 'p1',
931                                         'labels': [u'l2', u'l3'],
932                                         'locked': 0,
933                                         'id': 'id1',
934                                         'name': 'name1'}],
935                                 keys_header=['hostname', 'platform',
936                                              'labels'])
937
938
939    #
940    # Print mix table standard
941    #
942    def __test_print_mix_table_std(self, keys_header, sublist_keys,
943                                   expected):
944        self.__test_print_fields(self.atest.print_table_std,
945                                 expected,
946                                 keys_header=keys_header,
947                                 sublist_keys=sublist_keys)
948
949
950    def test_print_mix_table(self):
951        self.__test_print_mix_table_std(['name', 'hostname'], [],
952                                        'Name   Host\n'
953                                        'name0  h0\n'
954                                        'name1  h1\n')
955
956
957    def test_print_mix_table_sublist(self):
958        self.__test_print_mix_table_std(['name', 'hostname'], ['labels'],
959                                        'Name   Host\n'
960                                        'name0  h0\n'
961                                        'Labels: \n'
962                                        '\tl0, l1\n\n\n'
963                                        'name1  h1\n'
964                                        'Labels: \n'
965                                        '\tl2, l3\n\n\n')
966
967
968    #
969    # Print by ID standard
970    #
971    def __test_print_by_ids_std(self, expected):
972        self.__test_print_fields(self.atest.print_by_ids_std,
973                                 expected)
974
975
976    def test_print_by_ids_std_all_fields(self):
977        self.__test_print_by_ids_std('Id   Name\n'
978                                     'id0  name0\n'
979                                     'id1  name1\n')
980
981
982    #
983    # Print by ID parse
984    #
985    def __test_print_by_ids_parse(self, expected):
986        self.__test_print_fields(self.atest.print_by_ids_parse,
987                                 expected)
988
989
990    def test_print_by_ids_parse_all_fields(self):
991        self.__test_print_by_ids_parse('Id=id0|Name=name0|'
992                                       'Id=id1|Name=name1\n')
993
994
995if __name__ == '__main__':
996    unittest.main()
997