bindctl_test.py 21.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Copyright (C) 2009  Internet Systems Consortium.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.


import unittest
18
import isc.cc.data
19
import os
20
import io
21
22
import sys
import socket
23
import http.client
24
25
import pwd
import getpass
26
from optparse import OptionParser
27
28
from isc.config.config_data import ConfigData, MultiConfigData
from isc.config.module_spec import ModuleSpec
29
from isc.testutils.parse_args import TestOptParser, OptsError
30
from bindctl_main import set_bindctl_options
31
32
33
from bindctl import cmdparse
from bindctl import bindcmd
from bindctl.moduleinfo import *
34
from bindctl.exception import *
35
36
37
38
39
40
try:
    from collections import OrderedDict
except ImportError:
    from mycollections import OrderedDict

class TestCmdLex(unittest.TestCase):
41

42
    def my_assert_raise(self, exception_type, cmd_line):
Jelte Jansen's avatar
Jelte Jansen committed
43
        self.assertRaises(exception_type, cmdparse.BindCmdParser, cmd_line)
44
45
46


    def testCommandWithoutParameter(self):
Jelte Jansen's avatar
Jelte Jansen committed
47
48
49
50
        cmd_parser = cmdparse.BindCmdParser("zone add")
        assert cmd_parser.module == "zone"
        assert cmd_parser.command == "add"
        self.assertEqual(len(cmd_parser.params), 0)
51
52


53
54
55
56
    def testCommandWithParameters(self):
        lines = {"zone add zone_name = cnnic.cn, file = cnnic.cn.file master=1.1.1.1",
                 "zone add zone_name = \"cnnic.cn\", file ='cnnic.cn.file' master=1.1.1.1  ",
                 "zone add zone_name = 'cnnic.cn\", file ='cnnic.cn.file' master=1.1.1.1, " }
57

58
        for cmd_line in lines:
Jelte Jansen's avatar
Jelte Jansen committed
59
60
61
62
63
64
            cmd_parser = cmdparse.BindCmdParser(cmd_line)
            assert cmd_parser.module == "zone"
            assert cmd_parser.command == "add"
            assert cmd_parser.params["zone_name"] == "cnnic.cn"
            assert cmd_parser.params["file"] == "cnnic.cn.file"
            assert cmd_parser.params["master"] == '1.1.1.1'
65
66
67

    def testCommandWithParamters_2(self):
        '''Test whether the parameters in key=value can be parsed properly.'''
Jelte Jansen's avatar
Jelte Jansen committed
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
        cmd_parser = cmdparse.BindCmdParser('zone cmd name = 1:34::2')
        self.assertEqual(cmd_parser.params['name'], '1:34::2')

        cmd_parser = cmdparse.BindCmdParser('zone cmd name = 1\"\'34**&2'
                                            ' value=44\"\'\"')
        self.assertEqual(cmd_parser.params['name'], '1\"\'34**&2')
        self.assertEqual(cmd_parser.params['value'], '44\"\'\"')

        cmd_parser = cmdparse.BindCmdParser('zone cmd name = 1\"\'34**&2'
                                            ',value=  44\"\'\"')
        self.assertEqual(cmd_parser.params['name'], '1\"\'34**&2')
        self.assertEqual(cmd_parser.params['value'], '44\"\'\"')

        cmd_parser = cmdparse.BindCmdParser('zone cmd name =  1\'34**&2'
                                            'value=44\"\'\" value = '
                                            '\"==============\'')
        self.assertEqual(cmd_parser.params['name'], '1\'34**&2value=44\"\'\"')
        self.assertEqual(cmd_parser.params['value'], '==============')

        cmd_parser = cmdparse.BindCmdParser('zone cmd name =    \"1234, '
                                            '567890 \" value ==&*/')
        self.assertEqual(cmd_parser.params['name'], '1234, 567890 ')
        self.assertEqual(cmd_parser.params['value'], '=&*/')
91

92
    def testCommandWithListParam(self):
Jelte Jansen's avatar
Jelte Jansen committed
93
94
95
        cmd_parser = cmdparse.BindCmdParser("zone set zone_name='cnnic.cn', "
                                            "master='1.1.1.1, 2.2.2.2'")
        assert cmd_parser.params["master"] == '1.1.1.1, 2.2.2.2'
96

97
    def testCommandWithHelpParam(self):
