def test_load_config(self): daemon = MCRunner( config_file=self.config_file.name, pid_file=self.pid_file.name ) daemon.load_config() assert daemon.log_file == '/var/log/mcrunner/mcrunnerd.log' assert daemon.sock_file == '/tmp/mcrunner.sock' assert len(daemon.servers) == 2 survival = daemon.servers['survival'] creative = daemon.servers['creative'] assert survival.name == 'survival' assert survival.path == '/path/to/server1' assert survival.jar == 'spigot.jar' assert survival.opts == '-Xms1G -Xmx8G' assert creative.name == 'creative' assert creative.path == '/path/to/server2' assert creative.jar == 'craftbukkit.jar' assert creative.opts == '-Xms8G -Xmx16G'
def _set_up_daemon(self): self.logger = mock.MagicMock() with mock.patch.object(MCRunner, 'setup_logger'): self.daemon = MCRunner(config_file=self.config_file.name, pid_file=self.pid_file.name) return self.daemon
def test_create_logger(self): daemon = MCRunner( config_file=self.config_file.name, pid_file=self.pid_file.name ) daemon.load_config() with tempfile.NamedTemporaryFile() as f: daemon.log_file = f.name logger = daemon.create_logger() assert isinstance(logger, logging.getLoggerClass())
def test_get_status(self): daemon = MCRunner( config_file=self.config_file.name, pid_file=self.pid_file.name ) daemon.load_config() daemon.servers['survival'].get_status = mock.MagicMock(return_value='some status') daemon.servers['creative'].get_status = mock.MagicMock(return_value='some other status') status = daemon.get_status() assert status[0] is True assert 'survival: some status' in status[1] assert 'creative: some other status' in status[1]
def _set_up_daemon(self): self.logger = mock.MagicMock() with mock.patch.object(MCRunner, 'create_logger', return_value=self.logger): self.daemon = MCRunner( config_file=self.config_file.name, pid_file=self.pid_file.name ) return self.daemon
def test_socket_server_os_error(self): daemon = MCRunner( config_file=self.config_file.name, pid_file=self.pid_file.name ) daemon.sock_file = self.sock_file.name mock_sock = mock.MagicMock() with mock.patch.object(os, 'unlink', side_effect=OSError): with mock.patch('socket.socket', return_value=mock_sock) as MockSocket: sock = daemon.socket_server() assert MockSocket.call_count == 1 assert MockSocket.call_args[0] == (socket.AF_UNIX, socket.SOCK_STREAM) assert sock == mock_sock assert mock_sock.bind.call_count == 1 assert mock_sock.bind.call_args[0] == (self.sock_file.name,) assert mock_sock.listen.call_count == 1 assert mock_sock.listen.call_args[0] == (1,)
def _set_up_daemon_with_recv(self, recv_list): self.daemon = MCRunner( config_file=self.config_file.name, pid_file=self.pid_file.name ) mock_sock = mock.MagicMock() self.mock_conn = mock.MagicMock() mock_sock.accept = mock.MagicMock(return_value=( self.mock_conn, 'address' )) self.mock_conn.recv = mock.MagicMock(side_effect=recv_list) self.mock_logger = mock.MagicMock() self.daemon.create_logger = mock.MagicMock(return_value=self.mock_logger) self.daemon.socket_server = mock.MagicMock(return_value=mock_sock)
def test_on_exit(self): daemon = MCRunner( config_file=self.config_file.name, pid_file=self.pid_file.name ) daemon.load_config() daemon.logger = mock.MagicMock() daemon.servers['survival'].stop = mock.MagicMock() daemon.servers['creative'].stop = mock.MagicMock() daemon.on_exit() assert daemon.servers['survival'].stop.call_count == 1 assert daemon.servers['creative'].stop.call_count == 1
class MCRunnerTestCase(unittest.TestCase): def setUp(self): self.config_file = tempfile.NamedTemporaryFile() self.config_file.write(TEST_CONFIG) self.config_file.flush() self.pid_file = tempfile.NamedTemporaryFile() self.sock_file = tempfile.NamedTemporaryFile() def tearDown(self): self.config_file.close() self.pid_file.close() self.sock_file.close() def _set_up_daemon_with_recv(self, recv_list): self.daemon = MCRunner( config_file=self.config_file.name, pid_file=self.pid_file.name ) mock_sock = mock.MagicMock() self.mock_conn = mock.MagicMock() mock_sock.accept = mock.MagicMock(return_value=( self.mock_conn, 'address' )) self.mock_conn.recv = mock.MagicMock(side_effect=recv_list) self.mock_logger = mock.MagicMock() self.daemon.create_logger = mock.MagicMock(return_value=self.mock_logger) self.daemon.socket_server = mock.MagicMock(return_value=mock_sock) def test_load_config(self): daemon = MCRunner( config_file=self.config_file.name, pid_file=self.pid_file.name ) daemon.load_config() assert daemon.log_file == '/var/log/mcrunner/mcrunnerd.log' assert daemon.sock_file == '/tmp/mcrunner.sock' assert len(daemon.servers) == 2 survival = daemon.servers['survival'] creative = daemon.servers['creative'] assert survival.name == 'survival' assert survival.path == '/path/to/server1' assert survival.jar == 'spigot.jar' assert survival.opts == '-Xms1G -Xmx8G' assert creative.name == 'creative' assert creative.path == '/path/to/server2' assert creative.jar == 'craftbukkit.jar' assert creative.opts == '-Xms8G -Xmx16G' def test_socket_server(self): daemon = MCRunner( config_file=self.config_file.name, pid_file=self.pid_file.name ) daemon.sock_file = self.sock_file.name mock_sock = mock.MagicMock() with mock.patch.object(os, 'unlink'): with mock.patch('socket.socket', return_value=mock_sock) as MockSocket: sock = daemon.socket_server() assert MockSocket.call_count == 1 assert MockSocket.call_args[0] == (socket.AF_UNIX, socket.SOCK_STREAM) assert sock == mock_sock assert mock_sock.bind.call_count == 1 assert mock_sock.bind.call_args[0] == (self.sock_file.name,) assert mock_sock.listen.call_count == 1 assert mock_sock.listen.call_args[0] == (1,) def test_socket_server_os_error(self): daemon = MCRunner( config_file=self.config_file.name, pid_file=self.pid_file.name ) daemon.sock_file = self.sock_file.name mock_sock = mock.MagicMock() with mock.patch.object(os, 'unlink', side_effect=OSError): with mock.patch('socket.socket', return_value=mock_sock) as MockSocket: sock = daemon.socket_server() assert MockSocket.call_count == 1 assert MockSocket.call_args[0] == (socket.AF_UNIX, socket.SOCK_STREAM) assert sock == mock_sock assert mock_sock.bind.call_count == 1 assert mock_sock.bind.call_args[0] == (self.sock_file.name,) assert mock_sock.listen.call_count == 1 assert mock_sock.listen.call_args[0] == (1,) def test_create_logger(self): daemon = MCRunner( config_file=self.config_file.name, pid_file=self.pid_file.name ) daemon.load_config() with tempfile.NamedTemporaryFile() as f: daemon.log_file = f.name logger = daemon.create_logger() assert isinstance(logger, logging.getLoggerClass()) def test_get_status(self): daemon = MCRunner( config_file=self.config_file.name, pid_file=self.pid_file.name ) daemon.load_config() daemon.servers['survival'].get_status = mock.MagicMock(return_value='some status') daemon.servers['creative'].get_status = mock.MagicMock(return_value='some other status') status = daemon.get_status() assert status[0] is True assert 'survival: some status' in status[1] assert 'creative: some other status' in status[1] def test_on_exit(self): daemon = MCRunner( config_file=self.config_file.name, pid_file=self.pid_file.name ) daemon.load_config() daemon.logger = mock.MagicMock() daemon.servers['survival'].stop = mock.MagicMock() daemon.servers['creative'].stop = mock.MagicMock() daemon.on_exit() assert daemon.servers['survival'].stop.call_count == 1 assert daemon.servers['creative'].stop.call_count == 1 def test_run_no_message(self): self._set_up_daemon_with_recv([ 'some data', SystemExit ]) self.daemon.run() assert self.mock_conn.sendall.call_count == 1 assert self.mock_conn.sendall.call_args[0] == (str(COMMAND_RESPONSE_STATUSES['DONE']),) def test_run_socket_error(self): self._set_up_daemon_with_recv([ socket.error, SystemExit ]) self.daemon.run() assert self.mock_logger.exception.call_count == 1 assert self.mock_logger.exception.call_args[0] == ('Error during socket connection',) def test_run_status(self): self._set_up_daemon_with_recv([ 'status', SystemExit ]) self.daemon.get_status = mock.MagicMock(return_value=( True, 'some status' )) self.daemon.run() assert self.daemon.get_status.call_count == 1 assert self.mock_conn.sendall.call_count == 2 assert self.mock_conn.sendall.call_args_list[0][0] == (str(COMMAND_RESPONSE_STATUSES['MESSAGE']),) assert self.mock_conn.sendall.call_args_list[1][0] == ('some status',) assert self.mock_conn.close.call_count == 2 def test_run_with_start_server(self): self._set_up_daemon_with_recv([ 'start{}survival'.format(MCRUNNERD_COMMAND_DELIMITER), SystemExit ]) with mock.patch.object(MinecraftServer, 'start') as mock_start: self.daemon.run() assert mock_start.call_count == 1 assert self.mock_conn.sendall.call_count == 2 assert self.mock_conn.sendall.call_args_list[0][0] == (str(COMMAND_RESPONSE_STATUSES['MESSAGE']),) assert self.mock_conn.sendall.call_args_list[1][0] == ('Starting Minecraft server "survival"',) def test_run_with_start_invalid_server(self): self._set_up_daemon_with_recv([ 'start{}bad_server_name'.format(MCRUNNERD_COMMAND_DELIMITER), SystemExit ]) self.daemon.run() assert self.mock_conn.sendall.call_count == 2 assert self.mock_conn.sendall.call_args_list[0][0] == (str(COMMAND_RESPONSE_STATUSES['MESSAGE']),) assert self.mock_conn.sendall.call_args_list[1][0] == ('Minecraft server "bad_server_name" not defined',) def test_run_with_start_server_running(self): self._set_up_daemon_with_recv([ 'start{}survival'.format(MCRUNNERD_COMMAND_DELIMITER), SystemExit ]) with mock.patch.object(MinecraftServer, 'start', side_effect=ServerStartException('exc')) as mock_start: self.daemon.run() assert mock_start.call_count == 1 assert self.mock_conn.sendall.call_count == 2 assert self.mock_conn.sendall.call_args_list[0][0] == (str(COMMAND_RESPONSE_STATUSES['MESSAGE']),) assert self.mock_conn.sendall.call_args_list[1][0] == ('Could not start server! stderr:\n\nexc',) def test_run_with_stop_server(self): self._set_up_daemon_with_recv([ 'stop{}survival'.format(MCRUNNERD_COMMAND_DELIMITER), SystemExit ]) with mock.patch.object(MinecraftServer, 'stop') as mock_stop: self.daemon.run() assert mock_stop.call_count == 1 assert self.mock_conn.sendall.call_count == 2 assert self.mock_conn.sendall.call_args_list[0][0] == (str(COMMAND_RESPONSE_STATUSES['MESSAGE']),) assert self.mock_conn.sendall.call_args_list[1][0] == ('Stopping Minecraft server "survival"',) def test_run_with_stop_invalid_server(self): self._set_up_daemon_with_recv([ 'stop{}bad_server_name'.format(MCRUNNERD_COMMAND_DELIMITER), SystemExit ]) self.daemon.run() assert self.mock_conn.sendall.call_count == 2 assert self.mock_conn.sendall.call_args_list[0][0] == (str(COMMAND_RESPONSE_STATUSES['MESSAGE']),) assert self.mock_conn.sendall.call_args_list[1][0] == ('Minecraft server "bad_server_name" not defined',) def test_run_with_stop_server_not_running(self): self._set_up_daemon_with_recv([ 'stop{}survival'.format(MCRUNNERD_COMMAND_DELIMITER), SystemExit ]) with mock.patch.object(MinecraftServer, 'stop', side_effect=ServerNotRunningException) as mock_stop: self.daemon.run() assert mock_stop.call_count == 1 assert self.mock_conn.sendall.call_count == 2 assert self.mock_conn.sendall.call_args_list[0][0] == (str(COMMAND_RESPONSE_STATUSES['MESSAGE']),) assert self.mock_conn.sendall.call_args_list[1][0] == ('Minecraft server "survival" not running',) def test_run_with_command(self): self._set_up_daemon_with_recv([ 'command{delim}survival{delim}say test'.format(delim=MCRUNNERD_COMMAND_DELIMITER), SystemExit ]) with mock.patch.object(MinecraftServer, 'run_command') as mock_command: self.daemon.run() assert mock_command.call_count == 1 assert mock_command.call_args[0] == ('say test',) assert self.mock_conn.sendall.call_count == 2 assert self.mock_conn.sendall.call_args_list[0][0] == (str(COMMAND_RESPONSE_STATUSES['MESSAGE']),) assert self.mock_conn.sendall.call_args_list[1][0] == ('Sent command to Minecraft server "survival": "say test"',) def test_run_with_command_invalid_server(self): self._set_up_daemon_with_recv([ 'command{delim}bad_server_name{delim}say test'.format(delim=MCRUNNERD_COMMAND_DELIMITER), SystemExit ]) self.daemon.run() assert self.mock_conn.sendall.call_count == 2 assert self.mock_conn.sendall.call_args_list[0][0] == (str(COMMAND_RESPONSE_STATUSES['MESSAGE']),) assert self.mock_conn.sendall.call_args_list[1][0] == ('Minecraft server "bad_server_name" not defined',) def test_run_with_command_not_running(self): self._set_up_daemon_with_recv([ 'command{delim}survival{delim}say test'.format(delim=MCRUNNERD_COMMAND_DELIMITER), SystemExit ]) with mock.patch.object(MinecraftServer, 'run_command', side_effect=ServerNotRunningException) as mock_command: self.daemon.run() assert mock_command.call_count == 1 assert mock_command.call_args[0] == ('say test',) assert self.mock_conn.sendall.call_count == 2 assert self.mock_conn.sendall.call_args_list[0][0] == (str(COMMAND_RESPONSE_STATUSES['MESSAGE']),) assert self.mock_conn.sendall.call_args_list[1][0] == ('Minecraft server "survival" not running',)
class MCRunnerTestCase(unittest.TestCase): def setUp(self): self.config_file = tempfile.NamedTemporaryFile() self.config_file.write(TEST_CONFIG) self.config_file.flush() self.pid_file = tempfile.NamedTemporaryFile() self.sock_file = tempfile.NamedTemporaryFile() def tearDown(self): self.config_file.close() self.pid_file.close() self.sock_file.close() def _set_up_daemon(self): self.logger = mock.MagicMock() with mock.patch.object(MCRunner, 'create_logger', return_value=self.logger): self.daemon = MCRunner( config_file=self.config_file.name, pid_file=self.pid_file.name ) return self.daemon def _set_up_daemon_with_recv(self, recv_list): self._set_up_daemon() mock_sock = mock.MagicMock() mock_conn = mock.MagicMock() mock_sock.accept = mock.MagicMock(return_value=( mock_conn, 'address' )) self.daemon.socket_server = mock.MagicMock(return_value=mock_sock) self.mock_connection = mock.MagicMock() self.mock_connection.receive_message = mock.MagicMock(side_effect=recv_list) def _generate_mcrunnerd_patckage(self, *args): return MCRUNNERD_COMMAND_DELIMITER.join(args) def test_load_config(self): daemon = self._set_up_daemon() assert daemon.log_file == '/var/log/mcrunner/mcrunnerd.log' assert daemon.sock_file == '/tmp/mcrunner.sock' assert len(daemon.servers) == 2 survival = daemon.servers['survival'] creative = daemon.servers['creative'] assert survival.name == 'survival' assert survival.path == '/path/to/server1' assert survival.jar == 'spigot.jar' assert survival.opts == '-Xms1G -Xmx8G' assert creative.name == 'creative' assert creative.path == '/path/to/server2' assert creative.jar == 'craftbukkit.jar' assert creative.opts == '-Xms8G -Xmx16G' def test_socket_server(self): daemon = self._set_up_daemon() daemon.sock_file = self.sock_file.name mock_sock = mock.MagicMock() with mock.patch.object(os, 'unlink'): with mock.patch('socket.socket', return_value=mock_sock) as MockSocket: sock = daemon.socket_server() assert MockSocket.call_count == 1 assert MockSocket.call_args[0] == (socket.AF_UNIX, socket.SOCK_STREAM) assert sock == mock_sock assert mock_sock.bind.call_count == 1 assert mock_sock.bind.call_args[0] == (self.sock_file.name,) assert mock_sock.listen.call_count == 1 assert mock_sock.listen.call_args[0] == (1,) def test_socket_server_os_error(self): daemon = self._set_up_daemon() daemon.sock_file = self.sock_file.name mock_sock = mock.MagicMock() with mock.patch.object(os, 'unlink', side_effect=OSError): with mock.patch('socket.socket', return_value=mock_sock) as MockSocket: sock = daemon.socket_server() assert MockSocket.call_count == 1 assert MockSocket.call_args[0] == (socket.AF_UNIX, socket.SOCK_STREAM) assert sock == mock_sock assert mock_sock.bind.call_count == 1 assert mock_sock.bind.call_args[0] == (self.sock_file.name,) assert mock_sock.listen.call_count == 1 assert mock_sock.listen.call_args[0] == (1,) def test_create_logger(self): daemon = self._set_up_daemon() with tempfile.NamedTemporaryFile() as f: daemon.log_file = f.name logger = daemon.create_logger() assert isinstance(logger, logging.getLoggerClass()) def test_get_status(self): daemon = self._set_up_daemon() daemon.servers['survival'].get_status = mock.MagicMock(return_value='some status') daemon.servers['creative'].get_status = mock.MagicMock(return_value='some other status') mock_connection = mock.MagicMock() daemon.get_status(mock_connection) status = mock_connection.send_message.call_args[0][0] assert 'survival: some status' in status assert 'creative: some other status' in status def test_start_minecraft_server_exception(self): daemon = self._set_up_daemon() with mock.patch.object(MinecraftServer, 'start', side_effect=ServerStartException): daemon.start_minecraft_server('survival') def test_start_minecraft_server_invalid(self): daemon = self._set_up_daemon() daemon.start_minecraft_server('bad_server') def test_stop_minecraft_server(self): daemon = self._set_up_daemon() daemon.stop_minecraft_server('survival') def test_stop_minecraft_server_invalid(self): daemon = self._set_up_daemon() daemon.stop_minecraft_server('bad_server') def test_on_exit(self): daemon = self._set_up_daemon() daemon.servers['survival'].stop = mock.MagicMock() daemon.servers['creative'].stop = mock.MagicMock() daemon.on_exit() assert daemon.servers['survival'].stop.call_count == 1 assert daemon.servers['creative'].stop.call_count == 1 def test_set_uid(self): daemon = self._set_up_daemon() daemon.user = '******' with mock.patch('pwd.getpwnam', return_value=mock.MagicMock(pw_uid=1001)): with mock.patch('os.getuid', return_value=0): with mock.patch('os.setuid') as mock_setuid: daemon.set_uid() assert mock_setuid.call_count == 1 assert mock_setuid.call_args[0] == (1001,) def test_set_uid_self(self): daemon = self._set_up_daemon() daemon.user = '******' with mock.patch('pwd.getpwnam', return_value=mock.MagicMock(pw_uid=1001)): with mock.patch('os.getuid', return_value=1001): with mock.patch('os.setuid') as mock_setuid: daemon.set_uid() assert mock_setuid.call_count == 0 def test_set_uid_user_not_found(self): daemon = self._set_up_daemon() daemon.user = '******' with mock.patch('pwd.getpwnam', side_effect=KeyError): with self.assertRaises(SystemExit): daemon.set_uid() def test_set_uid_user_not_root(self): daemon = self._set_up_daemon() daemon.user = '******' with mock.patch('pwd.getpwnam', return_value=mock.MagicMock(pw_uid=1001)): with mock.patch('os.getuid', return_value=1002): with self.assertRaises(SystemExit): daemon.set_uid() def test_set_uid_failure(self): daemon = self._set_up_daemon() daemon.user = '******' with mock.patch('pwd.getpwnam', return_value=mock.MagicMock(pw_uid=1001)): with mock.patch('os.getuid', return_value=0): with mock.patch('os.setuid', side_effect=OSError): with self.assertRaises(SystemExit): daemon.set_uid() def test_run_no_message(self): self._set_up_daemon_with_recv([ 'some data', SystemExit ]) with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert self.mock_connection.receive_message.call_count == 2 assert self.mock_connection.send_message.call_count == 0 def test_run_socket_error(self): self._set_up_daemon_with_recv([ socket.error, SystemExit ]) with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert self.daemon.logger.exception.call_count == 1 assert self.daemon.logger.exception.call_args[0] == ('Error during socket connection',) def test_run_status(self): self._set_up_daemon_with_recv([ 'status', SystemExit ]) with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert self.mock_connection.send_message.call_count == 1 status = self.mock_connection.send_message.call_args[0][0] assert 'survival: Not running' in status assert 'creative: Not running' in status assert self.mock_connection.close.call_count == 2 def test_run_with_start_server(self): self._set_up_daemon_with_recv([ self._generate_mcrunnerd_patckage('start', 'survival'), SystemExit ]) with mock.patch.object(MinecraftServer, '_start_jar') as mock_start: with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert mock_start.call_count == 1 assert self.mock_connection.send_message.call_count == 2 assert self.mock_connection.send_message.call_args_list[0][0] == ('Starting server survival...',) assert self.mock_connection.send_message.call_args_list[1][0] == ('Server survival started.',) def test_run_with_start_invalid_server(self): self._set_up_daemon_with_recv([ self._generate_mcrunnerd_patckage('start', 'bad_server_name'), SystemExit ]) with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert self.mock_connection.send_message.call_count == 1 assert self.mock_connection.send_message.call_args[0] == ('Minecraft server "bad_server_name" not defined',) def test_run_with_start_server_running(self): self._set_up_daemon_with_recv([ self._generate_mcrunnerd_patckage('start', 'survival'), SystemExit ]) with mock.patch.object(MinecraftServer, 'start', side_effect=ServerStartException('reason')) as mock_start: with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert mock_start.call_count == 1 assert self.mock_connection.send_message.call_count == 1 assert self.mock_connection.send_message.call_args[0] == ('Could not start server! Reason: reason',) def test_run_with_restart_server(self): self._set_up_daemon_with_recv([ self._generate_mcrunnerd_patckage('restart', 'survival'), SystemExit ]) with mock.patch.object(MinecraftServer, 'pipe'): with mock.patch.object(MinecraftServer, 'run_command') as mock_run_command: with mock.patch.object(MinecraftServer, '_start_jar') as mock_start: with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert mock_start.call_count == 1 assert mock_run_command.call_count == 1 assert self.mock_connection.send_message.call_count == 4 assert self.mock_connection.send_message.call_args_list[0][0] == ('Stopping server survival...',) assert self.mock_connection.send_message.call_args_list[1][0] == ('Server survival stopped.',) assert self.mock_connection.send_message.call_args_list[2][0] == ('Starting server survival...',) assert self.mock_connection.send_message.call_args_list[3][0] == ('Server survival started.',) def test_run_with_stop_server(self): self._set_up_daemon_with_recv([ self._generate_mcrunnerd_patckage('stop', 'survival'), SystemExit ]) with mock.patch.object(MinecraftServer, 'pipe'): with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert self.mock_connection.send_message.call_count == 2 assert self.mock_connection.send_message.call_args_list[0][0] == ('Stopping server survival...',) assert self.mock_connection.send_message.call_args_list[1][0] == ('Server survival stopped.',) def test_run_with_stop_invalid_server(self): self._set_up_daemon_with_recv([ self._generate_mcrunnerd_patckage('stop', 'bad_server_name'), SystemExit ]) with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert self.mock_connection.send_message.call_count == 1 assert self.mock_connection.send_message.call_args[0] == ('Minecraft server "bad_server_name" not defined',) def test_run_with_stop_server_not_running(self): self._set_up_daemon_with_recv([ self._generate_mcrunnerd_patckage('stop', 'survival'), SystemExit ]) with mock.patch.object(MinecraftServer, 'stop', side_effect=ServerNotRunningException) as mock_stop: with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert mock_stop.call_count == 1 assert self.mock_connection.send_message.call_count == 1 assert self.mock_connection.send_message.call_args[0] == ('Minecraft server "survival" not running',) def test_run_with_command(self): self._set_up_daemon_with_recv([ self._generate_mcrunnerd_patckage('command', 'survival', 'say test'), SystemExit ]) with mock.patch.object(MinecraftServer, 'pipe'): with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert self.mock_connection.send_message.call_count == 1 assert self.mock_connection.send_message.call_args[0] == ('Sent command to Minecraft server "survival": "say test"',) def test_run_with_command_invalid_server(self): self._set_up_daemon_with_recv([ 'command{delim}bad_server_name{delim}say test'.format(delim=MCRUNNERD_COMMAND_DELIMITER), SystemExit ]) with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert self.mock_connection.send_message.call_count == 1 assert self.mock_connection.send_message.call_args[0] == ('Minecraft server "bad_server_name" not defined',) def test_run_with_command_not_running(self): self._set_up_daemon_with_recv([ self._generate_mcrunnerd_patckage('command', 'survival', 'say test'), SystemExit ]) with mock.patch.object(MinecraftServer, 'run_command', side_effect=ServerNotRunningException) as mock_command: with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert mock_command.call_count == 1 assert mock_command.call_args[0] == ('say test',) assert self.mock_connection.send_message.call_count == 1 assert self.mock_connection.send_message.call_args[0] == ('Minecraft server "survival" not running',)
class MCRunnerTestCase(unittest.TestCase): def setUp(self): self.config_file = tempfile.NamedTemporaryFile() self.config_file.write(TEST_CONFIG) self.config_file.flush() self.pid_file = tempfile.NamedTemporaryFile() self.sock_file = tempfile.NamedTemporaryFile() def tearDown(self): self.config_file.close() self.pid_file.close() self.sock_file.close() def _set_up_daemon(self): self.logger = mock.MagicMock() with mock.patch.object(MCRunner, 'setup_logger'): self.daemon = MCRunner(config_file=self.config_file.name, pid_file=self.pid_file.name) return self.daemon def _set_up_daemon_with_recv(self, recv_list): self._set_up_daemon() mock_sock = mock.MagicMock() mock_conn = mock.MagicMock() mock_sock.accept = mock.MagicMock(return_value=(mock_conn, 'address')) self.daemon.socket_server = mock.MagicMock(return_value=mock_sock) self.mock_connection = mock.MagicMock() self.mock_connection.receive_message = mock.MagicMock( side_effect=recv_list) def _generate_mcrunnerd_patckage(self, *args): return MCRUNNERD_COMMAND_DELIMITER.join(args) def test_load_config(self): daemon = self._set_up_daemon() assert daemon.log_file == '/var/log/mcrunner/mcrunnerd.log' assert daemon.sock_file == '/tmp/mcrunner.sock' assert len(daemon.servers) == 2 survival = daemon.servers['survival'] creative = daemon.servers['creative'] assert survival.name == 'survival' assert survival.path == '/path/to/server1' assert survival.jar == 'spigot.jar' assert survival.opts == '-Xms1G -Xmx8G' assert creative.name == 'creative' assert creative.path == '/path/to/server2' assert creative.jar == 'craftbukkit.jar' assert creative.opts == '-Xms8G -Xmx16G' def test_socket_server(self): daemon = self._set_up_daemon() daemon.sock_file = self.sock_file.name mock_sock = mock.MagicMock() with mock.patch.object(os, 'unlink'): with mock.patch('socket.socket', return_value=mock_sock) as MockSocket: sock = daemon.socket_server() assert MockSocket.call_count == 1 assert MockSocket.call_args[0] == (socket.AF_UNIX, socket.SOCK_STREAM) assert sock == mock_sock assert mock_sock.bind.call_count == 1 assert mock_sock.bind.call_args[0] == (self.sock_file.name, ) assert mock_sock.listen.call_count == 1 assert mock_sock.listen.call_args[0] == (1, ) def test_socket_server_os_error(self): daemon = self._set_up_daemon() daemon.sock_file = self.sock_file.name mock_sock = mock.MagicMock() with mock.patch.object(os, 'unlink', side_effect=OSError): with mock.patch('socket.socket', return_value=mock_sock) as MockSocket: sock = daemon.socket_server() assert MockSocket.call_count == 1 assert MockSocket.call_args[0] == (socket.AF_UNIX, socket.SOCK_STREAM) assert sock == mock_sock assert mock_sock.bind.call_count == 1 assert mock_sock.bind.call_args[0] == (self.sock_file.name, ) assert mock_sock.listen.call_count == 1 assert mock_sock.listen.call_args[0] == (1, ) def test_setup_logger(self): daemon = self._set_up_daemon() mock_logger = mock.MagicMock() with mock.patch('logging.handlers.RotatingFileHandler'): with mock.patch('logging.getLogger', return_value=mock_logger): daemon.setup_logger() assert mock_logger.addHandler.called assert mock_logger.setLevel.called def test_get_status(self): daemon = self._set_up_daemon() daemon.servers['survival'].get_status = mock.MagicMock( return_value=ServerStatus.RUNNING) daemon.servers['creative'].get_status = mock.MagicMock( return_value=ServerStatus.STOPPED) mock_connection = mock.MagicMock() daemon.get_status(mock_connection) status = mock_connection.send_message.call_args[0][0] assert 'survival: Running' in status assert 'creative: Stopped' in status def test_start_minecraft_server_exception(self): daemon = self._set_up_daemon() with mock.patch.object(MinecraftServer, 'start', side_effect=ServerStartException): daemon.start_minecraft_server('survival') def test_start_minecraft_server_invalid(self): daemon = self._set_up_daemon() daemon.start_minecraft_server('bad_server') def test_stop_minecraft_server(self): daemon = self._set_up_daemon() daemon.stop_minecraft_server('survival') def test_stop_minecraft_server_invalid(self): daemon = self._set_up_daemon() daemon.stop_minecraft_server('bad_server') def test_on_exit(self): daemon = self._set_up_daemon() daemon.servers['survival'].get_status = mock.MagicMock( return_value=ServerStatus.RUNNING) daemon.servers['survival'].stop = mock.MagicMock() daemon.servers['creative'].get_status = mock.MagicMock( return_value=ServerStatus.STOPPED) daemon.servers['creative'].stop = mock.MagicMock() daemon.on_exit() assert daemon.servers['survival'].stop.call_count == 1 assert daemon.servers['creative'].stop.call_count == 0 def test_set_uid(self): daemon = self._set_up_daemon() daemon.user = '******' with mock.patch('pwd.getpwnam', return_value=mock.MagicMock(pw_uid=1001)): with mock.patch('os.getuid', return_value=0): with mock.patch('os.setuid') as mock_setuid: daemon.set_uid() assert mock_setuid.call_count == 1 assert mock_setuid.call_args[0] == (1001, ) def test_set_uid_self(self): daemon = self._set_up_daemon() daemon.user = '******' with mock.patch('pwd.getpwnam', return_value=mock.MagicMock(pw_uid=1001)): with mock.patch('os.getuid', return_value=1001): with mock.patch('os.setuid') as mock_setuid: daemon.set_uid() assert mock_setuid.call_count == 0 def test_set_uid_user_not_found(self): daemon = self._set_up_daemon() daemon.user = '******' with mock.patch('pwd.getpwnam', side_effect=KeyError): with self.assertRaises(SystemExit): daemon.set_uid() def test_set_uid_user_not_root(self): daemon = self._set_up_daemon() daemon.user = '******' with mock.patch('pwd.getpwnam', return_value=mock.MagicMock(pw_uid=1001)): with mock.patch('os.getuid', return_value=1002): with self.assertRaises(SystemExit): daemon.set_uid() def test_set_uid_failure(self): daemon = self._set_up_daemon() daemon.user = '******' with mock.patch('pwd.getpwnam', return_value=mock.MagicMock(pw_uid=1001)): with mock.patch('os.getuid', return_value=0): with mock.patch('os.setuid', side_effect=OSError): with self.assertRaises(SystemExit): daemon.set_uid() @mock.patch('mcrunner.mcrunnerd.logger') def test_run_startup_socket_error(self, logger): self._set_up_daemon() self.daemon.socket_server = mock.MagicMock(side_effect=OSError) self.daemon.run() assert logger.exception.call_count == 1 assert logger.exception.call_args[0] == ( 'Could not start mcrunnerd: ', ) def test_run_no_message(self): self._set_up_daemon_with_recv(['some data', SystemExit]) with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert self.mock_connection.receive_message.call_count == 2 assert self.mock_connection.send_message.call_count == 0 @mock.patch('mcrunner.mcrunnerd.logger') def test_run_socket_error(self, logger): self._set_up_daemon_with_recv([socket.error, SystemExit]) with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert logger.exception.call_count == 1 assert logger.exception.call_args[0] == ( 'Error during socket connection', ) def test_run_status(self): self._set_up_daemon_with_recv(['status', SystemExit]) with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert self.mock_connection.send_message.call_count == 1 status = self.mock_connection.send_message.call_args[0][0] assert 'survival: Stopped' in status assert 'creative: Stopped' in status assert self.mock_connection.close.call_count == 2 def test_run_with_start_server(self): self._set_up_daemon_with_recv([ self._generate_mcrunnerd_patckage('start', 'survival'), SystemExit ]) with mock.patch.object(MinecraftServer, '_start_jar') as mock_start: with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert mock_start.call_count == 1 assert self.mock_connection.send_message.call_count == 2 assert self.mock_connection.send_message.call_args_list[0][0] == ( 'Starting Minecraft server "survival"...', ) assert self.mock_connection.send_message.call_args_list[1][0] == ( 'Minecraft server "survival" started.', ) def test_run_with_start_invalid_server(self): self._set_up_daemon_with_recv([ self._generate_mcrunnerd_patckage('start', 'bad_server_name'), SystemExit ]) with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert self.mock_connection.send_message.call_count == 1 assert self.mock_connection.send_message.call_args[0] == ( 'Minecraft server "bad_server_name" not defined.', ) def test_run_with_start_server_running(self): self._set_up_daemon_with_recv([ self._generate_mcrunnerd_patckage('start', 'survival'), SystemExit ]) with mock.patch.object( MinecraftServer, '_start_jar', side_effect=OSError('reason')) as mock_start_jar: with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert mock_start_jar.call_count == 1 assert self.mock_connection.send_message.called assert self.mock_connection.send_message.call_args[0] == ( 'Could not start server "survival"! Reason: reason', ) def test_run_with_restart_server(self): self._set_up_daemon_with_recv([ self._generate_mcrunnerd_patckage('restart', 'survival'), SystemExit ]) with mock.patch.object(MinecraftServer, 'pipe'): with mock.patch.object(MinecraftServer, 'run_command') as mock_run_command: with mock.patch.object(MinecraftServer, '_start_jar') as mock_start: with mock.patch( 'mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert mock_start.call_count == 1 assert mock_run_command.call_count == 1 assert self.mock_connection.send_message.call_count == 4 assert self.mock_connection.send_message.call_args_list[0][0] == ( 'Stopping Minecraft server "survival"...', ) assert self.mock_connection.send_message.call_args_list[1][0] == ( 'Minecraft server "survival" stopped.', ) assert self.mock_connection.send_message.call_args_list[2][0] == ( 'Starting Minecraft server "survival"...', ) assert self.mock_connection.send_message.call_args_list[3][0] == ( 'Minecraft server "survival" started.', ) def test_run_with_stop_server(self): self._set_up_daemon_with_recv([ self._generate_mcrunnerd_patckage('stop', 'survival'), SystemExit ]) with mock.patch.object(MinecraftServer, 'pipe'): with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert self.mock_connection.send_message.call_count == 2 assert self.mock_connection.send_message.call_args_list[0][0] == ( 'Stopping Minecraft server "survival"...', ) assert self.mock_connection.send_message.call_args_list[1][0] == ( 'Minecraft server "survival" stopped.', ) def test_run_with_stop_invalid_server(self): self._set_up_daemon_with_recv([ self._generate_mcrunnerd_patckage('stop', 'bad_server_name'), SystemExit ]) with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert self.mock_connection.send_message.call_count == 1 assert self.mock_connection.send_message.call_args[0] == ( 'Minecraft server "bad_server_name" not defined', ) def test_run_with_stop_server_not_running(self): self._set_up_daemon_with_recv([ self._generate_mcrunnerd_patckage('stop', 'survival'), SystemExit ]) with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert self.mock_connection.send_message.call_count == 1 assert self.mock_connection.send_message.call_args[0] == ( 'Minecraft server "survival" not running.', ) def test_run_with_command(self): self._set_up_daemon_with_recv([ self._generate_mcrunnerd_patckage('command', 'survival', 'say test'), SystemExit ]) with mock.patch.object(MinecraftServer, 'pipe'): with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert self.mock_connection.send_message.call_count == 1 assert self.mock_connection.send_message.call_args[0] == ( 'Sent command to Minecraft server "survival": "say test"', ) def test_run_with_command_invalid_server(self): self._set_up_daemon_with_recv([ 'command{delim}bad_server_name{delim}say test'.format( delim=MCRUNNERD_COMMAND_DELIMITER), SystemExit ]) with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert self.mock_connection.send_message.call_count == 1 assert self.mock_connection.send_message.call_args[0] == ( 'Minecraft server "bad_server_name" not defined', ) def test_run_with_command_not_running(self): self._set_up_daemon_with_recv([ self._generate_mcrunnerd_patckage('command', 'survival', 'say test'), SystemExit ]) with mock.patch.object( MinecraftServer, 'run_command', side_effect=ServerNotRunningException) as mock_command: with mock.patch('mcrunner.mcrunnerd.ServerSocketConnection', return_value=self.mock_connection): self.daemon.run() assert mock_command.call_count == 1 assert mock_command.call_args[0] == ('say test', ) assert self.mock_connection.send_message.call_count == 1 assert self.mock_connection.send_message.call_args[0] == ( 'Minecraft server "survival" not running', ) def test_log_debug(self): self._set_up_daemon() for level in [ 'debug', 'info', 'warning', 'error', 'exception', 'bad_level' ]: self.daemon._log_and_output(level, 'some message')