From 08ed478223edb11585bcb6c1fba06492849d77e3 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Mon, 17 Jun 2024 18:27:34 +0100 Subject: [PATCH 1/5] Adding nox to run tests with specific dependencies --- .github/workflows/quality_check.yml | 2 + Makefile | 3 + poetry.lock | 88 ++++++++++++++++++- pyproject.toml | 1 + tests/functional/{ => logger}/test_logger.py | 28 +++--- .../test_logger_powertools_formatter.py | 0 .../{ => logger}/test_logger_utils.py | 0 7 files changed, 108 insertions(+), 14 deletions(-) rename tests/functional/{ => logger}/test_logger.py (98%) rename tests/functional/{ => logger}/test_logger_powertools_formatter.py (100%) rename tests/functional/{ => logger}/test_logger_utils.py (100%) diff --git a/.github/workflows/quality_check.yml b/.github/workflows/quality_check.yml index 0f63716c09d..a562ce493b5 100644 --- a/.github/workflows/quality_check.yml +++ b/.github/workflows/quality_check.yml @@ -68,6 +68,8 @@ jobs: run: make mypy - name: Test with pytest run: make test + - name: Test dependencies with Nox + run: make nox - name: Security baseline run: make security-baseline - name: Complexity baseline diff --git a/Makefile b/Makefile index 55bed054c32..5768c7412e5 100644 --- a/Makefile +++ b/Makefile @@ -32,6 +32,9 @@ test: poetry run pytest -m "not perf" --ignore tests/e2e --cov=aws_lambda_powertools --cov-report=xml poetry run pytest --cache-clear tests/performance +nox: + poetry run nox --error-on-external-run --reuse-venv=yes --non-interactive + test-pydanticv2: poetry run pytest -m "not perf" --ignore tests/e2e diff --git a/poetry.lock b/poetry.lock index eaf91105be5..47f7dd894d7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "anyio" @@ -22,6 +22,20 @@ doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphin test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] trio = ["trio (>=0.23)"] +[[package]] +name = "argcomplete" +version = "3.4.0" +description = "Bash tab completion for argparse" +optional = false +python-versions = ">=3.8" +files = [ + {file = "argcomplete-3.4.0-py3-none-any.whl", hash = "sha256:69a79e083a716173e5532e0fa3bef45f793f4e61096cf52b5a42c0211c8b8aa5"}, + {file = "argcomplete-3.4.0.tar.gz", hash = "sha256:c2abcdfe1be8ace47ba777d4fce319eb13bf8ad9dace8d085dcad6eded88057f"}, +] + +[package.extras] +test = ["coverage", "mypy", "pexpect", "ruff", "wheel"] + [[package]] name = "async-timeout" version = "4.0.3" @@ -697,6 +711,23 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "colorlog" +version = "6.8.2" +description = "Add colours to the output of Python's logging module." +optional = false +python-versions = ">=3.6" +files = [ + {file = "colorlog-6.8.2-py3-none-any.whl", hash = "sha256:4dcbb62368e2800cb3c5abd348da7e53f6c362dda502ec27c560b2e58a66bd33"}, + {file = "colorlog-6.8.2.tar.gz", hash = "sha256:3e3e079a41feb5a1b64f978b5ea4f46040a94f11f0e8bbb8261e3dbbeca64d44"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} + +[package.extras] +development = ["black", "flake8", "mypy", "pytest", "types-colorama"] + [[package]] name = "constructs" version = "10.3.0" @@ -1037,6 +1068,17 @@ files = [ graph = ["objgraph (>=1.7.2)"] profile = ["gprof2dot (>=2022.7.29)"] +[[package]] +name = "distlib" +version = "0.3.8" +description = "Distribution utilities" +optional = false +python-versions = "*" +files = [ + {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, + {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, +] + [[package]] name = "docker" version = "7.1.0" @@ -2168,6 +2210,28 @@ doc = ["nb2plots (>=0.6)", "numpydoc (>=1.5)", "pillow (>=9.4)", "pydata-sphinx- extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.10)", "sympy (>=1.10)"] test = ["codecov (>=2.1)", "pytest (>=7.2)", "pytest-cov (>=4.0)"] +[[package]] +name = "nox" +version = "2024.4.15" +description = "Flexible test automation." +optional = false +python-versions = ">=3.7" +files = [ + {file = "nox-2024.4.15-py3-none-any.whl", hash = "sha256:6492236efa15a460ecb98e7b67562a28b70da006ab0be164e8821177577c0565"}, + {file = "nox-2024.4.15.tar.gz", hash = "sha256:ecf6700199cdfa9e5ea0a41ff5e6ef4641d09508eda6edb89d9987864115817f"}, +] + +[package.dependencies] +argcomplete = ">=1.9.4,<4.0" +colorlog = ">=2.6.1,<7.0.0" +packaging = ">=20.9" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} +virtualenv = ">=20.14.1" + +[package.extras] +tox-to-nox = ["jinja2", "tox"] +uv = ["uv (>=0.1.6)"] + [[package]] name = "opentelemetry-api" version = "1.16.0" @@ -3491,6 +3555,26 @@ files = [ [package.extras] test = ["coverage", "flake8 (>=3.7)", "mypy", "pretend", "pytest"] +[[package]] +name = "virtualenv" +version = "20.26.2" +description = "Virtual Python Environment builder" +optional = false +python-versions = ">=3.7" +files = [ + {file = "virtualenv-20.26.2-py3-none-any.whl", hash = "sha256:a624db5e94f01ad993d476b9ee5346fdf7b9de43ccaee0e0197012dc838a0e9b"}, + {file = "virtualenv-20.26.2.tar.gz", hash = "sha256:82bf0f4eebbb78d36ddaee0283d43fe5736b53880b8a8cdcd37390a07ac3741c"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<5" + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] + [[package]] name = "watchdog" version = "4.0.1" @@ -3669,4 +3753,4 @@ validation = ["fastjsonschema"] [metadata] lock-version = "2.0" python-versions = ">=3.8,<4.0.0" -content-hash = "1ef63c50d99b6f139ca65e6fc82b982b95dc6d582318bb3fe762dc653456ebc4" +content-hash = "367ffa0dc2a66c7f6f7662242ebb1ac8b23edf80df0238f4f8c47b10269c9782" diff --git a/pyproject.toml b/pyproject.toml index 35c0bd4808a..947d202bef7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -126,6 +126,7 @@ pytest-socket = ">=0.6,<0.8" types-redis = "^4.6.0.7" testcontainers = { extras = ["redis"], version = "^3.7.1" } multiprocess = "^0.70.16" +nox = "^2024.4.15" [tool.coverage.run] source = ["aws_lambda_powertools"] diff --git a/tests/functional/test_logger.py b/tests/functional/logger/test_logger.py similarity index 98% rename from tests/functional/test_logger.py rename to tests/functional/logger/test_logger.py index 7aa4037cb9c..096783c95f0 100644 --- a/tests/functional/test_logger.py +++ b/tests/functional/logger/test_logger.py @@ -15,7 +15,7 @@ import pytest -from aws_lambda_powertools import Logger, Tracer, set_package_logger_handler +from aws_lambda_powertools import Logger, Metrics, set_package_logger_handler from aws_lambda_powertools.logging import correlation_paths from aws_lambda_powertools.logging.exceptions import InvalidLoggerSamplingRateError from aws_lambda_powertools.logging.formatter import ( @@ -219,13 +219,14 @@ def test_package_logger_stream(stdout): # GIVEN package logger "aws_lambda_powertools" is explicitly set with no params set_package_logger(stream=stdout) - # WHEN Tracer is initialized in disabled mode - Tracer(disabled=True) + # WHEN we add a dimension in Metrics feature + my_metrics = Metrics(namespace="powertools") + my_metrics.add_dimension(name="dimension", value="test") - # THEN Tracer debug log statement should be logged + # THEN Metrics debug log statement should be logged output = stdout.getvalue() logger = logging.getLogger("aws_lambda_powertools") - assert "Tracing has been disabled" in output + assert "Adding dimension:" in output assert logger.level == logging.DEBUG @@ -235,10 +236,11 @@ def test_package_logger_format(capsys): formatter = logging.Formatter("message=%(message)s") set_package_logger(formatter=formatter) - # WHEN Tracer is initialized in disabled mode - Tracer(disabled=True) + # WHEN we add a dimension in Metrics feature + my_metrics = Metrics(namespace="powertools") + my_metrics.add_dimension(name="dimension", value="test") - # THEN Tracer debug log statement should be logged using `message=` format + # THEN Metrics debug log statement should be logged using `message=` format output = capsys.readouterr().out logger = logging.getLogger("aws_lambda_powertools") assert "message=" in output @@ -977,13 +979,15 @@ def test_set_package_logger_handler_with_powertools_debug_env_var(stdout, monkey logger = logging.getLogger("aws_lambda_powertools") # WHEN set_package_logger is used at initialization - # and any Powertools for AWS Lambda (Python) operation is used (e.g., Tracer) + # and any Powertools for AWS Lambda (Python) operation is used (e.g., Metrics add_dimension) set_package_logger_handler(stream=stdout) - Tracer(disabled=True) - # THEN Tracer debug log statement should be logged + my_metrics = Metrics(namespace="powertools") + my_metrics.add_dimension(name="dimension", value="test") + + # THEN Metrics debug log statement should be logged output = stdout.getvalue() - assert "Tracing has been disabled" in output + assert "Adding dimension:" in output assert logger.level == logging.DEBUG diff --git a/tests/functional/test_logger_powertools_formatter.py b/tests/functional/logger/test_logger_powertools_formatter.py similarity index 100% rename from tests/functional/test_logger_powertools_formatter.py rename to tests/functional/logger/test_logger_powertools_formatter.py diff --git a/tests/functional/test_logger_utils.py b/tests/functional/logger/test_logger_utils.py similarity index 100% rename from tests/functional/test_logger_utils.py rename to tests/functional/logger/test_logger_utils.py From 2a6b89ce2783f53cd6de52ddc012623fd42a3f21 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Mon, 17 Jun 2024 18:36:23 +0100 Subject: [PATCH 2/5] Ohhhh Leandro.. --- noxfile.py | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 noxfile.py diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 00000000000..da1245e80c5 --- /dev/null +++ b/noxfile.py @@ -0,0 +1,60 @@ +# Run nox tests +# +# usage: +# poetry run nox --error-on-external-run --reuse-venv=yes --non-interactive +# +# If you want to target a specific Python version, add -p parameter + +from typing import List, Optional + +import nox + +PREFIX_TESTS_FUNCTIONAL = "tests/functional" +PREFIX_TESTS_UNIT = "tests/unit" + +PYTHON_VERSIONS = ["3.8", "3.9", "3.10", "3.11", "3.12"] + + +def build_and_run_test(session: nox.Session, folders: List, extras: Optional[str] = "") -> None: + """ + This function is responsible for setting up the testing environment and running the test suite for specific feature. + + The function performs the following tasks: + 1. Installs the required dependencies for executing any test + 2. If the `extras` parameter is provided, the function installs the additional dependencies + 3. the function runs the pytest command with the specified folders as arguments, executing the test suite. + + Parameters + ---------- + session: nox.Session + The current Nox session object, which is used to manage the virtual environment and execute commands. + folders: List + A list of folder paths that contain the test files to be executed. + extras: Optional[str] + A string representing additional dependencies that should be installed for the test environment. + If not provided, the function will install the project with basic dependencies + """ + + # Required install to execute any test + session.install("poetry", "pytest", "pytest-mock", "pytest_socket") + + # Powertools project folder is in the root + if extras: + session.install(f"./[{extras}]") + else: + session.install("./") + + # Execute test in specific folders + session.run("pytest", *folders) + + +@nox.session(python=PYTHON_VERSIONS) +def test_with_only_required_packages(session: nox.Session): + """Tests that only depends for required libraries""" + # Logger + build_and_run_test( + session, + folders=[ + f"{PREFIX_TESTS_FUNCTIONAL}/logger/", + ], + ) From eee2d41e555f38d42a1f916ca9d32f46b82a0c93 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Mon, 17 Jun 2024 18:43:51 +0100 Subject: [PATCH 3/5] Locking python version --- noxfile.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/noxfile.py b/noxfile.py index da1245e80c5..18a9e9cd4d5 100644 --- a/noxfile.py +++ b/noxfile.py @@ -12,8 +12,6 @@ PREFIX_TESTS_FUNCTIONAL = "tests/functional" PREFIX_TESTS_UNIT = "tests/unit" -PYTHON_VERSIONS = ["3.8", "3.9", "3.10", "3.11", "3.12"] - def build_and_run_test(session: nox.Session, folders: List, extras: Optional[str] = "") -> None: """ @@ -48,7 +46,7 @@ def build_and_run_test(session: nox.Session, folders: List, extras: Optional[str session.run("pytest", *folders) -@nox.session(python=PYTHON_VERSIONS) +@nox.session() def test_with_only_required_packages(session: nox.Session): """Tests that only depends for required libraries""" # Logger From b6cbe2a4b0ffd56470c790c67db5cd3d5240ee63 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Mon, 17 Jun 2024 18:53:31 +0100 Subject: [PATCH 4/5] Adding local check + contributing --- CONTRIBUTING.md | 2 +- Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cc37371cb88..dc04db7ce4f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -67,7 +67,7 @@ timeline Pre-Pull Request
(make pr) : Code linting : Docs linting : Static typing analysis - : Tests (unit|functional|perf) + : Tests (unit|functional|perf|dependencies) : Security baseline : Complexity baseline : +pre-commit checks diff --git a/Makefile b/Makefile index 5768c7412e5..134cf141dd5 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ coverage-html: pre-commit: pre-commit run --show-diff-on-failure -pr: lint lint-docs mypy pre-commit test security-baseline complexity-baseline +pr: lint lint-docs mypy pre-commit test nox security-baseline complexity-baseline build: pr poetry build From 2fcda8f413aad38feaa0e0abc40af7062502a306 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Tue, 18 Jun 2024 10:12:45 +0100 Subject: [PATCH 5/5] Addressing Heitor's feedback --- .github/workflows/quality_check.yml | 2 +- Makefile | 4 +- tests/functional/logger/test_logger.py | 68 +---------- .../logger/test_logger_with_package_logger.py | 113 ++++++++++++++++++ 4 files changed, 117 insertions(+), 70 deletions(-) create mode 100644 tests/functional/logger/test_logger_with_package_logger.py diff --git a/.github/workflows/quality_check.yml b/.github/workflows/quality_check.yml index a562ce493b5..77e78201f70 100644 --- a/.github/workflows/quality_check.yml +++ b/.github/workflows/quality_check.yml @@ -69,7 +69,7 @@ jobs: - name: Test with pytest run: make test - name: Test dependencies with Nox - run: make nox + run: make test-dependencies - name: Security baseline run: make security-baseline - name: Complexity baseline diff --git a/Makefile b/Makefile index 134cf141dd5..85bb6a9d81d 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ test: poetry run pytest -m "not perf" --ignore tests/e2e --cov=aws_lambda_powertools --cov-report=xml poetry run pytest --cache-clear tests/performance -nox: +test-dependencies: poetry run nox --error-on-external-run --reuse-venv=yes --non-interactive test-pydanticv2: @@ -50,7 +50,7 @@ coverage-html: pre-commit: pre-commit run --show-diff-on-failure -pr: lint lint-docs mypy pre-commit test nox security-baseline complexity-baseline +pr: lint lint-docs mypy pre-commit test test-dependencies security-baseline complexity-baseline build: pr poetry build diff --git a/tests/functional/logger/test_logger.py b/tests/functional/logger/test_logger.py index 096783c95f0..e86dba27eb6 100644 --- a/tests/functional/logger/test_logger.py +++ b/tests/functional/logger/test_logger.py @@ -8,21 +8,19 @@ import secrets import string import sys -import warnings from collections import namedtuple from datetime import datetime, timezone from typing import Any, Callable, Dict, Iterable, List, Optional, Union import pytest -from aws_lambda_powertools import Logger, Metrics, set_package_logger_handler +from aws_lambda_powertools import Logger from aws_lambda_powertools.logging import correlation_paths from aws_lambda_powertools.logging.exceptions import InvalidLoggerSamplingRateError from aws_lambda_powertools.logging.formatter import ( BasePowertoolsFormatter, LambdaPowertoolsFormatter, ) -from aws_lambda_powertools.logging.logger import set_package_logger from aws_lambda_powertools.shared import constants from aws_lambda_powertools.utilities.data_classes import S3Event, event_source @@ -215,38 +213,6 @@ def handler(event, context): assert second_log["cold_start"] is False -def test_package_logger_stream(stdout): - # GIVEN package logger "aws_lambda_powertools" is explicitly set with no params - set_package_logger(stream=stdout) - - # WHEN we add a dimension in Metrics feature - my_metrics = Metrics(namespace="powertools") - my_metrics.add_dimension(name="dimension", value="test") - - # THEN Metrics debug log statement should be logged - output = stdout.getvalue() - logger = logging.getLogger("aws_lambda_powertools") - assert "Adding dimension:" in output - assert logger.level == logging.DEBUG - - -def test_package_logger_format(capsys): - # GIVEN package logger "aws_lambda_powertools" is explicitly - # with a custom formatter - formatter = logging.Formatter("message=%(message)s") - set_package_logger(formatter=formatter) - - # WHEN we add a dimension in Metrics feature - my_metrics = Metrics(namespace="powertools") - my_metrics.add_dimension(name="dimension", value="test") - - # THEN Metrics debug log statement should be logged using `message=` format - output = capsys.readouterr().out - logger = logging.getLogger("aws_lambda_powertools") - assert "message=" in output - assert logger.level == logging.DEBUG - - def test_logger_append_duplicated(stdout, service_name): # GIVEN Logger is initialized with request_id field logger = Logger(service=service_name, stream=stdout, request_id="value") @@ -973,38 +939,6 @@ def handler(event, context, planet, str_end="."): assert log["message"] == "Hello World!" -def test_set_package_logger_handler_with_powertools_debug_env_var(stdout, monkeypatch: pytest.MonkeyPatch): - # GIVEN POWERTOOLS_DEBUG is set - monkeypatch.setenv(constants.POWERTOOLS_DEBUG_ENV, "1") - logger = logging.getLogger("aws_lambda_powertools") - - # WHEN set_package_logger is used at initialization - # and any Powertools for AWS Lambda (Python) operation is used (e.g., Metrics add_dimension) - set_package_logger_handler(stream=stdout) - - my_metrics = Metrics(namespace="powertools") - my_metrics.add_dimension(name="dimension", value="test") - - # THEN Metrics debug log statement should be logged - output = stdout.getvalue() - assert "Adding dimension:" in output - assert logger.level == logging.DEBUG - - -def test_powertools_debug_env_var_warning(monkeypatch: pytest.MonkeyPatch): - # GIVEN POWERTOOLS_DEBUG is set - monkeypatch.setenv(constants.POWERTOOLS_DEBUG_ENV, "1") - warning_message = "POWERTOOLS_DEBUG environment variable is enabled. Setting logging level to DEBUG." - - # WHEN set_package_logger is used at initialization - # THEN a warning should be emitted - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("default") - set_package_logger_handler() - assert len(w) == 1 - assert str(w[0].message) == warning_message - - def test_logger_log_uncaught_exceptions(service_name, stdout): # GIVEN an initialized Logger is set with log_uncaught_exceptions logger = Logger(service=service_name, stream=stdout, log_uncaught_exceptions=True) diff --git a/tests/functional/logger/test_logger_with_package_logger.py b/tests/functional/logger/test_logger_with_package_logger.py new file mode 100644 index 00000000000..2dfd6016333 --- /dev/null +++ b/tests/functional/logger/test_logger_with_package_logger.py @@ -0,0 +1,113 @@ +import io +import json +import logging +import random +import string +import warnings +from collections import namedtuple + +import pytest + +from aws_lambda_powertools import Metrics, set_package_logger_handler +from aws_lambda_powertools.logging.logger import set_package_logger +from aws_lambda_powertools.shared import constants + + +@pytest.fixture +def stdout(): + return io.StringIO() + + +@pytest.fixture +def lambda_context(): + lambda_context = { + "function_name": "test", + "memory_limit_in_mb": 128, + "invoked_function_arn": "arn:aws:lambda:eu-west-1:809313241:function:test", + "aws_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72", + } + + return namedtuple("LambdaContext", lambda_context.keys())(*lambda_context.values()) + + +@pytest.fixture +def lambda_event(): + return {"greeting": "hello"} + + +@pytest.fixture +def service_name(): + chars = string.ascii_letters + string.digits + return "".join(random.SystemRandom().choice(chars) for _ in range(15)) + + +def capture_logging_output(stdout): + return json.loads(stdout.getvalue().strip()) + + +def capture_multiple_logging_statements_output(stdout): + return [json.loads(line.strip()) for line in stdout.getvalue().split("\n") if line] + + +def test_package_logger_stream(stdout): + # GIVEN package logger "aws_lambda_powertools" is explicitly set with no params + set_package_logger(stream=stdout) + + # WHEN we add a dimension in Metrics feature + my_metrics = Metrics(namespace="powertools") + my_metrics.add_dimension(name="dimension", value="test") + + # THEN Metrics debug log statement should be logged + output = stdout.getvalue() + logger = logging.getLogger("aws_lambda_powertools") + assert "Adding dimension:" in output + assert logger.level == logging.DEBUG + + +def test_package_logger_format(capsys): + # GIVEN package logger "aws_lambda_powertools" is explicitly + # with a custom formatter + formatter = logging.Formatter("message=%(message)s") + set_package_logger(formatter=formatter) + + # WHEN we add a dimension in Metrics feature + my_metrics = Metrics(namespace="powertools") + my_metrics.add_dimension(name="dimension", value="test") + + # THEN Metrics debug log statement should be logged using `message=` format + output = capsys.readouterr().out + logger = logging.getLogger("aws_lambda_powertools") + assert "message=" in output + assert logger.level == logging.DEBUG + + +def test_set_package_logger_handler_with_powertools_debug_env_var(stdout, monkeypatch: pytest.MonkeyPatch): + # GIVEN POWERTOOLS_DEBUG is set + monkeypatch.setenv(constants.POWERTOOLS_DEBUG_ENV, "1") + logger = logging.getLogger("aws_lambda_powertools") + + # WHEN set_package_logger is used at initialization + # and any Powertools for AWS Lambda (Python) operation is used (e.g., Metrics add_dimension) + set_package_logger_handler(stream=stdout) + + my_metrics = Metrics(namespace="powertools") + my_metrics.add_dimension(name="dimension", value="test") + + # THEN Metrics debug log statement should be logged + output = stdout.getvalue() + assert "Adding dimension:" in output + assert logger.level == logging.DEBUG + + +def test_powertools_debug_env_var_warning(monkeypatch: pytest.MonkeyPatch): + # GIVEN POWERTOOLS_DEBUG is set + monkeypatch.setenv(constants.POWERTOOLS_DEBUG_ENV, "1") + warning_message = "POWERTOOLS_DEBUG environment variable is enabled. Setting logging level to DEBUG." + + # WHEN set_package_logger is used at initialization + # THEN a warning should be emitted + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("default") + set_package_logger_handler() + assert len(w) == 1 + assert str(w[0].message) == warning_message