Jelte Jansen's avatar
Jelte Jansen committed
98
99
        cmd_parser = cmdparse.BindCmdParser("zone add help")
        assert cmd_parser.params["help"] == "help"
100

Jelte Jansen's avatar
Jelte Jansen committed
101
102
103
        cmd_parser = cmdparse.BindCmdParser("zone add help *&)&)*&&$#$^%")
        assert cmd_parser.params["help"] == "help"
        self.assertEqual(len(cmd_parser.params), 1)
104

105
106
107

    def testCmdModuleNameFormatError(self):
        self.my_assert_raise(CmdModuleNameFormatError, "zone=good")
108
109
        self.my_assert_raise(CmdModuleNameFormatError, "zo/ne")
        self.my_assert_raise(CmdModuleNameFormatError, "")
110
        self.my_assert_raise(CmdModuleNameFormatError, "=zone")
111
112
113
        self.my_assert_raise(CmdModuleNameFormatError, "zone,")


114
115
116
117
    def testCmdMissCommandNameFormatError(self):
        self.my_assert_raise(CmdMissCommandNameFormatError, "zone")
        self.my_assert_raise(CmdMissCommandNameFormatError, "zone ")
        self.my_assert_raise(CmdMissCommandNameFormatError, "help ")
118
119


120
121
122
123
124
125
126
127
    def testCmdCommandNameFormatError(self):
        self.my_assert_raise(CmdCommandNameFormatError, "zone =d")
        self.my_assert_raise(CmdCommandNameFormatError, "zone z=d")
        self.my_assert_raise(CmdCommandNameFormatError, "zone z-d ")
        self.my_assert_raise(CmdCommandNameFormatError, "zone zdd/")
        self.my_assert_raise(CmdCommandNameFormatError, "zone zdd/ \"")

class TestCmdSyntax(unittest.TestCase):
128

129
130
    def _create_bindcmd(self):
        """Create one bindcmd"""
131
132

        tool = bindcmd.BindCmdInterpreter()
133
134
135
136
137
138
        string_spec = { 'item_type' : 'string',
                       'item_optional' : False,
                       'item_default' : ''}
        int_spec = { 'item_type' : 'integer',
                       'item_optional' : False,
                       'item_default' : 10}
Jelte Jansen's avatar
Jelte Jansen committed
139
140
        zone_file_param = ParamInfo(name = "zone_file",
                                    param_spec = string_spec)
141
        zone_name = ParamInfo(name = 'zone_name', param_spec = string_spec)
142
143
        load_cmd = CommandInfo(name = "load")
        load_cmd.add_param(zone_file_param)
144
        load_cmd.add_param(zone_name)
145

Jelte Jansen's avatar
Jelte Jansen committed
146
147
148
149
150
151
152
        param_master = ParamInfo(name = "master", optional = True,
                                 param_spec = string_spec)
        param_master = ParamInfo(name = "port", optional = True,
                                 param_spec = int_spec)
        param_allow_update = ParamInfo(name = "allow_update",
                                       optional = True,
                                       param_spec = string_spec)
153
154
155
        set_cmd = CommandInfo(name = "set")
        set_cmd.add_param(param_master)
        set_cmd.add_param(param_allow_update)
156
        set_cmd.add_param(zone_name)
157
158
159
160

        reload_all_cmd = CommandInfo(name = "reload_all")

        zone_module = ModuleInfo(name = "zone")
161
162
163
        zone_module.add_command(load_cmd)
        zone_module.add_command(set_cmd)
        zone_module.add_command(reload_all_cmd)
164

165
166
        tool.add_module_info(zone_module)
        return tool
167
168


169
170
    def setUp(self):
        self.bindcmd = self._create_bindcmd()
171
172


173
    def no_assert_raise(self, cmd_line):
Jelte Jansen's avatar
Jelte Jansen committed
174
175
        cmd_parser = cmdparse.BindCmdParser(cmd_line)
        self.bindcmd._validate_cmd(cmd_parser)
176
177


178
    def my_assert_raise(self, exception_type, cmd_line):
Jelte Jansen's avatar
Jelte Jansen committed
179
180
181
        cmd_parser = cmdparse.BindCmdParser(cmd_line)
        self.assertRaises(exception_type, self.bindcmd._validate_cmd,
                          cmd_parser)
182
183


