From e306059da234e4950fcf07f0443de1ca787fe2c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Boros?= Date: Wed, 22 Aug 2018 11:59:21 +0200 Subject: [PATCH 1/3] Extend logger to be able to write to stdout/stderr Description Adding functionality to the logger to be able to write to stdout/stderr. This feature was requested in https://github.com/RebirthDB/rebirthdb-python/pull/9/files/8328cc1a20e57615da7163cd50148e5042741bdc#diff-565263873ac3f2f37ce9d01ee9bd638a --- rebirthdb/logger.py | 26 ++++++++++++++++++------- tests/test_logger.py | 46 +++++++++++++++++++++++++++++++++----------- 2 files changed, 54 insertions(+), 18 deletions(-) diff --git a/rebirthdb/logger.py b/rebirthdb/logger.py index 71e86dab..df331361 100644 --- a/rebirthdb/logger.py +++ b/rebirthdb/logger.py @@ -18,6 +18,7 @@ import logging +import sys class DriverLogger(object): @@ -37,8 +38,10 @@ def __init__(self, level=logging.INFO): log_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') logging.basicConfig(format=log_format) - self.log = logging.getLogger() - self.log.setLevel(level) + self.logger = logging.getLogger() + self.logger.setLevel(level) + + self.write_to_console = False @staticmethod def _convert_message(message): @@ -53,6 +56,15 @@ def _convert_message(message): return str(message) + def _log(self, level, message, *args, **kwargs): + if self.write_to_console: + if level <= logging.WARNING: + sys.stdout.write(message) + else: + sys.stderr.write(message) + + self.logger.log(level, message, args, kwargs) + def debug(self, message): """ Log debug messages. @@ -62,7 +74,7 @@ def debug(self, message): :rtype: None """ - self.log.debug(message) + self._log(logging.DEBUG, message) def info(self, message): """ @@ -73,7 +85,7 @@ def info(self, message): :rtype: None """ - self.log.info(message) + self._log(logging.INFO, message) def warning(self, message): """ @@ -84,7 +96,7 @@ def warning(self, message): :rtype: None """ - self.log.warning(message) + self._log(logging.WARNING, message) def error(self, message): """ @@ -95,7 +107,7 @@ def error(self, message): :rtype: None """ - self.log.error(message) + self._log(logging.ERROR, message) def exception(self, message): """ @@ -106,7 +118,7 @@ def exception(self, message): :rtype: None """ - self.log.exception(self._convert_message(message)) + self._log(logging.ERROR, self._convert_message(message), exc_info=1) default_logger = DriverLogger() diff --git a/tests/test_logger.py b/tests/test_logger.py index b0d912ca..d3f9cf55 100644 --- a/tests/test_logger.py +++ b/tests/test_logger.py @@ -1,7 +1,7 @@ import logging import pytest -from mock import patch +from mock import call, patch, ANY from rebirthdb.logger import DriverLogger @@ -22,33 +22,57 @@ def test_converter(self): converted_message = self.driver_logger._convert_message(message) assert converted_message == expected_message + @patch('rebirthdb.logger.sys.stdout') + def test_log_write_to_stdout(self, mock_stdout): + expected_message = 'message' + log_levels = [logging.DEBUG, logging.INFO, logging.WARNING] + self.driver_logger.write_to_console = True + + with patch.object(self.logger, 'log') as mock_log: + for level in log_levels: + self.driver_logger._log(level, expected_message) + mock_stdout.write.assert_has_calls([ + call(expected_message) + ]) + + @patch('rebirthdb.logger.sys.stderr') + def test_log_write_to_stderr(self, mock_stderr): + expected_message = 'message' + self.driver_logger.write_to_console = True + + with patch.object(self.logger, 'log') as mock_log: + self.driver_logger._log(logging.ERROR, expected_message) + mock_stderr.write.assert_has_calls([ + call(expected_message) + ]) + def test_log_debug(self): expected_message = 'debug message' - with patch.object(self.logger, 'debug') as mock_debug: + with patch.object(self.logger, 'log') as mock_log: self.driver_logger.debug(expected_message) - mock_debug.assert_called_once_with(expected_message) + mock_log.assert_called_once_with(logging.DEBUG, expected_message, ANY, ANY) def test_log_info(self): expected_message = 'info message' - with patch.object(self.logger, 'info') as mock_info: + with patch.object(self.logger, 'log') as mock_log: self.driver_logger.info(expected_message) - mock_info.assert_called_once_with(expected_message) + mock_log.assert_called_once_with(logging.INFO, expected_message, ANY, ANY) def test_log_warning(self): expected_message = 'warning message' - with patch.object(self.logger, 'warning') as mock_warning: + with patch.object(self.logger, 'log') as mock_log: self.driver_logger.warning(expected_message) - mock_warning.assert_called_once_with(expected_message) + mock_log.assert_called_once_with(logging.WARNING, expected_message, ANY, ANY) def test_log_error(self): expected_message = 'error message' - with patch.object(self.logger, 'error') as mock_error: + with patch.object(self.logger, 'log') as mock_log: self.driver_logger.error(expected_message) - mock_error.assert_called_once_with(expected_message) + mock_log.assert_called_once_with(logging.ERROR, expected_message, ANY, ANY) @patch('rebirthdb.logger.DriverLogger._convert_message') def test_log_exception(self, mock_converter): @@ -56,11 +80,11 @@ def test_log_exception(self, mock_converter): expected_exception = Exception(expected_message) mock_converter.return_value = expected_message - with patch.object(self.logger, 'exception') as mock_exception: + with patch.object(self.logger, 'log') as mock_log: try: raise expected_exception except Exception as exc: self.driver_logger.exception(exc) mock_converter.assert_called_once_with(expected_exception) - mock_exception.assert_called_once_with(expected_message) + mock_log.assert_called_once_with(logging.ERROR, expected_message, ANY, {'exc_info':1}) From 178903065ef2ba936c2c927c126df39e0f21fa18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Boros?= Date: Sun, 26 Aug 2018 15:54:07 +0200 Subject: [PATCH 2/3] Simplify integration tests Description Integration tests containes unused variables and other, not needed stuff, like `teardown_methods`. Note: Tear down methods are not needed in most of the cases, due to we are removing the DB itself at the end of every test. --- tests/integration/test_cursor.py | 6 +----- tests/integration/test_database.py | 7 +++++-- tests/integration/test_table.py | 6 ------ 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/tests/integration/test_cursor.py b/tests/integration/test_cursor.py index 8766cf24..4ef85078 100644 --- a/tests/integration/test_cursor.py +++ b/tests/integration/test_cursor.py @@ -1,7 +1,7 @@ import pytest from rebirthdb.errors import ReqlCursorEmpty -from tests.helpers import IntegrationTestCaseBase, INTEGRATION_TEST_DB +from tests.helpers import IntegrationTestCaseBase @pytest.mark.integration @@ -18,10 +18,6 @@ def setup_method(self): {'id': 5, 'name': 'Testing Cursor/Next 5'}, ] - def teardown_method(self): - self.r.table_drop(self.table_name).run(self.conn) - super(TestCursor, self).teardown_method() - def test_get_next_document(self): self.r.table(self.table_name).insert(self.documents).run(self.conn) documents = list() diff --git a/tests/integration/test_database.py b/tests/integration/test_database.py index 105be188..97777793 100644 --- a/tests/integration/test_database.py +++ b/tests/integration/test_database.py @@ -5,11 +5,14 @@ @pytest.mark.integration -class TestCursorFor(IntegrationTestCaseBase): +class TestDatabase(IntegrationTestCaseBase): def setup_method(self): - super(TestCursorFor, self).setup_method() + super(TestDatabase, self).setup_method() self.test_db_name = 'test_database' + def teardown_method(self): + self.conn.close() + def test_db_create(self): result = self.r.db_create(self.test_db_name).run(self.conn) self.r.db_drop(self.test_db_name).run(self.conn) diff --git a/tests/integration/test_table.py b/tests/integration/test_table.py index d3950390..de8c61eb 100644 --- a/tests/integration/test_table.py +++ b/tests/integration/test_table.py @@ -12,7 +12,6 @@ def setup_method(self): def test_table_create(self): result = self.r.table_create(self.test_table_name).run(self.conn) - self.r.table_drop(self.test_table_name).run(self.conn) assert result['tables_created'] == 1 assert len(result['config_changes']) == 1 @@ -28,7 +27,6 @@ def test_table_different_primary_key(self): expected_primary_key = 'bazinga' result = self.r.table_create(self.test_table_name, primary_key=expected_primary_key).run(self.conn) - self.r.table_drop(self.test_table_name).run(self.conn) assert result['tables_created'] == 1 assert len(result['config_changes']) == 1 @@ -38,7 +36,6 @@ def test_table_multiple_shards(self): expected_shards = 2 result = self.r.table_create(self.test_table_name, shards=expected_shards).run(self.conn) - self.r.table_drop(self.test_table_name).run(self.conn) assert result['tables_created'] == 1 assert len(result['config_changes']) == 1 @@ -48,7 +45,6 @@ def test_table_create_with_replicas(self): expected_replicas = 1 result = self.r.table_create(self.test_table_name, replicas=expected_replicas).run(self.conn) - self.r.table_drop(self.test_table_name).run(self.conn) assert result['tables_created'] == 1 assert len(result['config_changes']) == 1 @@ -67,8 +63,6 @@ def test_table_create_twice(self): with pytest.raises(ReqlRuntimeError): self.r.table_create(self.test_table_name).run(self.conn) - self.r.table_drop(self.test_table_name).run(self.conn) - def test_table_drop(self): self.r.table_create(self.test_table_name).run(self.conn) From cc1cbb99fdc76b5638e1dbe15a753809f669e0b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Boros?= Date: Mon, 3 Sep 2018 18:56:20 +0200 Subject: [PATCH 3/3] Remove not necessary tear_down --- tests/integration/test_database.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/integration/test_database.py b/tests/integration/test_database.py index 97777793..a03b8e0f 100644 --- a/tests/integration/test_database.py +++ b/tests/integration/test_database.py @@ -10,9 +10,6 @@ def setup_method(self): super(TestDatabase, self).setup_method() self.test_db_name = 'test_database' - def teardown_method(self): - self.conn.close() - def test_db_create(self): result = self.r.db_create(self.test_db_name).run(self.conn) self.r.db_drop(self.test_db_name).run(self.conn)