def setup_method(self, method): self.test_config = build_config_from_dicts( global_conf=None, main_conf={ "backup_directory": "/some/barman/home/main", "archiver": "on", }, test_conf={ "backup_directory": "/some/barman/home/main", "archiver": "on", }, ) self.test_config_with_pwd = build_config_from_dicts( global_conf=None, main_conf={ "backup_directory": "/some/barman/home/main", "conninfo": "host=pg01.nowhere user=postgres password=testpassword", "archiver": "on", }, test_conf={ "backup_directory": "/some/barman/home/main", "archiver": "on", }, )
def test_get_server_with_conflicts(self, monkeypatch, capsys): """ Test get_server method using a configuration containing errors :param monkeypatch monkeypatch: pytest patcher """ # Mock the args from argparse args = Mock() # conflicting directories monkeypatch.setattr(barman, '__config__', build_config_from_dicts( main_conf={ 'wals_directory': '/some/barman/home/main/wals', 'basebackups_directory': '/some/barman/home/main/wals', })) args.server_name = 'main' with pytest.raises(SystemExit): get_server(args, True) out, err = capsys.readouterr() assert err assert "ERROR: Conflicting path:" in err # conflicting directories with on_error_stop=False monkeypatch.setattr(barman, '__config__', build_config_from_dicts( main_conf={ 'wals_directory': '/some/barman/home/main/wals', 'basebackups_directory': '/some/barman/home/main/wals', })) args.server_name = 'main' get_server(args, on_error_stop=False) # In this case the server is returned and a warning message is emitted out, err = capsys.readouterr() assert err assert "ERROR: Conflicting path:" in err
def test_bad_init(self): """ Check the server is buildable with an empty configuration """ server = Server(build_config_from_dicts( main_conf={ 'conninfo': '', 'ssh_command': '', } ).get_server('main')) assert server.config.disabled # ARCHIVER_OFF_BACKCOMPATIBILITY - START OF CODE # # Check that either archiver or streaming_archiver are set # server = Server(build_config_from_dicts( # main_conf={ # 'archiver': 'off', # 'streaming_archiver': 'off' # } # ).get_server('main')) # assert server.config.disabled # assert "No archiver enabled for server 'main'. " \ # "Please turn on 'archiver', 'streaming_archiver' or " \ # "both" in server.config.msg_list # ARCHIVER_OFF_BACKCOMPATIBILITY - START OF CODE server = Server(build_config_from_dicts( main_conf={ 'archiver': 'off', 'streaming_archiver': 'on', 'slot_name': '' } ).get_server('main')) assert server.config.disabled assert "Streaming-only archiver requires 'streaming_conninfo' and " \ "'slot_name' options to be properly configured" \ in server.config.msg_list
def test_csv_values_recovery_options(self): """ Simple test for recovery_options values: '' and get-wal test case global value: recovery_options = '' expected: recovery_options = None test case global value: recovery_options = 'get-wal' expected: recovery_options = empty RecoveryOptions obj """ # Build configuration with empty recovery_options c = build_config_from_dicts({'recovery_options': ''}, None) main = c.get_server('main') expected = build_config_dictionary({ 'config': c, 'recovery_options': RecoveryOptions('', '', ''), }) assert main.__dict__ == expected # Build configuration with recovery_options set to get-wal c = build_config_from_dicts({'recovery_options': 'get-wal'}, None) main = c.get_server('main') expected = build_config_dictionary({ 'config': c, 'recovery_options': RecoveryOptions('get-wal', '', ''), }) assert main.__dict__ == expected
def test_get_server_list(self, monkeypatch, capsys): """ Test the get_server_list method :param monkeypatch monkeypatch: pytest patcher """ monkeypatch.setattr(barman, "__config__", build_config_from_dicts()) server_dict = get_server_list() assert server_dict # Expect 2 test servers Main and Test assert len(server_dict) == 2 # Test the method with global errors monkeypatch.setattr( barman, "__config__", build_config_from_dicts( global_conf=None, main_conf={ "basebackups_directory": "/some/barman/home/main/base", "incoming_wals_directory": "/some/barman/home/main/incoming", "wals_directory": "/some/barman/home/main/wals", "backup_directory": "/some/barman/home/main", "archiver": "on", }, test_conf={ "basebackups_directory": "/some/barman/home/test/wals", "incoming_wals_directory": "/some/barman/home/main/incoming", "wals_directory": "/some/barman/home/main/wals", "backup_directory": "/some/barman/home/main", "archiver": "on", }, ), ) # Expect the method to fail and exit with pytest.raises(SystemExit): get_server_list() out, err = capsys.readouterr() # Check for the presence of error messages assert err # Check paths in error messages assert ( "Conflicting path: " "basebackups_directory=/some/barman/home/main/base" in err ) assert ( "Conflicting path: " "incoming_wals_directory=/some/barman/home/main/incoming" in err ) assert "Conflicting path: wals_directory=/some/barman/home/main/wals" in err assert "Conflicting path: backup_directory=/some/barman/home/main" in err
def test_csv_values_global_conflict(self, out_mock): """ test case global value: backup_options = exclusive_backup, concurrent_backup server value: backup_options = expected: backup_options = exclusive_backup Empty value is not allowed in BackupOptions class, so we expect the configuration parser to fall back to the global value. The global backup_options holds conflicting parameters, so we expect the config builder to fall back to ignore de directive. :param out_mock: Mock the output """ # build a string with conflicting values conflict = "%s, %s" % (BackupOptions.EXCLUSIVE_BACKUP, BackupOptions.CONCURRENT_BACKUP) # add backup_options to minimal configuration string c = build_config_from_dicts(global_conf={ 'archiver': 'on', 'backup_options': conflict }, main_conf=None) main = c.get_server('main') # create the expected dictionary expected = build_config_dictionary({'config': main.config}) assert main.__dict__ == expected # use the mocked output class to verify the presence of the warning # for a bad configuration parameter out_mock.warning.assert_called_with( "Ignoring invalid configuration " "value '%s' for key %s in %s: %s", 'exclusive_backup, ' 'concurrent_backup', 'backup_options', '[barman] section', mock.ANY)
def test_csv_values_global_conflict(self, out_mock): """ test case global value: backup_options = exclusive_backup, concurrent_backup server value: backup_options = expected: backup_options = exclusive_backup Empty value is not allowed in BackupOptions class, so we expect the configuration parser to fall back to the global value. The global backup_options holds conflicting parameters, so we expect the config builder to fall back to ignore de directive. :param out_mock: Mock the output """ # build a string with conflicting values conflict = "%s, %s" % (BackupOptions.EXCLUSIVE_BACKUP, BackupOptions.CONCURRENT_BACKUP) # add backup_options to minimal configuration string c = build_config_from_dicts( {'backup_options': conflict}, None) main = c.get_server('main') # create the expected dictionary expected = build_config_dictionary({'config': main.config}) assert main.__dict__ == expected # use the mocked output class to verify the presence of the warning # for a bad configuration parameter out_mock.warning.assert_called_with("Invalid configuration value '%s' " "for key %s in %s: %s", None, 'backup_options', '[barman] section', mock.ANY)
def test_csv_values_multikey_invalid_server_value(self, out_mock): """ test case global: backup_options = concurrent_backup server: backup_options = exclusive_backup, none_of_your_business result = backup_options = concurrent_backup the 'none_of_your_business' value on server section invalidates the whole csv string, because is not an allowed value of the BackupOptions class. We expect to fallback to the global 'concurrent_backup' value. """ # build a string with a wrong value wrong_parameters = "%s, %s" % (BackupOptions.EXCLUSIVE_BACKUP, 'none_of_your_business') # add backup_options to minimal configuration string c = build_config_from_dicts( {'backup_options': BackupOptions.CONCURRENT_BACKUP}, {'backup_options': wrong_parameters}) main = c.get_server('main') # create the expected dictionary expected = build_config_dictionary({ 'config': main.config, 'backup_options': set(['concurrent_backup']), }) assert main.__dict__ == expected # use the mocked output class to verify the presence of the warning # for a bad configuration parameter out_mock.warning.assert_called_with("Invalid configuration value '%s' " "for key %s in %s: %s", None, 'backup_options', '[main] section', mock.ANY)
def test_recover_multiple_targets(self, get_server_mock, parse_backup_id_mock, monkeypatch, capsys): backup_info = Mock() backup_info.status = BackupInfo.DONE backup_info.tablespaces = [] parse_backup_id_mock.return_value = backup_info monkeypatch.setattr( barman, '__config__', build_config_from_dicts(main_conf={ 'archiver': 'on', })) # Testing mutual exclusiveness of target options args = Mock() args.backup_id = '20170823T104400' args.server_name = 'main' args.destination_directory = 'recovery_dir' args.tablespace = None args.target_name = None args.target_tli = 3 args.target_immediate = True args.target_time = None args.target_xid = None with pytest.raises(SystemExit): recover(args) _, err = capsys.readouterr() assert 'ERROR: You cannot specify multiple targets for the recovery ' \ 'operation' in err
def test_recover_default_target(self, get_server_mock, parse_backup_id_mock, monkeypatch, capsys): backup_info = Mock() backup_info.status = BackupInfo.DONE backup_info.tablespaces = [] parse_backup_id_mock.return_value = backup_info monkeypatch.setattr( barman, "__config__", build_config_from_dicts(main_conf={ "archiver": "on", }), ) # This parameters are fine args = Mock() args.backup_id = "20170823T104400" args.server_name = "main" args.destination_directory = "recovery_dir" args.tablespace = None args.target_name = None args.target_tli = None args.target_immediate = None args.target_time = None args.target_xid = None args.target_lsn = None args.target_action = None with pytest.raises(SystemExit): recover(args) _, err = capsys.readouterr() assert "" == err
def test_csv_values_invalid_server_value(self, out_mock): """ test case global: backup_options = exclusive_backup server: backup_options = none_of_your_business result = backup_options = exclusive_backup The 'none_of_your_business' value on server section, is not an allowed value for the BackupOptions class, We expect to the config builder to fallback to the global 'exclusive_backup' value """ # add backup_options to minimal configuration string c = build_config_from_dicts( {'backup_options': BackupOptions.EXCLUSIVE_BACKUP}, {'backup_options': 'none_of_your_business'}) main = c.get_server('main') # create the expected dictionary expected = build_config_dictionary({'config': main.config}) assert main.__dict__ == expected # use the mocked output class to verify the presence of the warning # for a bad configuration parameter out_mock.warning.assert_called_with("Invalid configuration value '%s' " "for key %s in %s: %s", None, 'backup_options', '[main] section', mock.ANY)
def test_init(self, tmpdir): """ Test the init method """ # Build a basic configuration config = build_config_from_dicts({ 'barman_lock_directory': tmpdir.strpath}) config.name = 'main' # Acquire a lock and initialise the ProjectManager. # Expect the ProjectManager to Retrieve the # "Running process" identified by the lock lock = ServerWalReceiveLock(tmpdir.strpath, 'main') with lock: pm = ProcessManager(config) # Test for the length of the process list assert len(pm.process_list) == 1 # Test for the server identifier of the process assert pm.process_list[0].server_name == 'main' # Test for the task type assert pm.process_list[0].task == 'receive-wal' # Read the pid from the lockfile and test id against the ProcessInfo # contained in the process_list with open(lock.filename, 'r') as lockfile: pid = lockfile.read().strip() assert int(pid) == pm.process_list[0].pid # Test lock file parse error. # Skip the lock and don't raise any exception. with lock: with open(lock.filename, 'w') as lockfile: lockfile.write("invalid") pm = ProcessManager(config) assert len(pm.process_list) == 0
def test_init(self, tmpdir): """ Test the init method """ # Build a basic configuration config = build_config_from_dicts( {"barman_lock_directory": tmpdir.strpath}) config.name = "main" # Acquire a lock and initialise the ProjectManager. # Expect the ProjectManager to Retrieve the # "Running process" identified by the lock lock = ServerWalReceiveLock(tmpdir.strpath, "main") with lock: pm = ProcessManager(config) # Test for the length of the process list assert len(pm.process_list) == 1 # Test for the server identifier of the process assert pm.process_list[0].server_name == "main" # Test for the task type assert pm.process_list[0].task == "receive-wal" # Read the pid from the lockfile and test id against the ProcessInfo # contained in the process_list with open(lock.filename, "r") as lockfile: pid = lockfile.read().strip() assert int(pid) == pm.process_list[0].pid # Test lock file parse error. # Skip the lock and don't raise any exception. with lock: with open(lock.filename, "w") as lockfile: lockfile.write("invalid") pm = ProcessManager(config) assert len(pm.process_list) == 0
def test_csv_values_global_concurrent(self): """ test case global value: backup_options = concurrent_backup expected: backup_options = concurrent_backup Simple test for concurrent_backup option parsing """ # add backup_options to minimal configuration string c = build_config_from_dicts(global_conf={ 'archiver': 'on', 'backup_options': BackupOptions.CONCURRENT_BACKUP }, main_conf=None) main = c.get_server('main') # create the expected dictionary expected = build_config_dictionary({ 'config': main.config, 'backup_options': set(['concurrent_backup']), 'backup_method': 'rsync', }) assert main.__dict__ == expected
def test_server_conflict_paths(self): """ Test for the presence of conflicting paths for a server """ # Build a configuration with conflicts: # basebackups_directory = /some/barman/home/main/wals # wals_directory = /some/barman/home/main/wals c = build_config_from_dicts( main_conf={ 'archiver': 'on', 'basebackups_directory': '/some/barman/home/main/wals', 'description': ' Text with quotes ', }) main = c.get_server('main') # create the expected dictionary expected = build_config_dictionary({ 'config': main.config, 'disabled': True, 'basebackups_directory': '/some/barman/home/main/wals', 'msg_list': [ 'Conflicting path: wals_directory=/some/barman/home/main/wals ' 'conflicts with \'basebackups_directory\' ' 'for server \'main\'' ], 'description': 'Text with quotes', }) assert main.__dict__ == expected
def test_populate_servers_following_symlink(self, tmpdir): """ Test for the presence of conflicting paths in configuration between all the servers """ incoming_dir = tmpdir.mkdir("incoming") wals_dir = tmpdir.join("wal") wals_dir.mksymlinkto(incoming_dir.strpath) c = build_config_from_dicts(global_conf=None, main_conf={ 'basebackups_directory': incoming_dir.strpath, 'incoming_wals_directory': incoming_dir.strpath, 'wals_directory': wals_dir.strpath, 'backup_directory': tmpdir.strpath, }) c._populate_servers() # If there is one or more path errors are present, # the msg_list of the 'main' server is populated during # the creation of the server configuration object assert len(c._servers['main'].msg_list) == 2 symlink = 0 for msg in c._servers['main'].msg_list: # Check for symlinks presence if "(symlink to: " in msg: symlink += 1 assert symlink == 1
def test_csv_values_invalid_server_value(self, out_mock): """ test case global: backup_options = exclusive_backup server: backup_options = none_of_your_business result = backup_options = exclusive_backup The 'none_of_your_business' value on server section, is not an allowed value for the BackupOptions class, We expect to the config builder to fallback to the global 'exclusive_backup' value """ # add backup_options to minimal configuration string c = build_config_from_dicts( global_conf={ 'archiver': 'on', 'backup_options': BackupOptions.EXCLUSIVE_BACKUP }, main_conf={'backup_options': 'none_of_your_business'}) main = c.get_server('main') # create the expected dictionary expected = build_config_dictionary({ 'config': main.config, 'backup_options': set([BackupOptions.EXCLUSIVE_BACKUP]) }) assert main.__dict__ == expected # use the mocked output class to verify the presence of the warning # for a bad configuration parameter out_mock.warning.assert_called_with( "Ignoring invalid configuration " "value '%s' for key %s in %s: %s", 'none_of_your_business', 'backup_options', '[main] section', mock.ANY)
def test_recover_one_target(self, get_server_mock, parse_backup_id_mock, monkeypatch, capsys): backup_info = Mock() backup_info.status = BackupInfo.DONE backup_info.tablespaces = [] parse_backup_id_mock.return_value = backup_info monkeypatch.setattr( barman, '__config__', build_config_from_dicts(main_conf={ 'archiver': 'on', })) # This parameters are fine args = Mock() args.backup_id = '20170823T104400' args.server_name = 'main' args.destination_directory = 'recovery_dir' args.tablespace = None args.target_name = None args.target_tli = None args.target_immediate = True args.target_time = None args.target_xid = None _, err = capsys.readouterr() with pytest.raises(SystemExit): recover(args) assert "" == err
def test_populate_servers(self): """ Test for the presence of conflicting paths in configuration between all the servers """ c = build_config_from_dicts( global_conf=None, main_conf={ 'basebackups_directory': '/some/barman/home/main/base', 'incoming_wals_directory': '/some/barman/home/main/incoming', 'wals_directory': '/some/barman/home/main/wals', 'backup_directory': '/some/barman/home/main', }, test_conf={ 'basebackups_directory': '/some/barman/home/test/wals', 'incoming_wals_directory': '/some/barman/home/main/incoming', 'wals_directory': '/some/barman/home/main/wals', 'backup_directory': '/some/barman/home/main', }) # attribute servers_msg_list is empty before _populate_server() assert len(c.servers_msg_list) == 0 c._populate_servers() # after _populate_servers() if there is a global paths error # servers_msg_list is created in configuration assert c.servers_msg_list assert len(c.servers_msg_list) == 4
def test_get_server_list_global_error_continue(self, monkeypatch): """ Test the population of the list of global errors for diagnostic purposes (diagnose invocation) :param monkeypatch monkeypatch: pytest patcher """ monkeypatch.setattr( barman, "__config__", build_config_from_dicts( global_conf=None, main_conf={ "backup_directory": "/some/barman/home/main", "archiver": "on", }, test_conf={ "backup_directory": "/some/barman/home/main", "archiver": "on", }, ), ) server_dict = get_server_list(on_error_stop=False) global_error_list = barman.__config__.servers_msg_list # Check for the presence of servers assert server_dict # Check for the presence of global errors assert global_error_list assert len(global_error_list) == 6
def test_populate_servers_following_symlink(self, tmpdir): """ Test for the presence of conflicting paths in configuration between all the servers """ incoming_dir = tmpdir.mkdir("incoming") wals_dir = tmpdir.join("wal") wals_dir.mksymlinkto(incoming_dir.strpath) c = build_config_from_dicts( global_conf=None, main_conf={ 'basebackups_directory': incoming_dir.strpath, 'incoming_wals_directory': incoming_dir.strpath, 'wals_directory': wals_dir.strpath, 'backup_directory': tmpdir.strpath, }) c._populate_servers() # If there is one or more path errors are present, # the msg_list of the 'main' server is populated during # the creation of the server configuration object assert len(c._servers['main'].msg_list) == 2 symlink = 0 for msg in c._servers['main'].msg_list: # Check for symlinks presence if "(symlink to: " in msg: symlink += 1 assert symlink == 1
def test_server_conflict_paths(self): """ Test for the presence of conflicting paths for a server """ # Build a configuration with conflicts: # basebackups_directory = /some/barman/home/main/wals # wals_directory = /some/barman/home/main/wals c = build_config_from_dicts(main_conf={ 'archiver': 'on', 'basebackups_directory': '/some/barman/home/main/wals', 'description': ' Text with quotes ', }) main = c.get_server('main') # create the expected dictionary expected = build_config_dictionary({ 'config': main.config, 'disabled': True, 'basebackups_directory': '/some/barman/home/main/wals', 'msg_list': [ 'Conflicting path: wals_directory=/some/barman/home/main/wals ' 'conflicts with \'basebackups_directory\' ' 'for server \'main\''], 'description': 'Text with quotes', }) assert main.__dict__ == expected
def test_get_server_list_global_error_continue(self, monkeypatch): """ Test the population of the list of global errors for diagnostic purposes (diagnose invocation) :param monkeypatch monkeypatch: pytest patcher """ monkeypatch.setattr(barman, '__config__', build_config_from_dicts( global_conf=None, main_conf={ 'basebackups_directory': '/some/barman/home/main/base', 'incoming_wals_directory': '/some/barman/home/main/incoming', 'wals_directory': '/some/barman/home/main/wals', 'backup_directory': '/some/barman/home/main', }, test_conf={ 'basebackups_directory': '/some/barman/home/test/wals', 'incoming_wals_directory': '/some/barman/home/main/incoming', 'wals_directory': '/some/barman/home/main/wals', 'backup_directory': '/some/barman/home/main', })) server_dict = get_server_list(on_error_stop=False) global_error_list = barman.__config__.servers_msg_list # Check for the presence of servers assert server_dict # Check for the presence of global errors assert global_error_list assert len(global_error_list) == 4
def test_get_server_list(self, monkeypatch, capsys): """ Test the get_server_list method :param monkeypatch monkeypatch: pytest patcher """ monkeypatch.setattr(barman, '__config__', build_config_from_dicts()) server_dict = get_server_list() assert server_dict # Expect 2 test servers Main and Test assert len(server_dict) == 2 # Test the method with global errors monkeypatch.setattr( barman, '__config__', build_config_from_dicts( global_conf=None, main_conf={ 'basebackups_directory': '/some/barman/home/main/base', 'incoming_wals_directory': '/some/barman/home/main/incoming', 'wals_directory': '/some/barman/home/main/wals', 'backup_directory': '/some/barman/home/main', 'archiver': 'on', }, test_conf={ 'basebackups_directory': '/some/barman/home/test/wals', 'incoming_wals_directory': '/some/barman/home/main/incoming', 'wals_directory': '/some/barman/home/main/wals', 'backup_directory': '/some/barman/home/main', 'archiver': 'on', })) # Expect the method to fail and exit with pytest.raises(SystemExit): get_server_list() out, err = capsys.readouterr() # Check for the presence of error messages assert err # Check paths in error messages assert 'Conflicting path: ' \ 'basebackups_directory=/some/barman/home/main/base' in err assert 'Conflicting path: ' \ 'incoming_wals_directory=/some/barman/home/main/incoming' in err assert 'Conflicting path: ' \ 'wals_directory=/some/barman/home/main/wals' in err assert 'Conflicting path: ' \ 'backup_directory=/some/barman/home/main' in err
def test_manage_server_command(self, monkeypatch, capsys): """ Test manage_server_command method checking the various types of error output :param monkeypatch monkeypatch: pytest patcher """ # Build a server with a config with path conflicts monkeypatch.setattr( barman, "__config__", build_config_from_dicts( main_conf=build_config_dictionary( { "wals_directory": "/some/barman/home/main/wals", "basebackups_directory": "/some/barman/home/main/wals", "archiver": "on", } ) ), ) server = Server(barman.__config__.get_server("main")) # Test a not blocking WARNING message manage_server_command(server) out, err = capsys.readouterr() # Expect an ERROR message because of conflicting paths assert "ERROR: Conflicting path" in err # Build a server with a config without path conflicts monkeypatch.setattr(barman, "__config__", build_config_from_dicts()) server = Server(barman.__config__.get_server("main")) # Set the server as not active server.config.active = False # Request to treat inactive as errors to_be_executed = manage_server_command(server, inactive_is_error=True) out, err = capsys.readouterr() # Expect a ERROR message because of a not active server assert "ERROR: Inactive server" in err assert not to_be_executed # Request to treat inactive as warning to_be_executed = manage_server_command(server, inactive_is_error=False) out, err = capsys.readouterr() # Expect no error whatsoever assert err == "" assert not to_be_executed
def test_init(self): """ Basic initialization test with minimal parameters """ server = Server(build_config_from_dicts( global_conf={ 'archiver': 'on' }).get_server('main')) assert not server.config.disabled
def test_bad_init(self): """ Check the server is buildable with an empty configuration """ server = Server( build_config_from_dicts(main_conf={ 'conninfo': '', 'ssh_command': '', }).get_server('main')) assert server.config.disabled
def test_get_server_list(self, monkeypatch, capsys): """ Test the get_server_list method :param monkeypatch monkeypatch: pytest patcher """ monkeypatch.setattr(barman, '__config__', build_config_from_dicts()) server_dict = get_server_list() assert server_dict # Expect 2 test servers Main and Test assert len(server_dict) == 2 # Test the method with global errors monkeypatch.setattr(barman, '__config__', build_config_from_dicts( global_conf=None, main_conf={ 'basebackups_directory': '/some/barman/home/main/base', 'incoming_wals_directory': '/some/barman/home/main/incoming', 'wals_directory': '/some/barman/home/main/wals', 'backup_directory': '/some/barman/home/main', 'archiver': 'on', }, test_conf={ 'basebackups_directory': '/some/barman/home/test/wals', 'incoming_wals_directory': '/some/barman/home/main/incoming', 'wals_directory': '/some/barman/home/main/wals', 'backup_directory': '/some/barman/home/main', 'archiver': 'on', })) # Expect the method to fail and exit with pytest.raises(SystemExit): get_server_list() out, err = capsys.readouterr() # Check for the presence of error messages assert err # Check paths in error messages assert 'Conflicting path: ' \ 'basebackups_directory=/some/barman/home/main/base' in err assert 'Conflicting path: ' \ 'incoming_wals_directory=/some/barman/home/main/incoming' in err assert 'Conflicting path: ' \ 'wals_directory=/some/barman/home/main/wals' in err assert 'Conflicting path: ' \ 'backup_directory=/some/barman/home/main' in err
def test_bad_init(self): """ Check the server is buildable with an empty configuration """ server = Server(build_config_from_dicts( main_conf={ 'conninfo': '', 'ssh_command': '', } ).get_server('main')) assert server.config.disabled
def test_manage_server_command(self, monkeypatch, capsys): """ Test manage_server_command method checking the various types of error output :param monkeypatch monkeypatch: pytest patcher """ # Build a server with a config with path conflicts monkeypatch.setattr(barman, '__config__', build_config_from_dicts( main_conf=build_config_dictionary({ 'wals_directory': '/some/barman/home/main/wals', 'basebackups_directory': '/some/barman/home/main/wals', 'archiver': 'on', }))) server = Server(barman.__config__.get_server('main')) # Test a not blocking WARNING message manage_server_command(server) out, err = capsys.readouterr() # Expect an ERROR message because of conflicting paths assert 'ERROR: Conflicting path' in err # Build a server with a config without path conflicts monkeypatch.setattr(barman, '__config__', build_config_from_dicts()) server = Server(barman.__config__.get_server('main')) # Set the server as not active server.config.active = False # Request to treat inactive as errors to_be_executed = manage_server_command(server, inactive_is_error=True) out, err = capsys.readouterr() # Expect a ERROR message because of a not active server assert 'ERROR: Inactive server' in err assert not to_be_executed # Request to treat inactive as warning to_be_executed = manage_server_command(server, inactive_is_error=False) out, err = capsys.readouterr() # Expect no error whatsoever assert err == '' assert not to_be_executed
def test_check_config_missing(self): """ Verify the check method can be called on an empty configuration """ server = Server(build_config_from_dicts( main_conf={ 'conninfo': '', 'ssh_command': '', } ).get_server('main')) check_strategy = CheckOutputStrategy() server.check(check_strategy) assert check_strategy.has_error
def test_get_server(self, monkeypatch): """ Test the get_server method, providing a basic configuration :param monkeypatch monkeypatch: pytest patcher """ # Mock the args from argparse args = Mock() args.server_name = 'main' monkeypatch.setattr(barman, '__config__', build_config_from_dicts()) server_main = get_server(args) # Expect the server to exists assert server_main # Expect the name to be the right one assert server_main.config.name == 'main'
def setup_method(self, method): self.test_config = build_config_from_dicts( global_conf=None, main_conf={ 'backup_directory': '/some/barman/home/main', 'archiver': 'on', }, test_conf={ 'backup_directory': '/some/barman/home/main', 'archiver': 'on', }) self.test_config_with_pwd = build_config_from_dicts( global_conf=None, main_conf={ 'backup_directory': '/some/barman/home/main', 'conninfo': 'host=pg01.nowhere user=postgres password=testpassword', 'archiver': 'on', }, test_conf={ 'backup_directory': '/some/barman/home/main', 'archiver': 'on', })
def _create_mock_config(self, tmpdir): """Helper for passive node tests which returns a mock config object""" barman_home = tmpdir.mkdir("barman_home") backup_dir = barman_home.mkdir("main") wals_dir = backup_dir.mkdir("wals") # Build the configuration for the server using # a fake configuration object filled with test values return build_config_from_dicts( global_conf=dict(barman_home=str(barman_home)), main_conf=dict( compression=None, wals_directory=str(wals_dir), primary_ssh_command="ssh fakeuser@fakehost", ), )
def test_get_server_global_error_list(self, monkeypatch, capsys): """ Test the management of multiple servers and the presence of global errors :param monkeypatch monkeypatch: pytest patcher """ args = Mock() args.server_name = "main" # Build 2 servers with shared path. monkeypatch.setattr( barman, "__config__", build_config_from_dicts( global_conf=None, main_conf={ "basebackups_directory": "/some/barman/home/main/base", "incoming_wals_directory": "/some/barman/home/main/incoming", "wals_directory": "/some/barman/home/main/wals", "backup_directory": "/some/barman/home/main", "archiver": "on", }, test_conf={ "basebackups_directory": "/some/barman/home/test/wals", "incoming_wals_directory": "/some/barman/home/main/incoming", "wals_directory": "/some/barman/home/main/wals", "backup_directory": "/some/barman/home/main", "archiver": "on", }, ), ) # Expect a conflict because of the shared paths with pytest.raises(SystemExit): get_server(args) out, err = capsys.readouterr() # Check for the presence of error messages assert err # Check paths in error messages assert ( "Conflicting path: " "basebackups_directory=/some/barman/home/main/base" in err ) assert ( "Conflicting path: " "incoming_wals_directory=/some/barman/home/main/incoming" in err ) assert "Conflicting path: wals_directory=/some/barman/home/main/wals" in err assert "Conflicting path: backup_directory=/some/barman/home/main" in err
def test_get_server_global_error_list(self, monkeypatch, capsys): """ Test the management of multiple servers and the presence of global errors :param monkeypatch monkeypatch: pytest patcher """ args = Mock() args.server_name = 'main' # Build 2 servers with shared path. monkeypatch.setattr( barman, '__config__', build_config_from_dicts( global_conf=None, main_conf={ 'basebackups_directory': '/some/barman/home/main/base', 'incoming_wals_directory': '/some/barman/home/main/incoming', 'wals_directory': '/some/barman/home/main/wals', 'backup_directory': '/some/barman/home/main', 'archiver': 'on', }, test_conf={ 'basebackups_directory': '/some/barman/home/test/wals', 'incoming_wals_directory': '/some/barman/home/main/incoming', 'wals_directory': '/some/barman/home/main/wals', 'backup_directory': '/some/barman/home/main', 'archiver': 'on', })) # Expect a conflict because of the shared paths with pytest.raises(SystemExit): get_server(args) out, err = capsys.readouterr() # Check for the presence of error messages assert err # Check paths in error messages assert 'Conflicting path: ' \ 'basebackups_directory=/some/barman/home/main/base' in err assert 'Conflicting path: ' \ 'incoming_wals_directory=/some/barman/home/main/incoming' in err assert 'Conflicting path: ' \ 'wals_directory=/some/barman/home/main/wals' in err assert 'Conflicting path: ' \ 'backup_directory=/some/barman/home/main' in err
def test_list(self, tmpdir): """ Test the list method from the ProjectManager class """ config = build_config_from_dicts({ 'barman_lock_directory': tmpdir.strpath}) config.name = 'main' with ServerWalReceiveLock(tmpdir.strpath, 'main'): pm = ProcessManager(config) process = pm.list('receive-wal')[0] assert process.server_name == 'main' assert process.task == 'receive-wal' with open(os.path.join( tmpdir.strpath, '.%s-receive-wal.lock' % config.name)) as lockfile: pid = lockfile.read().strip() assert int(pid) == process.pid
def test_list(self, tmpdir): """ Test the list method from the ProjectManager class """ config = build_config_from_dicts( {'barman_lock_directory': tmpdir.strpath}) config.name = 'main' with ServerWalReceiveLock(tmpdir.strpath, 'main'): pm = ProcessManager(config) process = pm.list('receive-wal')[0] assert process.server_name == 'main' assert process.task == 'receive-wal' with open( os.path.join(tmpdir.strpath, '.%s-receive-wal.lock' % config.name)) as lockfile: pid = lockfile.read().strip() assert int(pid) == process.pid
def test_kill(self, kill_mock, tmpdir): """ Test the Kill method from the ProjectManager class. Mocks the os.kill used inside the the kill method """ config = build_config_from_dicts( {"barman_lock_directory": tmpdir.strpath}) config.name = "main" # Acquire a lock, simulating a running process with ServerWalReceiveLock(tmpdir.strpath, "main"): # Build a ProcessManager and retrieve the receive-wal process pm = ProcessManager(config) pi = pm.list("receive-wal")[0] # Exit at the first invocation of kill (this is a failed kill) kill_mock.side_effect = OSError(errno.EPERM, "", "") kill = pm.kill(pi) # Expect the kill result to be false assert kill is False assert kill_mock.call_count == 1 kill_mock.assert_called_with(pi.pid, 2) kill_mock.reset_mock() # Exit at the second invocation of kill (this is a successful kill) kill_mock.side_effect = [None, OSError(errno.ESRCH, "", "")] # Expect the kill result to be true kill = pm.kill(pi) assert kill assert kill_mock.call_count == 2 kill_mock.assert_has_calls( [mock.call(pi.pid, 2), mock.call(pi.pid, 0)]) kill_mock.reset_mock() # Check for the retry feature. exit at the second iteration of the # kill cycle kill_mock.side_effect = [None, None, OSError(errno.ESRCH, "", "")] kill = pm.kill(pi) assert kill assert kill_mock.call_count == 3 kill_mock.assert_has_calls([ mock.call(pi.pid, 2), mock.call(pi.pid, 0), mock.call(pi.pid, 0) ])
def test_check_config_missing(self, tmpdir): """ Verify the check method can be called on an empty configuration """ server = Server(build_config_from_dicts( global_conf={ # Required by server.check_archive method "barman_lock_directory": tmpdir.mkdir('lock').strpath }, main_conf={ 'conninfo': '', 'ssh_command': '', # Required by server.check_archive method 'wals_directory': tmpdir.mkdir('wals').strpath, } ).get_server('main')) check_strategy = CheckOutputStrategy() server.check(check_strategy) assert check_strategy.has_error
def test_csv_values_global_concurrent(self): """ test case global value: backup_options = concurrent_backup expected: backup_options = concurrent_backup Simple test for concurrent_backup option parsing """ # add backup_options to minimal configuration string c = build_config_from_dicts( {'backup_options': BackupOptions.CONCURRENT_BACKUP}, None) main = c.get_server('main') # create the expected dictionary expected = build_config_dictionary({ 'config': main.config, 'backup_options': set(['concurrent_backup']), }) assert main.__dict__ == expected
def test_csv_values_global_exclusive(self): """ test case global value: backup_options = exclusive_backup server value: backup_options = expected: backup_options = exclusive_backup Empty value is not allowed in BackupOptions class, so we expect the configuration parser to fall back to the global value. """ # add backup_options configuration to minimal configuration string c = build_config_from_dicts( {'backup_options': BackupOptions.EXCLUSIVE_BACKUP}, {'backup_options': ''}) main = c.get_server('main') # create the expected dictionary expected = build_config_dictionary({'config': main.config}) assert main.__dict__ == expected
def test_get_server_global_error_list(self, monkeypatch, capsys): """ Test the management of multiple servers and the presence of global errors :param monkeypatch monkeypatch: pytest patcher """ args = Mock() args.server_name = 'main' # Build 2 servers with shared path. monkeypatch.setattr(barman, '__config__', build_config_from_dicts( global_conf=None, main_conf={ 'basebackups_directory': '/some/barman/home/main/base', 'incoming_wals_directory': '/some/barman/home/main/incoming', 'wals_directory': '/some/barman/home/main/wals', 'backup_directory': '/some/barman/home/main', 'archiver': 'on', }, test_conf={ 'basebackups_directory': '/some/barman/home/test/wals', 'incoming_wals_directory': '/some/barman/home/main/incoming', 'wals_directory': '/some/barman/home/main/wals', 'backup_directory': '/some/barman/home/main', 'archiver': 'on', })) # Expect a conflict because of the shared paths with pytest.raises(SystemExit): get_server(args) out, err = capsys.readouterr() # Check for the presence of error messages assert err # Check paths in error messages assert 'Conflicting path: ' \ 'basebackups_directory=/some/barman/home/main/base' in err assert 'Conflicting path: ' \ 'incoming_wals_directory=/some/barman/home/main/incoming' in err assert 'Conflicting path: ' \ 'wals_directory=/some/barman/home/main/wals' in err assert 'Conflicting path: ' \ 'backup_directory=/some/barman/home/main' in err
def test_kill(self, kill_mock, tmpdir): """ Test the Kill method from the ProjectManager class. Mocks the os.kill used inside the the kill method """ config = build_config_from_dicts({ 'barman_lock_directory': tmpdir.strpath}) config.name = 'main' # Acquire a lock, simulating a running process with ServerWalReceiveLock(tmpdir.strpath, 'main'): # Build a ProcessManager and retrieve the receive-wal process pm = ProcessManager(config) pi = pm.list('receive-wal')[0] # Exit at the first invocation of kill (this is a failed kill) kill_mock.side_effect = OSError(errno.EPERM, '', '') kill = pm.kill(pi) # Expect the kill result to be false assert kill is False assert kill_mock.call_count == 1 kill_mock.assert_called_with(pi.pid, 2) kill_mock.reset_mock() # Exit at the second invocation of kill (this is a successful kill) kill_mock.side_effect = [None, OSError(errno.ESRCH, '', '')] # Expect the kill result to be true kill = pm.kill(pi) assert kill assert kill_mock.call_count == 2 kill_mock.assert_has_calls([mock.call(pi.pid, 2), mock.call(pi.pid, 0)]) kill_mock.reset_mock() # Check for the retry feature. exit at the second iteration of the # kill cycle kill_mock.side_effect = [None, None, OSError(errno.ESRCH, '', '')] kill = pm.kill(pi) assert kill assert kill_mock.call_count == 3 kill_mock.assert_has_calls([mock.call(pi.pid, 2), mock.call(pi.pid, 0), mock.call(pi.pid, 0)])
def test_csv_values_global_concurrent(self): """ test case global value: backup_options = concurrent_backup expected: backup_options = concurrent_backup Simple test for concurrent_backup option parsing """ # add backup_options to minimal configuration string c = build_config_from_dicts( {'backup_options': BackupOptions.CONCURRENT_BACKUP}, None) main = c.get_server('main') expected = dict(config=c) expected.update(MINIMAL_CONFIG_MAIN) # override the backup_options value in the expected dictionary expected['backup_options'] = BackupOptions( BackupOptions.CONCURRENT_BACKUP, "", "") assert main.__dict__ == expected
def test_check_config_missing(self, tmpdir): """ Verify the check method can be called on an empty configuration """ server = Server( build_config_from_dicts( global_conf={ # Required by server.check_archive method "barman_lock_directory": tmpdir.mkdir("lock").strpath }, main_conf={ "conninfo": "", "ssh_command": "", # Required by server.check_archive method "wals_directory": tmpdir.mkdir("wals").strpath, }, ).get_server("main") ) check_strategy = CheckOutputStrategy() server.check(check_strategy) assert check_strategy.has_error
def test_invalid_option_output(self, out_mock): """ Test the config behavior with unknown options """ # build a configuration with a a server and a global unknown vale. then # add them to the minimal configuration. c = build_config_from_dicts({'test_global_option': 'invalid_value'}, {'test_server_option': 'invalid_value'}) c.validate_global_config() # use the mocked output class to verify the presence of the warning # for a unknown configuration parameter in the barman subsection out_mock.warning.assert_called_with( 'Invalid configuration option "%s" in [%s] section.', 'test_global_option', 'barman') # parse main section c.get_server('main') # use the mocked output class to verify the presence of the warning # for a unknown configuration parameter in the server subsection out_mock.warning.assert_called_with( 'Invalid configuration option "%s" in [%s] section.', 'test_server_option', 'main')
def test_invalid_option_output(self, out_mock): """ Test the config behavior with unknown options """ # build a configuration with a a server and a global unknown vale. then # add them to the minimal configuration. c = build_config_from_dicts( {'test_global_option': 'invalid_value'}, {'test_server_option': 'invalid_value'}) c.validate_global_config() # use the mocked output class to verify the presence of the warning # for a unknown configuration parameter in the barman subsection out_mock.warning.assert_called_with( 'Invalid configuration option "%s" in [%s] section.', 'test_global_option', 'barman') # parse main section c.get_server('main') # use the mocked output class to verify the presence of the warning # for a unknown configuration parameter in the server subsection out_mock.warning.assert_called_with( 'Invalid configuration option "%s" in [%s] section.', 'test_server_option', 'main')
def test_init(self): """ Basic initialization test with minimal parameters """ Server(build_config_from_dicts().get_server('main'))