184
185
186
187
188
189
190
191
    def testValidateSuccess(self):
        self.no_assert_raise("zone load zone_file='cn' zone_name='cn'")
        self.no_assert_raise("zone load zone_file='cn', zone_name='cn', ")
        self.no_assert_raise("zone help ")
        self.no_assert_raise("zone load help ")
        self.no_assert_raise("zone help help='dd' ")
        self.no_assert_raise("zone set allow_update='1.1.1.1' zone_name='cn'")
        self.no_assert_raise("zone set zone_name='cn'")
Jelte Jansen's avatar
Jelte Jansen committed
192
193
        self.my_assert_raise(isc.cc.data.DataTypeError,
                             "zone set zone_name ='cn', port='cn'")
194
195
        self.no_assert_raise("zone reload_all")

196
197
198
    def testCmdUnknownModuleSyntaxError(self):
        self.my_assert_raise(CmdUnknownModuleSyntaxError, "zoned d")
        self.my_assert_raise(CmdUnknownModuleSyntaxError, "dd dd  ")
199

200
201
    def testCmdUnknownCmdSyntaxError(self):
        self.my_assert_raise(CmdUnknownCmdSyntaxError, "zone dd")
202

203
    def testCmdMissParamSyntaxError(self):
Jelte Jansen's avatar
Jelte Jansen committed
204
205
206
207
208
209
210
211
        self.my_assert_raise(CmdMissParamSyntaxError,
                             "zone load zone_file='cn'")
        self.my_assert_raise(CmdMissParamSyntaxError,
                             "zone load zone_name='cn'")
        self.my_assert_raise(CmdMissParamSyntaxError,
                             "zone set allow_update='1.1.1.1'")
        self.my_assert_raise(CmdMissParamSyntaxError,
                             "zone set ")
212

213
    def testCmdUnknownParamSyntaxError(self):
Jelte Jansen's avatar
Jelte Jansen committed
214
215
216
217
218
219
        self.my_assert_raise(CmdUnknownParamSyntaxError,
                             "zone load zone_d='cn'")
        self.my_assert_raise(CmdUnknownParamSyntaxError,
                             "zone reload_all zone_name = 'cn'")
        self.my_assert_raise(CmdUnknownParamSyntaxError,
                             "zone help a b c")
220

221
222
223
224
225
226
227
228
229
230
231
232
233
class TestModuleInfo(unittest.TestCase):

    def test_get_param_name_by_position(self):
        cmd = CommandInfo('command')
        cmd.add_param(ParamInfo('name'))
        cmd.add_param(ParamInfo('age'))
        cmd.add_param(ParamInfo('data', optional = True))
        cmd.add_param(ParamInfo('sex'))
        self.assertEqual('name', cmd.get_param_name_by_position(0, 2))
        self.assertEqual('age', cmd.get_param_name_by_position(1, 2))
        self.assertEqual('sex', cmd.get_param_name_by_position(2, 3))
        self.assertEqual('data', cmd.get_param_name_by_position(2, 4))
        self.assertEqual('data', cmd.get_param_name_by_position(2, 4))
234

235
236
237
        self.assertRaises(KeyError, cmd.get_param_name_by_position, 4, 4)


238

239
240
241
242
class TestNameSequence(unittest.TestCase):
    """
    Test if the module/command/parameters is saved in the order creation
    """
243

244
    def _create_bindcmd(self):
245
246
        """Create one bindcmd"""

247
248
        self._cmd = CommandInfo(name = "load")
        self.module = ModuleInfo(name = "zone")
249
        self.tool = bindcmd.BindCmdInterpreter()
250
251
252
        for random_str in self.random_names:
            self._cmd.add_param(ParamInfo(name = random_str))
            self.module.add_command(CommandInfo(name = random_str))
253
254
            self.tool.add_module_info(ModuleInfo(name = random_str))

255
    def setUp(self):
Jelte Jansen's avatar
Jelte Jansen committed
256
257
        self.random_names = ['1erdfeDDWsd', '3fe', '2009erd',
                             'Fe231', 'tere142', 'rei8WD']
258
        self._create_bindcmd()
259
260

    def testSequence(self):
261
262
263
        param_names = self._cmd.get_param_names()
        cmd_names = self.module.get_command_names()
        module_names = self.tool.get_module_names()
264

