From 3a3cd304b884f0ebb372b9404207523d682dc494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Sun, 27 Oct 2024 18:03:30 +0100 Subject: [PATCH] tests: refactor logging tests add restaure 100% coverage --- canaille/app/logging.py | 12 +-- tests/app/test_flaskutils.py | 96 -------------------- tests/app/test_logging.py | 168 +++++++++++++++++++++++++++++++++++ 3 files changed, 169 insertions(+), 107 deletions(-) create mode 100644 tests/app/test_logging.py diff --git a/canaille/app/logging.py b/canaille/app/logging.py index 1aa23108..5edf5553 100644 --- a/canaille/app/logging.py +++ b/canaille/app/logging.py @@ -10,10 +10,7 @@ def add_log_level(level_name, level_num, method_name=None): Comprehensively adds a new logging level to the `logging` module and the currently configured logging class. `level_name` becomes an attribute of the `logging` module with the value - `level_num`. `method_name` becomes a convenience method for both `logging` - itself and the class returned by `logging.getLoggerClass()` (usually just - `logging.Logger`). If `methodName` is not specified, `levelName.lower()` is - used. + `level_num`. To avoid accidental clobberings of existing attributes, this method will raise an `AttributeError` if the level name is already an attribute of the `logging` module or if the method name is already present @@ -29,13 +26,6 @@ def add_log_level(level_name, level_num, method_name=None): if not method_name: method_name = level_name.lower() - if hasattr(logging, level_name): - raise AttributeError(f"{level_name} already defined in logging module") - if hasattr(logging, method_name): - raise AttributeError(f"{method_name} already defined in logging module") - if hasattr(logging.getLoggerClass(), method_name): - raise AttributeError(f"{method_name} already defined in logger class") - # This method was inspired by the answers to Stack Overflow post # http://stackoverflow.com/q/2183233/2988730, especially # http://stackoverflow.com/a/13638084/2988730 diff --git a/tests/app/test_flaskutils.py b/tests/app/test_flaskutils.py index 98667afc..6eae3f60 100644 --- a/tests/app/test_flaskutils.py +++ b/tests/app/test_flaskutils.py @@ -1,7 +1,6 @@ import os import toml -from flask_webtest import TestApp from canaille import create_app from canaille.app.flask import set_parameter_in_url_query @@ -35,98 +34,3 @@ def test_environment_configuration(configuration, tmp_path): del os.environ["CONFIG"] os.remove(config_path) - - -def test_file_log_config(configuration, backend, tmp_path, smtpd, admin): - assert len(smtpd.messages) == 0 - log_path = os.path.join(tmp_path, "canaille-by-file.log") - - file_content = LOGGING_CONF_FILE_CONTENT.format(log_path=log_path) - config_file_path = tmp_path / "logging.conf" - with open(config_file_path, "w") as fd: - fd.write(file_content) - - configuration["CANAILLE"]["LOGGING"] = str(config_file_path) - app = create_app(configuration, backend=backend) - - testclient = TestApp(app) - with testclient.session_transaction() as sess: - sess["user_id"] = [admin.id] - - res = testclient.get("/admin/mail") - res.form["email"] = "test@test.com" - res = res.form.submit() - - assert len(smtpd.messages) == 1 - assert "Test email from" in smtpd.messages[0].get("Subject") - - with open(log_path) as fd: - log_content = fd.read() - - assert "Sending a mail to test@test.com: Test email from" in log_content - - -def test_dict_log_config(configuration, backend, tmp_path, smtpd, admin): - assert len(smtpd.messages) == 0 - log_path = os.path.join(tmp_path, "canaille-by-dict.log") - configuration["CANAILLE"]["LOGGING"] = { - "version": 1, - "formatters": { - "default": { - "format": "[%(asctime)s] %(levelname)s in %(module)s: %(message)s", - } - }, - "handlers": { - "wsgi": { - "class": "logging.handlers.WatchedFileHandler", - "filename": log_path, - "formatter": "default", - } - }, - "root": {"level": "DEBUG", "handlers": ["wsgi"]}, - "loggers": { - "faker": {"level": "WARNING"}, - }, - "disable_existing_loggers": False, - } - app = create_app(configuration, backend=backend) - - testclient = TestApp(app) - with testclient.session_transaction() as sess: - sess["user_id"] = [admin.id] - - res = testclient.get("/admin/mail") - res.form["email"] = "test@test.com" - res = res.form.submit() - - assert len(smtpd.messages) == 1 - assert "Test email from" in smtpd.messages[0].get("Subject") - - with open(log_path) as fd: - log_content = fd.read() - - assert "Sending a mail to test@test.com: Test email from" in log_content - - -LOGGING_CONF_FILE_CONTENT = """ -[loggers] -keys=root - -[handlers] -keys=wsgi - -[formatters] -keys=default - -[logger_root] -level=DEBUG -handlers=wsgi - -[handler_wsgi] -class=logging.handlers.WatchedFileHandler -args=('{log_path}',) -formatter=default - -[formatter_default] -format=[%(asctime)s] %(levelname)s in %(module)s: %(message)s -""" diff --git a/tests/app/test_logging.py b/tests/app/test_logging.py new file mode 100644 index 00000000..90d9a78c --- /dev/null +++ b/tests/app/test_logging.py @@ -0,0 +1,168 @@ +import logging +import os + +from flask_webtest import TestApp + +from canaille import create_app +from canaille.app.logging import add_log_level + +LOGGING_CONF_FILE_CONTENT = """ +[loggers] +keys=root + +[handlers] +keys=wsgi + +[formatters] +keys=default + +[logger_root] +level={log_level} +handlers=wsgi + +[handler_wsgi] +class=logging.handlers.WatchedFileHandler +args=('{log_path}',) +formatter=default + +[formatter_default] +format=[%(asctime)s] %(levelname)s in %(module)s: %(message)s +""" + + +def test_file_log_config(configuration, backend, tmp_path, smtpd, admin): + assert len(smtpd.messages) == 0 + log_path = os.path.join(tmp_path, "canaille-by-file.log") + + file_content = LOGGING_CONF_FILE_CONTENT.format( + log_path=log_path, log_level="DEBUG" + ) + config_file_path = tmp_path / "logging.conf" + with open(config_file_path, "w") as fd: + fd.write(file_content) + + configuration["CANAILLE"]["LOGGING"] = str(config_file_path) + app = create_app(configuration, backend=backend) + + testclient = TestApp(app) + with testclient.session_transaction() as sess: + sess["user_id"] = [admin.id] + + res = testclient.get("/admin/mail") + res.form["email"] = "test@test.com" + res = res.form.submit() + + assert len(smtpd.messages) == 1 + assert "Test email from" in smtpd.messages[0].get("Subject") + + with open(log_path) as fd: + log_content = fd.read() + + assert "Sending a mail to test@test.com: Test email from" in log_content + + +def test_dict_log_config(configuration, backend, tmp_path, smtpd, admin): + assert len(smtpd.messages) == 0 + log_path = os.path.join(tmp_path, "canaille-by-dict.log") + configuration["CANAILLE"]["LOGGING"] = { + "version": 1, + "formatters": { + "default": { + "format": "[%(asctime)s] %(levelname)s in %(module)s: %(message)s", + } + }, + "handlers": { + "wsgi": { + "class": "logging.handlers.WatchedFileHandler", + "filename": log_path, + "formatter": "default", + } + }, + "root": {"level": "DEBUG", "handlers": ["wsgi"]}, + "loggers": { + "faker": {"level": "WARNING"}, + }, + "disable_existing_loggers": False, + } + app = create_app(configuration, backend=backend) + + testclient = TestApp(app) + with testclient.session_transaction() as sess: + sess["user_id"] = [admin.id] + + res = testclient.get("/admin/mail") + res.form["email"] = "test@test.com" + res = res.form.submit() + + assert len(smtpd.messages) == 1 + assert "Test email from" in smtpd.messages[0].get("Subject") + + with open(log_path) as fd: + log_content = fd.read() + + assert "Sending a mail to test@test.com: Test email from" in log_content + + +def test_custom_root_logger(caplog): + """Checks adding custom log levels to the root logger.""" + + add_log_level("FOOBAR", logging.INFO + 6) + logging.foobar("foobar") + assert ("root", logging.FOOBAR, "foobar") in caplog.record_tuples + + add_log_level("FOOBAZ", logging.INFO + 7, "baz") + logging.baz("foobar") + assert ("root", logging.FOOBAZ, "foobar") in caplog.record_tuples + + +def test_custom_flask_logger(testclient, caplog): + """Checks adding custom log levels to the Flask logger.""" + + add_log_level("FOOBAR", logging.INFO + 6) + testclient.app.logger.foobar("foobar") + assert ("canaille", logging.FOOBAR, "foobar") in caplog.record_tuples + + add_log_level("FOOBAZ", logging.INFO + 7, "baz") + testclient.app.logger.baz("foobar") + assert ("canaille", logging.FOOBAZ, "foobar") in caplog.record_tuples + + +def test_silent_custom_logger(testclient, caplog, tmp_path, configuration, backend): + """Checks custom log levels de-activated by configuration.""" + + add_log_level("FOOBAR", logging.INFO + 6) + add_log_level("FOOBAZ", logging.INFO + 7) + + log_path = os.path.join(tmp_path, "canaille-by-dict.log") + configuration["CANAILLE"]["LOGGING"] = { + "version": 1, + "formatters": { + "default": { + "format": "[%(asctime)s] %(levelname)s in %(module)s: %(message)s", + } + }, + "handlers": { + "wsgi": { + "class": "logging.handlers.WatchedFileHandler", + "filename": log_path, + "formatter": "default", + } + }, + "root": {"level": "FOOBAZ", "handlers": ["wsgi"]}, + "loggers": { + "faker": {"level": "FOOBAZ"}, + }, + "disable_existing_loggers": False, + } + app = create_app(configuration, backend=backend) + + TestApp(app) + + testclient.app.logger.foobar("foobar") + testclient.app.logger.foobaz("foobaz") + + with open(log_path) as fd: + log_content = fd.read() + + assert "foobar" not in log_content + assert "foobaz" in log_content