def test_prompt_input_validate_failure(self, capfd): # this is a bit complex, because our mocks need to do different things on first and second calls input_returns = ['hello', 'goodbye'] def input_se(*args): return input_returns.pop(0) input_mock = mock.MagicMock(side_effect=input_se) confirm_mock = mock.MagicMock() confirm_mock.return_value = True validate_returns = [None, 'eybdoog'] def validate_se(*args): return validate_returns.pop(0) validate_mock = mock.MagicMock(side_effect=validate_se) dc = DnstestConfig() with mock.patch('pydnstest.config.DnstestConfig.input_wrapper', input_mock): with mock.patch('pydnstest.config.DnstestConfig.confirm_response', confirm_mock): foo = dc.prompt_input("foo", validate_cb=validate_mock) assert input_mock.call_count == 2 out, err = capfd.readouterr() assert out == "ERROR: invalid response: hello\n" assert err == "" assert confirm_mock.call_count == 1 assert validate_mock.call_count == 2 assert foo == 'eybdoog'
def test_confirm_response_empty(self): dc = DnstestConfig() input_mock = mock.MagicMock() input_mock.return_value = "\n" with mock.patch('pydnstest.config.DnstestConfig.input_wrapper', input_mock): foo = dc.confirm_response('foo') assert input_mock.call_count == 1 assert input_mock.call_args == mock.call("Is 'foo' correct? [y/N] ") assert foo == False
def test_set_example_values(self): """ test converting the example config to a string """ dc = DnstestConfig() dc.set_example_values() assert dc.server_prod == '1.2.3.4' assert dc.server_test == '1.2.3.5' assert dc.default_domain == '.example.com' assert dc.have_reverse_dns == True assert dc.ignore_ttl == False assert dc.sleep == 0.0
def test_parse_bad_config_file(self, save_user_config): fpath = os.path.abspath("dnstest.ini") contents = """ [servers] blarg """ self.write_conf_file(fpath, contents) dc = DnstestConfig() with pytest.raises(ParsingError): dc.load_config(fpath)
def test_input_wrapper(self): dc = DnstestConfig() input_mock = mock.MagicMock() if sys.version_info[0] == 3: with mock.patch('builtins.input', input_mock): dc.input_wrapper("foo") else: with mock.patch('__builtin__.raw_input', input_mock): dc.input_wrapper("foo") assert input_mock.call_count == 1 assert input_mock.call_args == mock.call('foo')
def test_parse_empty_config_file(self, save_user_config): dc = DnstestConfig() fpath = os.path.abspath("dnstest.ini") contents = "" self.write_conf_file(fpath, contents) dc.load_config(fpath) assert dc.server_prod == '' assert dc.server_test == '' assert dc.default_domain == '' assert dc.have_reverse_dns == True assert dc.ignore_ttl == False assert dc.sleep == 0.0
def test_parse_example_config_file(self, save_user_config): dc = DnstestConfig() fpath = os.path.abspath("dnstest.ini.example") dc.load_config(fpath) assert dc.server_prod == '1.2.3.4' assert dc.server_test == '1.2.3.5' assert dc.default_domain == '.example.com' assert dc.have_reverse_dns == True assert dc.ignore_ttl == False assert dc.sleep == 0.0 assert dc.asDict() == {'default_domain': '.example.com', 'have_reverse_dns': True, 'servers': {'prod': '1.2.3.4', 'test': '1.2.3.5'}, 'ignore_ttl': False, 'sleep': 0.0}
def test_promptconfig_no_confirm(self, capfd): dc = DnstestConfig() dc.conf_file = '/foo/bar/baz' def prompt_input_se(prompt, default=None, validate_cb=None): ret = { "Production DNS Server IP": '1.2.3.4', "Test/Staging DNS Server IP": '5.6.7.8', "Check for reverse DNS by default? [Y|n]": True, "Default domain for to append to any input that appears to be less than a FQDN (blank for none)": 'example.com', "Ignore difference in TTL when comparing responses? [y|N]": False, "Sleep between DNS record tests (seconds)": 0.0, } return ret[prompt] prompt_input_mock = mock.MagicMock(side_effect=prompt_input_se) confirm_response_mock = mock.MagicMock() confirm_response_mock.return_value = False to_string_mock = mock.MagicMock() to_string_mock.return_value = 'foo bar baz' write_mock = mock.MagicMock() write_mock.return_value = True with mock.patch('pydnstest.config.DnstestConfig.prompt_input', prompt_input_mock): with mock.patch('pydnstest.config.DnstestConfig.to_string', to_string_mock): with mock.patch('pydnstest.config.DnstestConfig.confirm_response', confirm_response_mock): with mock.patch('pydnstest.config.DnstestConfig.write', write_mock): with pytest.raises(SystemExit) as excinfo: dc.prompt_config() assert excinfo.value.code == "Exiting on user request. No configuration written." assert prompt_input_mock.call_count == 6 assert prompt_input_mock.call_args_list == [ mock.call("Production DNS Server IP", validate_cb=dc.validate_ipaddr), mock.call("Test/Staging DNS Server IP", validate_cb=dc.validate_ipaddr), mock.call("Check for reverse DNS by default? [Y|n]", default=True, validate_cb=dc.validate_bool), mock.call("Default domain for to append to any input that appears to be less than a FQDN (blank for none)", default=''), mock.call("Ignore difference in TTL when comparing responses? [y|N]", default=False, validate_cb=dc.validate_bool), mock.call("Sleep between DNS record tests (seconds)", default=0.0, validate_cb=dc.validate_float), ] assert to_string_mock.call_count == 1 assert confirm_response_mock.call_count == 1 assert write_mock.call_count == 0 out, err = capfd.readouterr() assert out == "Configuration:\n#####################\nfoo bar baz\n#####################\n\n" assert err == "" assert dc.server_prod == '1.2.3.4' assert dc.server_test == '5.6.7.8' assert dc.have_reverse_dns == True assert dc.default_domain == 'example.com' assert dc.ignore_ttl == False assert dc.sleep == 0.0
def test_prompt_input_default(self): input_mock = mock.MagicMock() input_mock.return_value = '' confirm_mock = mock.MagicMock() confirm_mock.return_value = True dc = DnstestConfig() with mock.patch('pydnstest.config.DnstestConfig.input_wrapper', input_mock): with mock.patch('pydnstest.config.DnstestConfig.confirm_response', confirm_mock): foo = dc.prompt_input("foo", default='bar') assert input_mock.call_count == 1 assert input_mock.call_args == mock.call("foo (default: bar): ") assert confirm_mock.call_count == 1 assert foo == 'bar'
def test_prompt_input_validate_success(self): input_mock = mock.MagicMock() input_mock.return_value = 'hello' confirm_mock = mock.MagicMock() confirm_mock.return_value = True validate_mock = mock.MagicMock() validate_mock.return_value = 'goodbye' dc = DnstestConfig() with mock.patch('pydnstest.config.DnstestConfig.input_wrapper', input_mock): with mock.patch('pydnstest.config.DnstestConfig.confirm_response', confirm_mock): foo = dc.prompt_input("foo", validate_cb=validate_mock) assert input_mock.call_count == 1 assert confirm_mock.call_count == 1 assert validate_mock.call_count == 1 assert foo == 'goodbye'
def test_write(self, save_user_config): """ test writing the file to disk """ dc = DnstestConfig() conf_str = dc.to_string() mock_open = mock.mock_open() if sys.version_info[0] == 3: mock_target = 'builtins.open' else: mock_target = '__builtin__.open' with mock.patch(mock_target, mock_open, create=True): dc.write() assert mock_open.call_count == 1 fh = mock_open.return_value.__enter__.return_value assert fh.write.call_count == 1 assert fh.write.call_args == mock.call(conf_str)
def test_prompt_input_no_confirm(self): input_mock = mock.MagicMock() input_mock.return_value = 'hello' def confirm_se(*args): return confirm_returns.pop(0) confirm_returns = [False, True] confirm_mock = mock.MagicMock(side_effect=confirm_se) dc = DnstestConfig() with mock.patch('pydnstest.config.DnstestConfig.input_wrapper', input_mock): with mock.patch('pydnstest.config.DnstestConfig.confirm_response', confirm_mock): foo = dc.prompt_input("foo") assert input_mock.call_count == 2 assert confirm_mock.call_count == 2 assert foo == 'hello'
def test_example_config_to_string(self): """ test converting the example config to a string """ fpath = os.path.abspath("dnstest.ini.example") with open(fpath, 'r') as fh: expected = fh.read() dc = DnstestConfig() dc.server_prod = '1.2.3.4' dc.server_test = '1.2.3.5' dc.default_domain = '.example.com' dc.have_reverse_dns = True dc.ignore_ttl = False dc.sleep = 0.0 result = dc.to_string() assert result == expected
def test_prompt_input_default_float(self): input_mock = mock.MagicMock() input_mock.return_value = '' confirm_mock = mock.MagicMock() confirm_mock.return_value = True validate_mock = mock.MagicMock() validate_mock.return_value = 123.456 dc = DnstestConfig() with mock.patch('pydnstest.config.DnstestConfig.input_wrapper', input_mock): with mock.patch('pydnstest.config.DnstestConfig.confirm_response', confirm_mock): foo = dc.prompt_input("foo", default=123.456, validate_cb=validate_mock) assert input_mock.call_count == 1 assert input_mock.call_args == mock.call("foo (default: 123.456): ") assert confirm_mock.call_count == 1 assert validate_mock.call_count == 1 assert validate_mock.call_args == mock.call('123.456') assert foo == 123.456
def setup_verifies(self): """ Sets up test environment for tests of verify methods, including redefining resolve_name and lookup_reverse to the appropriate methods in this class """ config = DnstestConfig() config.server_test = "test" config.server_prod = "prod" config.default_domain = ".example.com" config.have_reverse_dns = True chk = DNStestChecks(config) # stub chk.DNS.resolve_name = self.stub_resolve_name_verify # stub chk.DNS.lookup_reverse = self.stub_lookup_reverse_verify return chk
def test_parse_example_config_file(self, save_user_config): dc = DnstestConfig() fpath = os.path.abspath("dnstest.ini.example") dc.load_config(fpath) assert dc.server_prod == '1.2.3.4' assert dc.server_test == '1.2.3.5' assert dc.default_domain == '.example.com' assert dc.have_reverse_dns == True assert dc.ignore_ttl == False assert dc.sleep == 0.0 assert dc.asDict() == { 'default_domain': '.example.com', 'have_reverse_dns': True, 'servers': { 'prod': '1.2.3.4', 'test': '1.2.3.5' }, 'ignore_ttl': False, 'sleep': 0.0 }
def setup_checks(self): global config global chk global parser config = DnstestConfig() config.server_test = "test_server_stub" config.server_prod = "prod_server_stub" config.default_domain = ".example.com" config.have_reverse_dns = True pydnstest.config = config parser = DnstestParser() pydnstest.parser = parser chk = DNStestChecks(config) # stub chk.DNS.resolve_name = self.stub_resolve_name # stub chk.DNS.lookup_reverse = self.stub_lookup_reverse pydnstest.chk = chk return (parser, chk)
def setup_parser_return_unknown_op(self): """ Sets up test environment for tests of check methods, including redefining resolve_name and lookup_reverse to the appropriate methods in this class """ config = DnstestConfig() config.server_test = "test" config.server_prod = "prod" config.default_domain = ".example.com" config.have_reverse_dns = True parser = DnstestParser() # mock the parser function to just return None parser.parse_line = self.parser_return_unknown_op pydnstest.parser = parser chk = DNStestChecks(config) # stub chk.DNS.resolve_name = self.stub_resolve_name # stub chk.DNS.lookup_reverse = self.stub_lookup_reverse return (parser, chk)
def setup_checks(self): """ Sets up test environment for tests of check methods, including redefining resolve_name and lookup_reverse to the appropriate methods in this class """ config = DnstestConfig() config.server_test = "test" config.server_prod = "prod" config.default_domain = ".example.com" config.have_reverse_dns = True config.ignore_ttl = False parser = DnstestParser() pydnstest.parser = parser chk = DNStestChecks(config) # stub chk.DNS.resolve_name = self.stub_resolve_name # stub chk.DNS.lookup_reverse = self.stub_lookup_reverse return (parser, chk)
def test_find_dot_config_file(self, save_user_config): dc = DnstestConfig() fpath = os.path.expanduser("~/.dnstest.ini") self.write_conf_file(fpath, "test_find_dot_config_file") assert dc.find_config_file() == fpath
def main(options): """ main function - does everything... split this out this way for testing...p """ # read in config, set variable config = DnstestConfig() if options.exampleconf: config.set_example_values() print(config.to_string()) raise SystemExit(0) if options.promptconfig: # interactively build a configuration file config.prompt_config() raise SystemExit(0) if options.config_file: conf_file = options.config_file else: conf_file = config.find_config_file() if conf_file is None: print( "ERROR: no configuration file found. Run with --promptconfig to build one interactively, or --example-config for an example." ) raise SystemExit(1) config.load_config(conf_file) if options.ignorettl: config.ignore_ttl = True if options.configprint: print("# {fname}".format(fname=config.conf_file)) print(config.to_string()) raise SystemExit(0) parser = DnstestParser() chk = DNStestChecks(config) if options.sleep: config.sleep = options.sleep print("Note - will sleep %g seconds between lines" % options.sleep) # if no other options, read from stdin if options.testfile: if not os.path.exists(options.testfile): print("ERROR: test file '%s' does not exist." % options.testfile) raise SystemExit(1) fh = open(options.testfile, 'r') else: # read from stdin sys.stderr.write( "WARNING: reading from STDIN. Run with '-f filename' to read tests from a file.\n" ) fh = sys.stdin # read input line by line, handle each line as we're given it passed = 0 failed = 0 for line in fh: line = line.strip() if not line: continue if line[:1] == "#": continue if options.verify: r = run_verify_line(line, parser, chk) else: r = run_check_line(line, parser, chk) if r is False: continue elif r['result']: passed = passed + 1 else: failed = failed + 1 format_test_output(r) if config.sleep is not None and config.sleep > 0.0: sleep(config.sleep) msg = "" if failed == 0: msg = "All %d tests passed. (pydnstest %s)" % (passed, VERSION) else: msg = "%d passed / %d FAILED. (pydnstest %s)" % (passed, failed, VERSION) print("++++ %s" % msg) if options.testfile: # we were reading a file, close it fh.close()
def test_validate_float(self, input_str, result): dc = DnstestConfig() assert dc.validate_float(input_str) == result
def test_promptconfig_no_confirm(self, capfd): dc = DnstestConfig() dc.conf_file = '/foo/bar/baz' def prompt_input_se(prompt, default=None, validate_cb=None): ret = { "Production DNS Server IP": '1.2.3.4', "Test/Staging DNS Server IP": '5.6.7.8', "Check for reverse DNS by default? [Y|n]": True, "Default domain for to append to any input that appears to be less than a FQDN (blank for none)": 'example.com', "Ignore difference in TTL when comparing responses? [y|N]": False, "Sleep between DNS record tests (seconds)": 0.0, } return ret[prompt] prompt_input_mock = mock.MagicMock(side_effect=prompt_input_se) confirm_response_mock = mock.MagicMock() confirm_response_mock.return_value = False to_string_mock = mock.MagicMock() to_string_mock.return_value = 'foo bar baz' write_mock = mock.MagicMock() write_mock.return_value = True with mock.patch('pydnstest.config.DnstestConfig.prompt_input', prompt_input_mock): with mock.patch('pydnstest.config.DnstestConfig.to_string', to_string_mock): with mock.patch( 'pydnstest.config.DnstestConfig.confirm_response', confirm_response_mock): with mock.patch('pydnstest.config.DnstestConfig.write', write_mock): with pytest.raises(SystemExit) as excinfo: dc.prompt_config() assert excinfo.value.code == "Exiting on user request. No configuration written." assert prompt_input_mock.call_count == 6 assert prompt_input_mock.call_args_list == [ mock.call("Production DNS Server IP", validate_cb=dc.validate_ipaddr), mock.call("Test/Staging DNS Server IP", validate_cb=dc.validate_ipaddr), mock.call("Check for reverse DNS by default? [Y|n]", default=True, validate_cb=dc.validate_bool), mock.call( "Default domain for to append to any input that appears to be less than a FQDN (blank for none)", default=''), mock.call( "Ignore difference in TTL when comparing responses? [y|N]", default=False, validate_cb=dc.validate_bool), mock.call("Sleep between DNS record tests (seconds)", default=0.0, validate_cb=dc.validate_float), ] assert to_string_mock.call_count == 1 assert confirm_response_mock.call_count == 1 assert write_mock.call_count == 0 out, err = capfd.readouterr() assert out == "Configuration:\n#####################\nfoo bar baz\n#####################\n\n" assert err == "" assert dc.server_prod == '1.2.3.4' assert dc.server_test == '5.6.7.8' assert dc.have_reverse_dns == True assert dc.default_domain == 'example.com' assert dc.ignore_ttl == False assert dc.sleep == 0.0
def main(options): """ main function - does everything... split this out this way for testing...p """ # read in config, set variable config = DnstestConfig() if options.exampleconf: config.set_example_values() print(config.to_string()) raise SystemExit(0) if options.promptconfig: # interactively build a configuration file config.prompt_config() raise SystemExit(0) if options.config_file: conf_file = options.config_file else: conf_file = config.find_config_file() if conf_file is None: print("ERROR: no configuration file found. Run with --promptconfig to build one interactively, or --example-config for an example.") raise SystemExit(1) config.load_config(conf_file) if options.ignorettl: config.ignore_ttl = True if options.configprint: print("# {fname}".format(fname=config.conf_file)) print(config.to_string()) raise SystemExit(0) parser = DnstestParser() chk = DNStestChecks(config) if options.sleep: config.sleep = options.sleep print("Note - will sleep %g seconds between lines" % options.sleep) # if no other options, read from stdin if options.testfile: if not os.path.exists(options.testfile): print("ERROR: test file '%s' does not exist." % options.testfile) raise SystemExit(1) fh = open(options.testfile, 'r') else: # read from stdin sys.stderr.write("WARNING: reading from STDIN. Run with '-f filename' to read tests from a file.\n") fh = sys.stdin # read input line by line, handle each line as we're given it passed = 0 failed = 0 for line in fh: line = line.strip() if not line: continue if line[:1] == "#": continue if options.verify: r = run_verify_line(line, parser, chk) else: r = run_check_line(line, parser, chk) if r is False: continue elif r['result']: passed = passed + 1 else: failed = failed + 1 format_test_output(r) if config.sleep is not None and config.sleep > 0.0: sleep(config.sleep) msg = "" if failed == 0: msg = "All %d tests passed. (pydnstest %s)" % (passed, VERSION) else: msg = "%d passed / %d FAILED. (pydnstest %s)" % (passed, failed, VERSION) print("++++ %s" % msg) if options.testfile: # we were reading a file, close it fh.close()
def test_find_no_config_file(self, save_user_config): dc = DnstestConfig() assert dc.find_config_file() == None
def test_find_main_config_file(self, save_user_config): dc = DnstestConfig() fpath = os.path.abspath("dnstest.ini") self.write_conf_file(fpath, "test_find_main_config_file") assert dc.find_config_file() == fpath