265
266
267
268
269
270
        i = 0
        while i < len(self.random_names):
            assert self.random_names[i] == param_names[i+1]
            assert self.random_names[i] == cmd_names[i+1]
            assert self.random_names[i] == module_names[i+1]
            i = i + 1
271

272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# tine class to fake a UIModuleCCSession, but only the config data
# parts for the next set of tests
class FakeCCSession(MultiConfigData):
    def __init__(self):
        self._local_changes = {}
        self._current_config = {}
        self._specifications = {}
        self.add_foo_spec()

    def add_foo_spec(self):
        spec = { "module_name": "foo",
                 "config_data": [
                 { "item_name": "an_int",
                   "item_type": "integer",
                   "item_optional": False,
                   "item_default": 1
                 },
                 { "item_name": "a_list",
                   "item_type": "list",
                   "item_optional": False,
                   "item_default": [],
                   "list_item_spec":
                   { "item_name": "a_string",
                     "item_type": "string",
                     "item_optional": False,
                     "item_default": "bar"
                   }
                 }
                 ]
               }
        self.set_specification(ModuleSpec(spec))
303

304

305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
# fake socket
class FakeSocket():
    def __init__(self):
        self.run = True

    def connect(self, to):
        if not self.run:
            raise socket.error

    def close(self):
        self.run = False

    def send(self, data):
        if not self.run:
            raise socket.error
        return len(data)

    def makefile(self, type):
        return self

    def sendall(self, data):
        if not self.run:
            raise socket.error
        return len(data)


331
332
333
334
335
336
class TestConfigCommands(unittest.TestCase):
    def setUp(self):
        self.tool = bindcmd.BindCmdInterpreter()
        mod_info = ModuleInfo(name = "foo")
        self.tool.add_module_info(mod_info)
        self.tool.config_data = FakeCCSession()
337
        self.stdout_backup = sys.stdout
338

339
340
341
342
343
344
    def test_precmd(self):
        def update_all_modules_info():
            raise socket.error
        def precmd(line):
            self.tool.precmd(line)
        self.tool._update_all_modules_info = update_all_modules_info
Jelte Jansen's avatar
Jelte Jansen committed
345
346
        # If line is equals to 'EOF', _update_all_modules_info()
        # shouldn't be called
347
        precmd('EOF')
348
349
        self.assertRaises(socket.error, precmd, 'continue')

350
351
352
    def test_run(self):
        def login_to_cmdctl():
            return True
353
        def cmd_loop():
354
            self.tool._send_message("/module_spec", None)
355

356
        self.tool.login_to_cmdctl = login_to_cmdctl
357
358
        # rewrite cmdloop() to avoid interactive mode
        self.tool.cmdloop = cmd_loop
359

360
        self.tool.conn.sock = FakeSocket()
361
        self.tool.conn.sock.close()
362
363
364
365

        # validate log message for socket.err
        socket_err_output = io.StringIO()
        sys.stdout = socket_err_output
366
        self.assertEqual(1, self.tool.run())
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
367
        self.assertEqual("Failed to send request, the connection is closed\n",
368
369
370
                         socket_err_output.getvalue())
        socket_err_output.close()

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
371
        # validate log message for http.client.CannotSendRequest
372
373
        cannot_send_output = io.StringIO()
        sys.stdout = cannot_send_output
374
        self.assertEqual(1, self.tool.run())
375
376
377
        self.assertEqual("Can not send request, the connection is busy\n",
                         cannot_send_output.getvalue())
        cannot_send_output.close()
378

379
    def test_apply_cfg_command_int(self):
380
        self.tool.location = '/'
381
382
383
384

        self.assertEqual((1, MultiConfigData.DEFAULT),
                         self.tool.config_data.get_value("/foo/an_int"))

Jelte Jansen's avatar
Jelte Jansen committed
385
386
387
        cmd_parser = cmdparse.BindCmdParser('config set identifier='
                                            '"foo/an_int" value="5"')
        self.tool.apply_config_cmd(cmd_parser)
388
389
390
        self.assertEqual((5, MultiConfigData.LOCAL),
                         self.tool.config_data.get_value("/foo/an_int"))

Jelte Jansen's avatar
Jelte Jansen committed
391
392
393
        cmd_parser = cmdparse.BindCmdParser('config unset identifier='
                                            '"foo/an_int"')
        self.tool.apply_config_cmd(cmd_parser)
394
395
396
397

        self.assertEqual((1, MultiConfigData.DEFAULT),
                         self.tool.config_data.get_value("/foo/an_int"))

398
        # this should raise a NotFoundError
Jelte Jansen's avatar
Jelte Jansen committed
399
400
401
402
        cmd_parser = cmdparse.BindCmdParser('config set identifier='
                                            '"foo/bar" value="[]"')
        self.assertRaises(isc.cc.data.DataNotFoundError,
                          self.tool.apply_config_cmd, cmd_parser)
403

Jelte Jansen's avatar
Jelte Jansen committed
404
405
        cmd_parser = cmdparse.BindCmdParser('config unset identifier='
                                            '"foo/bar"')
406
        self.assertRaises(isc.cc.data.DataNotFoundError,
Jelte Jansen's avatar
Jelte Jansen committed
407
                          self.tool.apply_config_cmd, cmd_parser)
408

409
        # this should raise a TypeError
Jelte Jansen's avatar
Jelte Jansen committed
410
411
412
413
        cmd_parser = cmdparse.BindCmdParser('config set identifier='
                                            '"foo/an_int" value="[]"')
        self.assertRaises(isc.cc.data.DataTypeError,
                          self.tool.apply_config_cmd, cmd_parser)
414

415
416
417
    # this is a very specific one for use with a set of list tests
    # to try out the flexibility of the parser (only in the next test)
    def clt(self, full_cmd_string, item_value):
Jelte Jansen's avatar
Jelte Jansen committed
418
419
        cmd_parser = cmdparse.BindCmdParser(full_cmd_string)
        self.tool.apply_config_cmd(cmd_parser)
420
421
422
        self.assertEqual(([item_value], MultiConfigData.LOCAL),
                         self.tool.config_data.get_value("/foo/a_list"))

423
424
425
426
427
428
    def test_apply_cfg_command_list(self):
        self.tool.location = '/'

        self.assertEqual(([], MultiConfigData.DEFAULT),
                         self.tool.config_data.get_value("/foo/a_list"))

429
430
431
432
433
434
435
436
437
438
439
        self.clt("config set identifier=\"foo/a_list\" value=[\"a\"]", "a")
        self.clt("config set identifier=\"foo/a_list\" value =[\"b\"]", "b")
        self.clt("config set identifier=\"foo/a_list\" value= [\"c\"]", "c")
        self.clt("config set identifier=\"foo/a_list\" value = [\"d\"]", "d")
        self.clt("config set identifier =\"foo/a_list\" value=[\"e\"]", "e")
        self.clt("config set identifier= \"foo/a_list\" value=[\"f\"]", "f")
        self.clt("config set identifier = \"foo/a_list\" value=[\"g\"]", "g")
        self.clt("config set identifier = \"foo/a_list\" value = [\"h\"]", "h")
        self.clt("config set identifier = \"foo/a_list\" value=[\"i\" ]", "i")
        self.clt("config set identifier = \"foo/a_list\" value=[ \"j\"]", "j")
        self.clt("config set identifier = \"foo/a_list\" value=[ \"k\" ]", "k")
440
441

        # this should raise a TypeError
Jelte Jansen's avatar
Jelte Jansen committed
442
443
444
445
        cmd_parser = cmdparse.BindCmdParser('config set identifier='
                                            '"foo/a_list" value="a"')
        self.assertRaises(isc.cc.data.DataTypeError,
                          self.tool.apply_config_cmd, cmd_parser)
446

Jelte Jansen's avatar
Jelte Jansen committed
447
448
449
450
        cmd_parser = cmdparse.BindCmdParser('config set identifier='
                                            '"foo/a_list" value=[1]')
        self.assertRaises(isc.cc.data.DataTypeError,
                          self.tool.apply_config_cmd, cmd_parser)
451

452
453
454
    def tearDown(self):
        sys.stdout = self.stdout_backup

455
    def test_cmd_has_identifier_param(self):
JINMEI Tatuya's avatar
JINMEI Tatuya committed
456
        module = ModuleInfo(name="test_module")
457

JINMEI Tatuya's avatar
JINMEI Tatuya committed
458
        cmd = CommandInfo(name="command_with_identifier")
459
        param = ParamInfo(name=bindcmd.CFGITEM_IDENTIFIER_PARAM)
460
461
462
        cmd.add_param(param)
        module.add_command(cmd)

JINMEI Tatuya's avatar
JINMEI Tatuya committed
463
464
        cmd = CommandInfo(name="command_without_identifier")
        param = ParamInfo(name="some_argument")
465
466
467
468
469
        cmd.add_param(param)
        module.add_command(cmd)

        self.tool.add_module_info(module)

Jelte Jansen's avatar
Jelte Jansen committed
470
471
472
        cmd_parser = cmdparse.BindCmdParser('test_module '
                                            'command_with_identifier')
        self.assertTrue(self.tool._cmd_has_identifier_param(cmd_parser))
473

Jelte Jansen's avatar
Jelte Jansen committed
474
475
476
        cmd_parser = cmdparse.BindCmdParser('test_module '
                                            'command_without_identifier')
        self.assertFalse(self.tool._cmd_has_identifier_param(cmd_parser))
477

Jelte Jansen's avatar
Jelte Jansen committed
478
479
480
        cmd_parser = cmdparse.BindCmdParser('badmodule '
                                            'command_without_identifier')
        self.assertFalse(self.tool._cmd_has_identifier_param(cmd_parser))
481
482
483

    def test_get_identifier_startswith(self):
        hints = self.tool._get_identifier_startswith("/")
JINMEI Tatuya's avatar
JINMEI Tatuya committed
484
        self.assertEqual(['foo/an_int', 'foo/a_list'], hints)
485
486
487
488
489
490
491

        hints = self.tool._get_identifier_startswith("/foo/an")
        self.assertEqual(['foo/an_int'], hints)

        hints = self.tool._get_identifier_startswith("/bar")
        self.assertEqual([], hints)

492
493
494
495
496
497
class FakeBindCmdInterpreter(bindcmd.BindCmdInterpreter):
    def __init__(self):
        pass

class TestBindCmdInterpreter(unittest.TestCase):

498
499
500
501
502
503
    def setUp(self):
        self.old_stdout = sys.stdout

    def tearDown(self):
        sys.stdout = self.old_stdout

504
505
506
507
508
509
510
511
    def _create_invalid_csv_file(self, csvfilename):
        import csv
        csvfile = open(csvfilename, 'w')
        writer = csv.writer(csvfile)
        writer.writerow(['name1'])
        writer.writerow(['name2'])
        csvfile.close()

512
513
    def test_csv_file_dir(self):
        # Checking default value
514
        home_dir = pwd.getpwnam(getpass.getuser()).pw_dir
515
516
517
518
519
520
521
        self.assertEqual(home_dir + os.sep + '.bind10' + os.sep,
                         bindcmd.BindCmdInterpreter().csv_file_dir)

        new_csv_dir = '/something/different/'
        custom_cmd = bindcmd.BindCmdInterpreter(csv_file_dir=new_csv_dir)
        self.assertEqual(new_csv_dir, custom_cmd.csv_file_dir)

522
    def test_get_saved_user_info(self):
523
524
525
526
527
528
529
530
531
532
533
        with open(os.devnull, 'w') as f:
            sys.stdout = f
            cmd = bindcmd.BindCmdInterpreter()
            users = cmd._get_saved_user_info('/notexist', 'csv_file.csv')
            self.assertEqual([], users)

            csvfilename = 'csv_file.csv'
            self._create_invalid_csv_file(csvfilename)
            users = cmd._get_saved_user_info('./', csvfilename)
            self.assertEqual([], users)
            os.remove(csvfilename)
534
535
536

class TestCommandLineOptions(unittest.TestCase):
    def setUp(self):
537
        self.parser = TestOptParser()
538
539
540
541
542
543
544
545
546
547
548
549
        set_bindctl_options(self.parser)

    def test_csv_file_dir(self):
        # by default the option is "undefined"
        (options, _) = self.parser.parse_args([])
        self.assertEqual(None, options.csv_file_dir)

        # specify the option, valid case.
        (options, _) = self.parser.parse_args(['--csv-file-dir', 'some_dir'])
        self.assertEqual('some_dir', options.csv_file_dir)

        # missing option arg; should trigger parser error.
550
        self.assertRaises(OptsError, self.parser.parse_args,
551
552
                          ['--csv-file-dir'])

553
554
if __name__== "__main__":
    unittest.main()
555