This is an automated email from the ASF dual-hosted git repository.

potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 95953571e8 Update `Dag.test()` to run with an executor if desired 
(#40205)
95953571e8 is described below

commit 95953571e86f3f021cc94cc85bc291d52df440d8
Author: Vincent <[email protected]>
AuthorDate: Fri Jun 14 15:49:56 2024 -0400

    Update `Dag.test()` to run with an executor if desired (#40205)
    
    * Update `Dag.test()` to run with an executor if desired
    
    * Add missing parameter
    
    * Fix typo
    
    * Move `add_logger_if_needed` to local execution
    
    * Add `keep-env-variables` to `breeze testing db-tests`, `breeze testing 
non-db-tests` and `breeze shell`
    
    * Add documentation
    
    * Fix tests
    
    * Introduce `use-executor` flag
    
    * Update `debug` documentation
    
    * Fix test
---
 airflow/cli/cli_config.py                          |  7 +++
 airflow/cli/commands/dag_command.py                |  5 +-
 airflow/models/dag.py                              | 36 ++++++++++--
 contributing-docs/testing/unit_tests.rst           | 23 ++++++++
 dev/breeze/doc/images/output_shell.svg             | 24 ++++----
 dev/breeze/doc/images/output_shell.txt             |  2 +-
 dev/breeze/doc/images/output_testing_db-tests.svg  | 26 ++++++---
 dev/breeze/doc/images/output_testing_db-tests.txt  |  2 +-
 .../doc/images/output_testing_non-db-tests.svg     | 26 ++++++---
 .../doc/images/output_testing_non-db-tests.txt     |  2 +-
 dev/breeze/doc/images/output_testing_tests.svg     | 26 ++++++---
 dev/breeze/doc/images/output_testing_tests.txt     |  2 +-
 .../src/airflow_breeze/commands/common_options.py  |  6 ++
 .../airflow_breeze/commands/developer_commands.py  |  4 ++
 .../commands/developer_commands_config.py          |  1 +
 .../airflow_breeze/commands/testing_commands.py    |  8 +++
 .../commands/testing_commands_config.py            |  3 +
 .../src/airflow_breeze/params/shell_params.py      |  1 +
 dev/breeze/src/airflow_breeze/utils/run_tests.py   |  3 +
 docs/apache-airflow/core-concepts/debug.rst        |  9 ++-
 tests/cli/commands/test_dag_command.py             | 15 ++++-
 tests/conftest.py                                  | 65 ++++++++++++----------
 tests/system/utils/__init__.py                     |  4 +-
 23 files changed, 218 insertions(+), 82 deletions(-)

diff --git a/airflow/cli/cli_config.py b/airflow/cli/cli_config.py
index d9bb2f5897..f4aab0caf5 100644
--- a/airflow/cli/cli_config.py
+++ b/airflow/cli/cli_config.py
@@ -417,6 +417,12 @@ ARG_SAVE_DAGRUN = Arg(
     ("--save-dagrun",),
     help="After completing the backfill, saves the diagram for current DAG Run 
to the indicated file.\n\n",
 )
+ARG_USE_EXECUTOR = Arg(
+    ("--use-executor",),
+    help="Use an executor to test the DAG. By default it runs the DAG without 
an executor. "
+    "If set, it uses the executor configured in the environment.",
+    action="store_true",
+)
 
 # list_tasks
 ARG_TREE = Arg(("-t", "--tree"), help="Tree view", action="store_true")
@@ -1280,6 +1286,7 @@ DAGS_COMMANDS = (
             ARG_SHOW_DAGRUN,
             ARG_IMGCAT_DAGRUN,
             ARG_SAVE_DAGRUN,
+            ARG_USE_EXECUTOR,
             ARG_VERBOSE,
         ),
     ),
diff --git a/airflow/cli/commands/dag_command.py 
b/airflow/cli/commands/dag_command.py
index 3a91072cdf..24ba7a80fc 100644
--- a/airflow/cli/commands/dag_command.py
+++ b/airflow/cli/commands/dag_command.py
@@ -605,9 +605,12 @@ def dag_test(args, dag: DAG | None = None, session: 
Session = NEW_SESSION) -> No
         except ValueError as e:
             raise SystemExit(f"Configuration {args.conf!r} is not valid JSON. 
Error: {e}")
     execution_date = args.execution_date or timezone.utcnow()
+    use_executor = args.use_executor
     with _airflow_parsing_context_manager(dag_id=args.dag_id):
         dag = dag or get_dag(subdir=args.subdir, dag_id=args.dag_id)
-    dr: DagRun = dag.test(execution_date=execution_date, run_conf=run_conf, 
session=session)
+    dr: DagRun = dag.test(
+        execution_date=execution_date, run_conf=run_conf, 
use_executor=use_executor, session=session
+    )
     show_dagrun = args.show_dagrun
     imgcat = args.imgcat_dagrun
     filename = args.save_dagrun
diff --git a/airflow/models/dag.py b/airflow/models/dag.py
index 1bf812abda..57fb5a9008 100644
--- a/airflow/models/dag.py
+++ b/airflow/models/dag.py
@@ -2885,6 +2885,7 @@ class DAG(LoggingMixin):
         run_conf: dict[str, Any] | None = None,
         conn_file_path: str | None = None,
         variable_file_path: str | None = None,
+        use_executor: bool = False,
         session: Session = NEW_SESSION,
     ) -> DagRun:
         """
@@ -2894,6 +2895,7 @@ class DAG(LoggingMixin):
         :param run_conf: configuration to pass to newly created dagrun
         :param conn_file_path: file path to a connection file in either yaml 
or json
         :param variable_file_path: file path to a variable file in either yaml 
or json
+        :param use_executor: if set, uses an executor to test the DAG
         :param session: database connection (optional)
         """
 
@@ -2952,6 +2954,15 @@ class DAG(LoggingMixin):
             # Instead of starting a scheduler, we run the minimal loop 
possible to check
             # for task readiness and dependency management. This is notably 
faster
             # than creating a BackfillJob and allows us to surface logs to the 
user
+
+            # ``Dag.test()`` works in two different modes depending on 
``use_executor``:
+            # - if ``use_executor`` is False, runs the task locally with no 
executor using ``_run_task``
+            # - if ``use_executor`` is True, sends the task instances to the 
executor with
+            #   ``BaseExecutor.queue_task_instance``
+            if use_executor:
+                executor = ExecutorLoader.get_default_executor()
+                executor.start()
+
             while dr.state == DagRunState.RUNNING:
                 session.expire_all()
                 schedulable_tis, _ = dr.update_state(session=session)
@@ -2967,14 +2978,27 @@ class DAG(LoggingMixin):
                 if not scheduled_tis and ids_unrunnable:
                     self.log.warning("No tasks to run. unrunnable tasks: %s", 
ids_unrunnable)
                     time.sleep(1)
+
                 triggerer_running = _triggerer_is_healthy()
                 for ti in scheduled_tis:
-                    try:
-                        add_logger_if_needed(ti)
-                        ti.task = tasks[ti.task_id]
-                        _run_task(ti=ti, inline_trigger=not triggerer_running, 
session=session)
-                    except Exception:
-                        self.log.exception("Task failed; ti=%s", ti)
+                    ti.task = tasks[ti.task_id]
+
+                    if use_executor:
+                        if executor.has_task(ti):
+                            continue
+                        # Send the task to the executor
+                        executor.queue_task_instance(ti, ignore_ti_state=True)
+                    else:
+                        # Run the task locally
+                        try:
+                            add_logger_if_needed(ti)
+                            _run_task(ti=ti, inline_trigger=not 
triggerer_running, session=session)
+                        except Exception:
+                            self.log.exception("Task failed; ti=%s", ti)
+                if use_executor:
+                    executor.heartbeat()
+            if use_executor:
+                executor.end()
         return dr
 
     @provide_session
diff --git a/contributing-docs/testing/unit_tests.rst 
b/contributing-docs/testing/unit_tests.rst
index 4136e3c5c8..bb11aa585e 100644
--- a/contributing-docs/testing/unit_tests.rst
+++ b/contributing-docs/testing/unit_tests.rst
@@ -1440,6 +1440,29 @@ to **ignore**, e.g. set ``PYTHONWARNINGS`` environment 
variable to ``ignore``.
 
     pytest tests/core/ --disable-capture-warnings
 
+Keep tests using environment variables
+......................................
+
+By default, all environment variables related to Airflow (starting by 
``AIRFLOW__``) are all cleared before running tests
+to avoid potential side effect. However, in some scenarios you might want to 
disable this mechanism and keep the
+environment variables you defined to configure your Airflow environment. For 
example, you might want to run tests
+against a specific database configured through the environment variable 
``AIRFLOW__DATABASE__SQL_ALCHEMY_CONN``.
+Or running tests using a specific executor to run tasks configured through 
``AIRFLOW__CORE__EXECUTOR``.
+
+To keep using environment variables you defined in your environment, you need 
to provide ``--keep-env-variables`` as
+pytest CLI argument.
+
+.. code-block:: bash
+
+    pytest tests/core/ --keep-env-variables
+
+This parameter is also available in Breeze.
+
+.. code-block:: bash
+
+    breeze testing db-tests --keep-env-variables
+
+
 Code Coverage
 -------------
 
diff --git a/dev/breeze/doc/images/output_shell.svg 
b/dev/breeze/doc/images/output_shell.svg
index f1449fefe5..c4a7c212e2 100644
--- a/dev/breeze/doc/images/output_shell.svg
+++ b/dev/breeze/doc/images/output_shell.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 3758.7999999999997" 
xmlns="http://www.w3.org/2000/svg";>
+<svg class="rich-terminal" viewBox="0 0 1482 3783.2" 
xmlns="http://www.w3.org/2000/svg";>
     <!-- Generated with Rich https://www.textualize.io -->
     <style>
 
@@ -43,7 +43,7 @@
 
     <defs>
     <clipPath id="breeze-shell-clip-terminal">
-      <rect x="0" y="0" width="1463.0" height="3707.7999999999997" />
+      <rect x="0" y="0" width="1463.0" height="3732.2" />
     </clipPath>
     <clipPath id="breeze-shell-line-0">
     <rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -498,9 +498,12 @@
 <clipPath id="breeze-shell-line-150">
     <rect x="0" y="3661.5" width="1464" height="24.65"/>
             </clipPath>
+<clipPath id="breeze-shell-line-151">
+    <rect x="0" y="3685.9" width="1464" height="24.65"/>
+            </clipPath>
     </defs>
 
-    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="3756.8" rx="8"/><text 
class="breeze-shell-title" fill="#c5c8c6" text-anchor="middle" x="740" 
y="27">Command:&#160;shell</text>
+    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="3781.2" rx="8"/><text 
class="breeze-shell-title" fill="#c5c8c6" text-anchor="middle" x="740" 
y="27">Command:&#160;shell</text>
             <g transform="translate(26,22)">
             <circle cx="0" cy="0" r="7" fill="#ff5f57"/>
             <circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -655,13 +658,14 @@
 </text><text class="breeze-shell-r5" x="0" y="3484.8" textLength="12.2" 
clip-path="url(#breeze-shell-line-142)">│</text><text class="breeze-shell-r4" 
x="24.4" y="3484.8" textLength="122" 
clip-path="url(#breeze-shell-line-142)">--max-time</text><text 
class="breeze-shell-r1" x="353.8" y="3484.8" textLength="1049.2" 
clip-path="url(#breeze-shell-line-142)">Maximum&#160;time&#160;that&#160;the&#160;command&#160;should&#160;take&#160;-&#160;if&#160;it&#160;takes&#160;longer,&#160;the&#160;comm
 [...]
 </text><text class="breeze-shell-r5" x="0" y="3509.2" textLength="12.2" 
clip-path="url(#breeze-shell-line-143)">│</text><text class="breeze-shell-r7" 
x="353.8" y="3509.2" textLength="1049.2" 
clip-path="url(#breeze-shell-line-143)">(INTEGER&#160;RANGE)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&
 [...]
 </text><text class="breeze-shell-r5" x="0" y="3533.6" textLength="12.2" 
clip-path="url(#breeze-shell-line-144)">│</text><text class="breeze-shell-r4" 
x="24.4" y="3533.6" textLength="219.6" 
clip-path="url(#breeze-shell-line-144)">--verbose-commands</text><text 
class="breeze-shell-r1" x="353.8" y="3533.6" textLength="414.8" 
clip-path="url(#breeze-shell-line-144)">Show&#160;details&#160;of&#160;commands&#160;executed.</text><text
 class="breeze-shell-r5" x="1451.8" y="3533.6" textLength="12. [...]
-</text><text class="breeze-shell-r5" x="0" y="3558" textLength="1464" 
clip-path="url(#breeze-shell-line-145)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-shell-r1" x="1464" y="3558" textLength="12.2" 
clip-path="url(#breeze-shell-line-145)">
-</text><text class="breeze-shell-r5" x="0" y="3582.4" textLength="24.4" 
clip-path="url(#breeze-shell-line-146)">╭─</text><text class="breeze-shell-r5" 
x="24.4" y="3582.4" textLength="195.2" 
clip-path="url(#breeze-shell-line-146)">&#160;Common&#160;options&#160;</text><text
 class="breeze-shell-r5" x="219.6" y="3582.4" textLength="1220" 
clip-path="url(#breeze-shell-line-146)">────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 cl [...]
-</text><text class="breeze-shell-r5" x="0" y="3606.8" textLength="12.2" 
clip-path="url(#breeze-shell-line-147)">│</text><text class="breeze-shell-r4" 
x="24.4" y="3606.8" textLength="97.6" 
clip-path="url(#breeze-shell-line-147)">--answer</text><text 
class="breeze-shell-r6" x="158.6" y="3606.8" textLength="24.4" 
clip-path="url(#breeze-shell-line-147)">-a</text><text class="breeze-shell-r1" 
x="207.4" y="3606.8" textLength="317.2" 
clip-path="url(#breeze-shell-line-147)">Force&#160;answer&#16 [...]
-</text><text class="breeze-shell-r5" x="0" y="3631.2" textLength="12.2" 
clip-path="url(#breeze-shell-line-148)">│</text><text class="breeze-shell-r4" 
x="24.4" y="3631.2" textLength="109.8" 
clip-path="url(#breeze-shell-line-148)">--dry-run</text><text 
class="breeze-shell-r6" x="158.6" y="3631.2" textLength="24.4" 
clip-path="url(#breeze-shell-line-148)">-D</text><text class="breeze-shell-r1" 
x="207.4" y="3631.2" textLength="719.8" 
clip-path="url(#breeze-shell-line-148)">If&#160;dry-run&#16 [...]
-</text><text class="breeze-shell-r5" x="0" y="3655.6" textLength="12.2" 
clip-path="url(#breeze-shell-line-149)">│</text><text class="breeze-shell-r4" 
x="24.4" y="3655.6" textLength="109.8" 
clip-path="url(#breeze-shell-line-149)">--verbose</text><text 
class="breeze-shell-r6" x="158.6" y="3655.6" textLength="24.4" 
clip-path="url(#breeze-shell-line-149)">-v</text><text class="breeze-shell-r1" 
x="207.4" y="3655.6" textLength="585.6" 
clip-path="url(#breeze-shell-line-149)">Print&#160;verbose& [...]
-</text><text class="breeze-shell-r5" x="0" y="3680" textLength="12.2" 
clip-path="url(#breeze-shell-line-150)">│</text><text class="breeze-shell-r4" 
x="24.4" y="3680" textLength="73.2" 
clip-path="url(#breeze-shell-line-150)">--help</text><text 
class="breeze-shell-r6" x="158.6" y="3680" textLength="24.4" 
clip-path="url(#breeze-shell-line-150)">-h</text><text class="breeze-shell-r1" 
x="207.4" y="3680" textLength="329.4" 
clip-path="url(#breeze-shell-line-150)">Show&#160;this&#160;message&#16 [...]
-</text><text class="breeze-shell-r5" x="0" y="3704.4" textLength="1464" 
clip-path="url(#breeze-shell-line-151)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-shell-r1" x="1464" y="3704.4" textLength="12.2" 
clip-path="url(#breeze-shell-line-151)">
+</text><text class="breeze-shell-r5" x="0" y="3558" textLength="12.2" 
clip-path="url(#breeze-shell-line-145)">│</text><text class="breeze-shell-r4" 
x="24.4" y="3558" textLength="244" 
clip-path="url(#breeze-shell-line-145)">--keep-env-variables</text><text 
class="breeze-shell-r1" x="353.8" y="3558" textLength="1000.4" 
clip-path="url(#breeze-shell-line-145)">Do&#160;not&#160;clear&#160;environment&#160;variables&#160;that&#160;might&#160;have&#160;side&#160;effect&#160;while&#160;running&#
 [...]
+</text><text class="breeze-shell-r5" x="0" y="3582.4" textLength="1464" 
clip-path="url(#breeze-shell-line-146)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-shell-r1" x="1464" y="3582.4" textLength="12.2" 
clip-path="url(#breeze-shell-line-146)">
+</text><text class="breeze-shell-r5" x="0" y="3606.8" textLength="24.4" 
clip-path="url(#breeze-shell-line-147)">╭─</text><text class="breeze-shell-r5" 
x="24.4" y="3606.8" textLength="195.2" 
clip-path="url(#breeze-shell-line-147)">&#160;Common&#160;options&#160;</text><text
 class="breeze-shell-r5" x="219.6" y="3606.8" textLength="1220" 
clip-path="url(#breeze-shell-line-147)">────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 cl [...]
+</text><text class="breeze-shell-r5" x="0" y="3631.2" textLength="12.2" 
clip-path="url(#breeze-shell-line-148)">│</text><text class="breeze-shell-r4" 
x="24.4" y="3631.2" textLength="97.6" 
clip-path="url(#breeze-shell-line-148)">--answer</text><text 
class="breeze-shell-r6" x="158.6" y="3631.2" textLength="24.4" 
clip-path="url(#breeze-shell-line-148)">-a</text><text class="breeze-shell-r1" 
x="207.4" y="3631.2" textLength="317.2" 
clip-path="url(#breeze-shell-line-148)">Force&#160;answer&#16 [...]
+</text><text class="breeze-shell-r5" x="0" y="3655.6" textLength="12.2" 
clip-path="url(#breeze-shell-line-149)">│</text><text class="breeze-shell-r4" 
x="24.4" y="3655.6" textLength="109.8" 
clip-path="url(#breeze-shell-line-149)">--dry-run</text><text 
class="breeze-shell-r6" x="158.6" y="3655.6" textLength="24.4" 
clip-path="url(#breeze-shell-line-149)">-D</text><text class="breeze-shell-r1" 
x="207.4" y="3655.6" textLength="719.8" 
clip-path="url(#breeze-shell-line-149)">If&#160;dry-run&#16 [...]
+</text><text class="breeze-shell-r5" x="0" y="3680" textLength="12.2" 
clip-path="url(#breeze-shell-line-150)">│</text><text class="breeze-shell-r4" 
x="24.4" y="3680" textLength="109.8" 
clip-path="url(#breeze-shell-line-150)">--verbose</text><text 
class="breeze-shell-r6" x="158.6" y="3680" textLength="24.4" 
clip-path="url(#breeze-shell-line-150)">-v</text><text class="breeze-shell-r1" 
x="207.4" y="3680" textLength="585.6" 
clip-path="url(#breeze-shell-line-150)">Print&#160;verbose&#160;inf [...]
+</text><text class="breeze-shell-r5" x="0" y="3704.4" textLength="12.2" 
clip-path="url(#breeze-shell-line-151)">│</text><text class="breeze-shell-r4" 
x="24.4" y="3704.4" textLength="73.2" 
clip-path="url(#breeze-shell-line-151)">--help</text><text 
class="breeze-shell-r6" x="158.6" y="3704.4" textLength="24.4" 
clip-path="url(#breeze-shell-line-151)">-h</text><text class="breeze-shell-r1" 
x="207.4" y="3704.4" textLength="329.4" 
clip-path="url(#breeze-shell-line-151)">Show&#160;this&#160;mes [...]
+</text><text class="breeze-shell-r5" x="0" y="3728.8" textLength="1464" 
clip-path="url(#breeze-shell-line-152)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-shell-r1" x="1464" y="3728.8" textLength="12.2" 
clip-path="url(#breeze-shell-line-152)">
 </text>
     </g>
     </g>
diff --git a/dev/breeze/doc/images/output_shell.txt 
b/dev/breeze/doc/images/output_shell.txt
index ea3e916b67..bf6f6c56b4 100644
--- a/dev/breeze/doc/images/output_shell.txt
+++ b/dev/breeze/doc/images/output_shell.txt
@@ -1 +1 @@
-84c9572359eef66076ea6af1355fdda7
+a5bba63821f20893fc787cc71c6a5c66
diff --git a/dev/breeze/doc/images/output_testing_db-tests.svg 
b/dev/breeze/doc/images/output_testing_db-tests.svg
index 391e9843c8..78943ade78 100644
--- a/dev/breeze/doc/images/output_testing_db-tests.svg
+++ b/dev/breeze/doc/images/output_testing_db-tests.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 2612.0" 
xmlns="http://www.w3.org/2000/svg";>
+<svg class="rich-terminal" viewBox="0 0 1482 2660.7999999999997" 
xmlns="http://www.w3.org/2000/svg";>
     <!-- Generated with Rich https://www.textualize.io -->
     <style>
 
@@ -43,7 +43,7 @@
 
     <defs>
     <clipPath id="breeze-testing-db-tests-clip-terminal">
-      <rect x="0" y="0" width="1463.0" height="2561.0" />
+      <rect x="0" y="0" width="1463.0" height="2609.7999999999997" />
     </clipPath>
     <clipPath id="breeze-testing-db-tests-line-0">
     <rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -357,9 +357,15 @@
 <clipPath id="breeze-testing-db-tests-line-103">
     <rect x="0" y="2514.7" width="1464" height="24.65"/>
             </clipPath>
+<clipPath id="breeze-testing-db-tests-line-104">
+    <rect x="0" y="2539.1" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-testing-db-tests-line-105">
+    <rect x="0" y="2563.5" width="1464" height="24.65"/>
+            </clipPath>
     </defs>
 
-    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="2610" rx="8"/><text 
class="breeze-testing-db-tests-title" fill="#c5c8c6" text-anchor="middle" 
x="740" y="27">Command:&#160;testing&#160;db-tests</text>
+    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="2658.8" rx="8"/><text 
class="breeze-testing-db-tests-title" fill="#c5c8c6" text-anchor="middle" 
x="740" y="27">Command:&#160;testing&#160;db-tests</text>
             <g transform="translate(26,22)">
             <circle cx="0" cy="0" r="7" fill="#ff5f57"/>
             <circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -468,12 +474,14 @@
 </text><text class="breeze-testing-db-tests-r5" x="0" y="2362.4" 
textLength="12.2" 
clip-path="url(#breeze-testing-db-tests-line-96)">│</text><text 
class="breeze-testing-db-tests-r4" x="24.4" y="2362.4" textLength="195.2" 
clip-path="url(#breeze-testing-db-tests-line-96)">--skip-providers</text><text 
class="breeze-testing-db-tests-r1" x="768.6" y="2362.4" textLength="671" 
clip-path="url(#breeze-testing-db-tests-line-96)">Space-separated&#160;list&#160;of&#160;provider&#160;ids&#160;to&#160
 [...]
 </text><text class="breeze-testing-db-tests-r5" x="0" y="2386.8" 
textLength="12.2" 
clip-path="url(#breeze-testing-db-tests-line-97)">│</text><text 
class="breeze-testing-db-tests-r1" x="768.6" y="2386.8" textLength="671" 
clip-path="url(#breeze-testing-db-tests-line-97)">running&#160;tests&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 [...]
 </text><text class="breeze-testing-db-tests-r5" x="0" y="2411.2" 
textLength="12.2" 
clip-path="url(#breeze-testing-db-tests-line-98)">│</text><text 
class="breeze-testing-db-tests-r6" x="768.6" y="2411.2" textLength="671" 
clip-path="url(#breeze-testing-db-tests-line-98)">(TEXT)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 [...]
-</text><text class="breeze-testing-db-tests-r5" x="0" y="2435.6" 
textLength="1464" 
clip-path="url(#breeze-testing-db-tests-line-99)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-testing-db-tests-r1" x="1464" y="2435.6" textLength="12.2" 
clip-path="url(#breeze-testing-db-tests-line-99)">
-</text><text class="breeze-testing-db-tests-r5" x="0" y="2460" 
textLength="24.4" 
clip-path="url(#breeze-testing-db-tests-line-100)">╭─</text><text 
class="breeze-testing-db-tests-r5" x="24.4" y="2460" textLength="195.2" 
clip-path="url(#breeze-testing-db-tests-line-100)">&#160;Common&#160;options&#160;</text><text
 class="breeze-testing-db-tests-r5" x="219.6" y="2460" textLength="1220" 
clip-path="url(#breeze-testing-db-tests-line-100)">───────────────────────────────────────────────────────
 [...]
-</text><text class="breeze-testing-db-tests-r5" x="0" y="2484.4" 
textLength="12.2" 
clip-path="url(#breeze-testing-db-tests-line-101)">│</text><text 
class="breeze-testing-db-tests-r4" x="24.4" y="2484.4" textLength="109.8" 
clip-path="url(#breeze-testing-db-tests-line-101)">--dry-run</text><text 
class="breeze-testing-db-tests-r7" x="158.6" y="2484.4" textLength="24.4" 
clip-path="url(#breeze-testing-db-tests-line-101)">-D</text><text 
class="breeze-testing-db-tests-r1" x="207.4" y="2484.4" t [...]
-</text><text class="breeze-testing-db-tests-r5" x="0" y="2508.8" 
textLength="12.2" 
clip-path="url(#breeze-testing-db-tests-line-102)">│</text><text 
class="breeze-testing-db-tests-r4" x="24.4" y="2508.8" textLength="109.8" 
clip-path="url(#breeze-testing-db-tests-line-102)">--verbose</text><text 
class="breeze-testing-db-tests-r7" x="158.6" y="2508.8" textLength="24.4" 
clip-path="url(#breeze-testing-db-tests-line-102)">-v</text><text 
class="breeze-testing-db-tests-r1" x="207.4" y="2508.8" t [...]
-</text><text class="breeze-testing-db-tests-r5" x="0" y="2533.2" 
textLength="12.2" 
clip-path="url(#breeze-testing-db-tests-line-103)">│</text><text 
class="breeze-testing-db-tests-r4" x="24.4" y="2533.2" textLength="73.2" 
clip-path="url(#breeze-testing-db-tests-line-103)">--help</text><text 
class="breeze-testing-db-tests-r7" x="158.6" y="2533.2" textLength="24.4" 
clip-path="url(#breeze-testing-db-tests-line-103)">-h</text><text 
class="breeze-testing-db-tests-r1" x="207.4" y="2533.2" textL [...]
-</text><text class="breeze-testing-db-tests-r5" x="0" y="2557.6" 
textLength="1464" 
clip-path="url(#breeze-testing-db-tests-line-104)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-testing-db-tests-r1" x="1464" y="2557.6" textLength="12.2" 
clip-path="url(#breeze-testing-db-tests-line-104)">
+</text><text class="breeze-testing-db-tests-r5" x="0" y="2435.6" 
textLength="12.2" 
clip-path="url(#breeze-testing-db-tests-line-99)">│</text><text 
class="breeze-testing-db-tests-r4" x="24.4" y="2435.6" textLength="244" 
clip-path="url(#breeze-testing-db-tests-line-99)">--keep-env-variables</text><text
 class="breeze-testing-db-tests-r1" x="768.6" y="2435.6" textLength="671" 
clip-path="url(#breeze-testing-db-tests-line-99)">Do&#160;not&#160;clear&#160;environment&#160;variables&#160;that&#1
 [...]
+</text><text class="breeze-testing-db-tests-r5" x="0" y="2460" 
textLength="12.2" 
clip-path="url(#breeze-testing-db-tests-line-100)">│</text><text 
class="breeze-testing-db-tests-r1" x="768.6" y="2460" textLength="671" 
clip-path="url(#breeze-testing-db-tests-line-100)">effect&#160;while&#160;running&#160;tests&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><t
 [...]
+</text><text class="breeze-testing-db-tests-r5" x="0" y="2484.4" 
textLength="1464" 
clip-path="url(#breeze-testing-db-tests-line-101)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-testing-db-tests-r1" x="1464" y="2484.4" textLength="12.2" 
clip-path="url(#breeze-testing-db-tests-line-101)">
+</text><text class="breeze-testing-db-tests-r5" x="0" y="2508.8" 
textLength="24.4" 
clip-path="url(#breeze-testing-db-tests-line-102)">╭─</text><text 
class="breeze-testing-db-tests-r5" x="24.4" y="2508.8" textLength="195.2" 
clip-path="url(#breeze-testing-db-tests-line-102)">&#160;Common&#160;options&#160;</text><text
 class="breeze-testing-db-tests-r5" x="219.6" y="2508.8" textLength="1220" 
clip-path="url(#breeze-testing-db-tests-line-102)">─────────────────────────────────────────────────
 [...]
+</text><text class="breeze-testing-db-tests-r5" x="0" y="2533.2" 
textLength="12.2" 
clip-path="url(#breeze-testing-db-tests-line-103)">│</text><text 
class="breeze-testing-db-tests-r4" x="24.4" y="2533.2" textLength="109.8" 
clip-path="url(#breeze-testing-db-tests-line-103)">--dry-run</text><text 
class="breeze-testing-db-tests-r7" x="158.6" y="2533.2" textLength="24.4" 
clip-path="url(#breeze-testing-db-tests-line-103)">-D</text><text 
class="breeze-testing-db-tests-r1" x="207.4" y="2533.2" t [...]
+</text><text class="breeze-testing-db-tests-r5" x="0" y="2557.6" 
textLength="12.2" 
clip-path="url(#breeze-testing-db-tests-line-104)">│</text><text 
class="breeze-testing-db-tests-r4" x="24.4" y="2557.6" textLength="109.8" 
clip-path="url(#breeze-testing-db-tests-line-104)">--verbose</text><text 
class="breeze-testing-db-tests-r7" x="158.6" y="2557.6" textLength="24.4" 
clip-path="url(#breeze-testing-db-tests-line-104)">-v</text><text 
class="breeze-testing-db-tests-r1" x="207.4" y="2557.6" t [...]
+</text><text class="breeze-testing-db-tests-r5" x="0" y="2582" 
textLength="12.2" 
clip-path="url(#breeze-testing-db-tests-line-105)">│</text><text 
class="breeze-testing-db-tests-r4" x="24.4" y="2582" textLength="73.2" 
clip-path="url(#breeze-testing-db-tests-line-105)">--help</text><text 
class="breeze-testing-db-tests-r7" x="158.6" y="2582" textLength="24.4" 
clip-path="url(#breeze-testing-db-tests-line-105)">-h</text><text 
class="breeze-testing-db-tests-r1" x="207.4" y="2582" textLength="3 [...]
+</text><text class="breeze-testing-db-tests-r5" x="0" y="2606.4" 
textLength="1464" 
clip-path="url(#breeze-testing-db-tests-line-106)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-testing-db-tests-r1" x="1464" y="2606.4" textLength="12.2" 
clip-path="url(#breeze-testing-db-tests-line-106)">
 </text>
     </g>
     </g>
diff --git a/dev/breeze/doc/images/output_testing_db-tests.txt 
b/dev/breeze/doc/images/output_testing_db-tests.txt
index c4bf6a5ab1..79046b465a 100644
--- a/dev/breeze/doc/images/output_testing_db-tests.txt
+++ b/dev/breeze/doc/images/output_testing_db-tests.txt
@@ -1 +1 @@
-bb0fb04d5bfb7c35f30f42f1f85743e5
+5c81d62f63ff4d874b1f148e5de2a6e5
diff --git a/dev/breeze/doc/images/output_testing_non-db-tests.svg 
b/dev/breeze/doc/images/output_testing_non-db-tests.svg
index 8385ef5733..ba15884ec6 100644
--- a/dev/breeze/doc/images/output_testing_non-db-tests.svg
+++ b/dev/breeze/doc/images/output_testing_non-db-tests.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 2416.7999999999997" 
xmlns="http://www.w3.org/2000/svg";>
+<svg class="rich-terminal" viewBox="0 0 1482 2465.6" 
xmlns="http://www.w3.org/2000/svg";>
     <!-- Generated with Rich https://www.textualize.io -->
     <style>
 
@@ -43,7 +43,7 @@
 
     <defs>
     <clipPath id="breeze-testing-non-db-tests-clip-terminal">
-      <rect x="0" y="0" width="1463.0" height="2365.7999999999997" />
+      <rect x="0" y="0" width="1463.0" height="2414.6" />
     </clipPath>
     <clipPath id="breeze-testing-non-db-tests-line-0">
     <rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -333,9 +333,15 @@
 <clipPath id="breeze-testing-non-db-tests-line-95">
     <rect x="0" y="2319.5" width="1464" height="24.65"/>
             </clipPath>
+<clipPath id="breeze-testing-non-db-tests-line-96">
+    <rect x="0" y="2343.9" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-testing-non-db-tests-line-97">
+    <rect x="0" y="2368.3" width="1464" height="24.65"/>
+            </clipPath>
     </defs>
 
-    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="2414.8" rx="8"/><text 
class="breeze-testing-non-db-tests-title" fill="#c5c8c6" text-anchor="middle" 
x="740" y="27">Command:&#160;testing&#160;non-db-tests</text>
+    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="2463.6" rx="8"/><text 
class="breeze-testing-non-db-tests-title" fill="#c5c8c6" text-anchor="middle" 
x="740" y="27">Command:&#160;testing&#160;non-db-tests</text>
             <g transform="translate(26,22)">
             <circle cx="0" cy="0" r="7" fill="#ff5f57"/>
             <circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -436,12 +442,14 @@
 </text><text class="breeze-testing-non-db-tests-r5" x="0" y="2167.2" 
textLength="12.2" 
clip-path="url(#breeze-testing-non-db-tests-line-88)">│</text><text 
class="breeze-testing-non-db-tests-r4" x="24.4" y="2167.2" textLength="195.2" 
clip-path="url(#breeze-testing-non-db-tests-line-88)">--skip-providers</text><text
 class="breeze-testing-non-db-tests-r1" x="768.6" y="2167.2" textLength="671" 
clip-path="url(#breeze-testing-non-db-tests-line-88)">Space-separated&#160;list&#160;of&#160;provid
 [...]
 </text><text class="breeze-testing-non-db-tests-r5" x="0" y="2191.6" 
textLength="12.2" 
clip-path="url(#breeze-testing-non-db-tests-line-89)">│</text><text 
class="breeze-testing-non-db-tests-r1" x="768.6" y="2191.6" textLength="671" 
clip-path="url(#breeze-testing-non-db-tests-line-89)">running&#160;tests&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#
 [...]
 </text><text class="breeze-testing-non-db-tests-r5" x="0" y="2216" 
textLength="12.2" 
clip-path="url(#breeze-testing-non-db-tests-line-90)">│</text><text 
class="breeze-testing-non-db-tests-r6" x="768.6" y="2216" textLength="671" 
clip-path="url(#breeze-testing-non-db-tests-line-90)">(TEXT)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 [...]
-</text><text class="breeze-testing-non-db-tests-r5" x="0" y="2240.4" 
textLength="1464" 
clip-path="url(#breeze-testing-non-db-tests-line-91)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-testing-non-db-tests-r1" x="1464" y="2240.4" textLength="12.2" 
clip-path="url(#breeze-testing-non-db-tests-line-91)">
-</text><text class="breeze-testing-non-db-tests-r5" x="0" y="2264.8" 
textLength="24.4" 
clip-path="url(#breeze-testing-non-db-tests-line-92)">╭─</text><text 
class="breeze-testing-non-db-tests-r5" x="24.4" y="2264.8" textLength="195.2" 
clip-path="url(#breeze-testing-non-db-tests-line-92)">&#160;Common&#160;options&#160;</text><text
 class="breeze-testing-non-db-tests-r5" x="219.6" y="2264.8" textLength="1220" 
clip-path="url(#breeze-testing-non-db-tests-line-92)">────────────────────────────
 [...]
-</text><text class="breeze-testing-non-db-tests-r5" x="0" y="2289.2" 
textLength="12.2" 
clip-path="url(#breeze-testing-non-db-tests-line-93)">│</text><text 
class="breeze-testing-non-db-tests-r4" x="24.4" y="2289.2" textLength="109.8" 
clip-path="url(#breeze-testing-non-db-tests-line-93)">--dry-run</text><text 
class="breeze-testing-non-db-tests-r7" x="158.6" y="2289.2" textLength="24.4" 
clip-path="url(#breeze-testing-non-db-tests-line-93)">-D</text><text 
class="breeze-testing-non-db-tests-r [...]
-</text><text class="breeze-testing-non-db-tests-r5" x="0" y="2313.6" 
textLength="12.2" 
clip-path="url(#breeze-testing-non-db-tests-line-94)">│</text><text 
class="breeze-testing-non-db-tests-r4" x="24.4" y="2313.6" textLength="109.8" 
clip-path="url(#breeze-testing-non-db-tests-line-94)">--verbose</text><text 
class="breeze-testing-non-db-tests-r7" x="158.6" y="2313.6" textLength="24.4" 
clip-path="url(#breeze-testing-non-db-tests-line-94)">-v</text><text 
class="breeze-testing-non-db-tests-r [...]
-</text><text class="breeze-testing-non-db-tests-r5" x="0" y="2338" 
textLength="12.2" 
clip-path="url(#breeze-testing-non-db-tests-line-95)">│</text><text 
class="breeze-testing-non-db-tests-r4" x="24.4" y="2338" textLength="73.2" 
clip-path="url(#breeze-testing-non-db-tests-line-95)">--help</text><text 
class="breeze-testing-non-db-tests-r7" x="158.6" y="2338" textLength="24.4" 
clip-path="url(#breeze-testing-non-db-tests-line-95)">-h</text><text 
class="breeze-testing-non-db-tests-r1" x="207. [...]
-</text><text class="breeze-testing-non-db-tests-r5" x="0" y="2362.4" 
textLength="1464" 
clip-path="url(#breeze-testing-non-db-tests-line-96)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-testing-non-db-tests-r1" x="1464" y="2362.4" textLength="12.2" 
clip-path="url(#breeze-testing-non-db-tests-line-96)">
+</text><text class="breeze-testing-non-db-tests-r5" x="0" y="2240.4" 
textLength="12.2" 
clip-path="url(#breeze-testing-non-db-tests-line-91)">│</text><text 
class="breeze-testing-non-db-tests-r4" x="24.4" y="2240.4" textLength="244" 
clip-path="url(#breeze-testing-non-db-tests-line-91)">--keep-env-variables</text><text
 class="breeze-testing-non-db-tests-r1" x="768.6" y="2240.4" textLength="671" 
clip-path="url(#breeze-testing-non-db-tests-line-91)">Do&#160;not&#160;clear&#160;environment&#16
 [...]
+</text><text class="breeze-testing-non-db-tests-r5" x="0" y="2264.8" 
textLength="12.2" 
clip-path="url(#breeze-testing-non-db-tests-line-92)">│</text><text 
class="breeze-testing-non-db-tests-r1" x="768.6" y="2264.8" textLength="671" 
clip-path="url(#breeze-testing-non-db-tests-line-92)">effect&#160;while&#160;running&#160;tests&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#1
 [...]
+</text><text class="breeze-testing-non-db-tests-r5" x="0" y="2289.2" 
textLength="1464" 
clip-path="url(#breeze-testing-non-db-tests-line-93)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-testing-non-db-tests-r1" x="1464" y="2289.2" textLength="12.2" 
clip-path="url(#breeze-testing-non-db-tests-line-93)">
+</text><text class="breeze-testing-non-db-tests-r5" x="0" y="2313.6" 
textLength="24.4" 
clip-path="url(#breeze-testing-non-db-tests-line-94)">╭─</text><text 
class="breeze-testing-non-db-tests-r5" x="24.4" y="2313.6" textLength="195.2" 
clip-path="url(#breeze-testing-non-db-tests-line-94)">&#160;Common&#160;options&#160;</text><text
 class="breeze-testing-non-db-tests-r5" x="219.6" y="2313.6" textLength="1220" 
clip-path="url(#breeze-testing-non-db-tests-line-94)">────────────────────────────
 [...]
+</text><text class="breeze-testing-non-db-tests-r5" x="0" y="2338" 
textLength="12.2" 
clip-path="url(#breeze-testing-non-db-tests-line-95)">│</text><text 
class="breeze-testing-non-db-tests-r4" x="24.4" y="2338" textLength="109.8" 
clip-path="url(#breeze-testing-non-db-tests-line-95)">--dry-run</text><text 
class="breeze-testing-non-db-tests-r7" x="158.6" y="2338" textLength="24.4" 
clip-path="url(#breeze-testing-non-db-tests-line-95)">-D</text><text 
class="breeze-testing-non-db-tests-r1" x=" [...]
+</text><text class="breeze-testing-non-db-tests-r5" x="0" y="2362.4" 
textLength="12.2" 
clip-path="url(#breeze-testing-non-db-tests-line-96)">│</text><text 
class="breeze-testing-non-db-tests-r4" x="24.4" y="2362.4" textLength="109.8" 
clip-path="url(#breeze-testing-non-db-tests-line-96)">--verbose</text><text 
class="breeze-testing-non-db-tests-r7" x="158.6" y="2362.4" textLength="24.4" 
clip-path="url(#breeze-testing-non-db-tests-line-96)">-v</text><text 
class="breeze-testing-non-db-tests-r [...]
+</text><text class="breeze-testing-non-db-tests-r5" x="0" y="2386.8" 
textLength="12.2" 
clip-path="url(#breeze-testing-non-db-tests-line-97)">│</text><text 
class="breeze-testing-non-db-tests-r4" x="24.4" y="2386.8" textLength="73.2" 
clip-path="url(#breeze-testing-non-db-tests-line-97)">--help</text><text 
class="breeze-testing-non-db-tests-r7" x="158.6" y="2386.8" textLength="24.4" 
clip-path="url(#breeze-testing-non-db-tests-line-97)">-h</text><text 
class="breeze-testing-non-db-tests-r1" x [...]
+</text><text class="breeze-testing-non-db-tests-r5" x="0" y="2411.2" 
textLength="1464" 
clip-path="url(#breeze-testing-non-db-tests-line-98)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-testing-non-db-tests-r1" x="1464" y="2411.2" textLength="12.2" 
clip-path="url(#breeze-testing-non-db-tests-line-98)">
 </text>
     </g>
     </g>
diff --git a/dev/breeze/doc/images/output_testing_non-db-tests.txt 
b/dev/breeze/doc/images/output_testing_non-db-tests.txt
index ad9bd4cd3d..d541217e8d 100644
--- a/dev/breeze/doc/images/output_testing_non-db-tests.txt
+++ b/dev/breeze/doc/images/output_testing_non-db-tests.txt
@@ -1 +1 @@
-de053d3c185f555646e70ba8c818b646
+a9b2111b5c2f75bc3b827445cf9e3daa
diff --git a/dev/breeze/doc/images/output_testing_tests.svg 
b/dev/breeze/doc/images/output_testing_tests.svg
index 7876ef08a1..d9b94589e6 100644
--- a/dev/breeze/doc/images/output_testing_tests.svg
+++ b/dev/breeze/doc/images/output_testing_tests.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 3051.2" 
xmlns="http://www.w3.org/2000/svg";>
+<svg class="rich-terminal" viewBox="0 0 1482 3100.0" 
xmlns="http://www.w3.org/2000/svg";>
     <!-- Generated with Rich https://www.textualize.io -->
     <style>
 
@@ -43,7 +43,7 @@
 
     <defs>
     <clipPath id="breeze-testing-tests-clip-terminal">
-      <rect x="0" y="0" width="1463.0" height="3000.2" />
+      <rect x="0" y="0" width="1463.0" height="3049.0" />
     </clipPath>
     <clipPath id="breeze-testing-tests-line-0">
     <rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -411,9 +411,15 @@
 <clipPath id="breeze-testing-tests-line-121">
     <rect x="0" y="2953.9" width="1464" height="24.65"/>
             </clipPath>
+<clipPath id="breeze-testing-tests-line-122">
+    <rect x="0" y="2978.3" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-testing-tests-line-123">
+    <rect x="0" y="3002.7" width="1464" height="24.65"/>
+            </clipPath>
     </defs>
 
-    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="3049.2" rx="8"/><text 
class="breeze-testing-tests-title" fill="#c5c8c6" text-anchor="middle" x="740" 
y="27">Command:&#160;testing&#160;tests</text>
+    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="3098" rx="8"/><text 
class="breeze-testing-tests-title" fill="#c5c8c6" text-anchor="middle" x="740" 
y="27">Command:&#160;testing&#160;tests</text>
             <g transform="translate(26,22)">
             <circle cx="0" cy="0" r="7" fill="#ff5f57"/>
             <circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -540,12 +546,14 @@
 </text><text class="breeze-testing-tests-r5" x="0" y="2801.6" 
textLength="12.2" clip-path="url(#breeze-testing-tests-line-114)">│</text><text 
class="breeze-testing-tests-r4" x="24.4" y="2801.6" textLength="195.2" 
clip-path="url(#breeze-testing-tests-line-114)">--skip-providers</text><text 
class="breeze-testing-tests-r1" x="768.6" y="2801.6" textLength="671" 
clip-path="url(#breeze-testing-tests-line-114)">Space-separated&#160;list&#160;of&#160;provider&#160;ids&#160;to&#160;skip&#160;when
 [...]
 </text><text class="breeze-testing-tests-r5" x="0" y="2826" textLength="12.2" 
clip-path="url(#breeze-testing-tests-line-115)">│</text><text 
class="breeze-testing-tests-r1" x="768.6" y="2826" textLength="671" 
clip-path="url(#breeze-testing-tests-line-115)">running&#160;tests&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#
 [...]
 </text><text class="breeze-testing-tests-r5" x="0" y="2850.4" 
textLength="12.2" clip-path="url(#breeze-testing-tests-line-116)">│</text><text 
class="breeze-testing-tests-r7" x="768.6" y="2850.4" textLength="671" 
clip-path="url(#breeze-testing-tests-line-116)">(TEXT)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
-</text><text class="breeze-testing-tests-r5" x="0" y="2874.8" 
textLength="1464" 
clip-path="url(#breeze-testing-tests-line-117)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-testing-tests-r1" x="1464" y="2874.8" textLength="12.2" 
clip-path="url(#breeze-testing-tests-line-117)">
-</text><text class="breeze-testing-tests-r5" x="0" y="2899.2" 
textLength="24.4" 
clip-path="url(#breeze-testing-tests-line-118)">╭─</text><text 
class="breeze-testing-tests-r5" x="24.4" y="2899.2" textLength="195.2" 
clip-path="url(#breeze-testing-tests-line-118)">&#160;Common&#160;options&#160;</text><text
 class="breeze-testing-tests-r5" x="219.6" y="2899.2" textLength="1220" 
clip-path="url(#breeze-testing-tests-line-118)">───────────────────────────────────────────────────────────────────
 [...]
-</text><text class="breeze-testing-tests-r5" x="0" y="2923.6" 
textLength="12.2" clip-path="url(#breeze-testing-tests-line-119)">│</text><text 
class="breeze-testing-tests-r4" x="24.4" y="2923.6" textLength="109.8" 
clip-path="url(#breeze-testing-tests-line-119)">--dry-run</text><text 
class="breeze-testing-tests-r6" x="158.6" y="2923.6" textLength="24.4" 
clip-path="url(#breeze-testing-tests-line-119)">-D</text><text 
class="breeze-testing-tests-r1" x="207.4" y="2923.6" textLength="719.8" cli 
[...]
-</text><text class="breeze-testing-tests-r5" x="0" y="2948" textLength="12.2" 
clip-path="url(#breeze-testing-tests-line-120)">│</text><text 
class="breeze-testing-tests-r4" x="24.4" y="2948" textLength="109.8" 
clip-path="url(#breeze-testing-tests-line-120)">--verbose</text><text 
class="breeze-testing-tests-r6" x="158.6" y="2948" textLength="24.4" 
clip-path="url(#breeze-testing-tests-line-120)">-v</text><text 
class="breeze-testing-tests-r1" x="207.4" y="2948" textLength="585.6" 
clip-path=" [...]
-</text><text class="breeze-testing-tests-r5" x="0" y="2972.4" 
textLength="12.2" clip-path="url(#breeze-testing-tests-line-121)">│</text><text 
class="breeze-testing-tests-r4" x="24.4" y="2972.4" textLength="73.2" 
clip-path="url(#breeze-testing-tests-line-121)">--help</text><text 
class="breeze-testing-tests-r6" x="158.6" y="2972.4" textLength="24.4" 
clip-path="url(#breeze-testing-tests-line-121)">-h</text><text 
class="breeze-testing-tests-r1" x="207.4" y="2972.4" textLength="329.4" clip-pa 
[...]
-</text><text class="breeze-testing-tests-r5" x="0" y="2996.8" 
textLength="1464" 
clip-path="url(#breeze-testing-tests-line-122)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-testing-tests-r1" x="1464" y="2996.8" textLength="12.2" 
clip-path="url(#breeze-testing-tests-line-122)">
+</text><text class="breeze-testing-tests-r5" x="0" y="2874.8" 
textLength="12.2" clip-path="url(#breeze-testing-tests-line-117)">│</text><text 
class="breeze-testing-tests-r4" x="24.4" y="2874.8" textLength="244" 
clip-path="url(#breeze-testing-tests-line-117)">--keep-env-variables</text><text
 class="breeze-testing-tests-r1" x="768.6" y="2874.8" textLength="671" 
clip-path="url(#breeze-testing-tests-line-117)">Do&#160;not&#160;clear&#160;environment&#160;variables&#160;that&#160;might&#160;h
 [...]
+</text><text class="breeze-testing-tests-r5" x="0" y="2899.2" 
textLength="12.2" clip-path="url(#breeze-testing-tests-line-118)">│</text><text 
class="breeze-testing-tests-r1" x="768.6" y="2899.2" textLength="671" 
clip-path="url(#breeze-testing-tests-line-118)">effect&#160;while&#160;running&#160;tests&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 clas [...]
+</text><text class="breeze-testing-tests-r5" x="0" y="2923.6" 
textLength="1464" 
clip-path="url(#breeze-testing-tests-line-119)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-testing-tests-r1" x="1464" y="2923.6" textLength="12.2" 
clip-path="url(#breeze-testing-tests-line-119)">
+</text><text class="breeze-testing-tests-r5" x="0" y="2948" textLength="24.4" 
clip-path="url(#breeze-testing-tests-line-120)">╭─</text><text 
class="breeze-testing-tests-r5" x="24.4" y="2948" textLength="195.2" 
clip-path="url(#breeze-testing-tests-line-120)">&#160;Common&#160;options&#160;</text><text
 class="breeze-testing-tests-r5" x="219.6" y="2948" textLength="1220" 
clip-path="url(#breeze-testing-tests-line-120)">─────────────────────────────────────────────────────────────────────────
 [...]
+</text><text class="breeze-testing-tests-r5" x="0" y="2972.4" 
textLength="12.2" clip-path="url(#breeze-testing-tests-line-121)">│</text><text 
class="breeze-testing-tests-r4" x="24.4" y="2972.4" textLength="109.8" 
clip-path="url(#breeze-testing-tests-line-121)">--dry-run</text><text 
class="breeze-testing-tests-r6" x="158.6" y="2972.4" textLength="24.4" 
clip-path="url(#breeze-testing-tests-line-121)">-D</text><text 
class="breeze-testing-tests-r1" x="207.4" y="2972.4" textLength="719.8" cli 
[...]
+</text><text class="breeze-testing-tests-r5" x="0" y="2996.8" 
textLength="12.2" clip-path="url(#breeze-testing-tests-line-122)">│</text><text 
class="breeze-testing-tests-r4" x="24.4" y="2996.8" textLength="109.8" 
clip-path="url(#breeze-testing-tests-line-122)">--verbose</text><text 
class="breeze-testing-tests-r6" x="158.6" y="2996.8" textLength="24.4" 
clip-path="url(#breeze-testing-tests-line-122)">-v</text><text 
class="breeze-testing-tests-r1" x="207.4" y="2996.8" textLength="585.6" cli 
[...]
+</text><text class="breeze-testing-tests-r5" x="0" y="3021.2" 
textLength="12.2" clip-path="url(#breeze-testing-tests-line-123)">│</text><text 
class="breeze-testing-tests-r4" x="24.4" y="3021.2" textLength="73.2" 
clip-path="url(#breeze-testing-tests-line-123)">--help</text><text 
class="breeze-testing-tests-r6" x="158.6" y="3021.2" textLength="24.4" 
clip-path="url(#breeze-testing-tests-line-123)">-h</text><text 
class="breeze-testing-tests-r1" x="207.4" y="3021.2" textLength="329.4" clip-pa 
[...]
+</text><text class="breeze-testing-tests-r5" x="0" y="3045.6" 
textLength="1464" 
clip-path="url(#breeze-testing-tests-line-124)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-testing-tests-r1" x="1464" y="3045.6" textLength="12.2" 
clip-path="url(#breeze-testing-tests-line-124)">
 </text>
     </g>
     </g>
diff --git a/dev/breeze/doc/images/output_testing_tests.txt 
b/dev/breeze/doc/images/output_testing_tests.txt
index 731a581153..e51cb04161 100644
--- a/dev/breeze/doc/images/output_testing_tests.txt
+++ b/dev/breeze/doc/images/output_testing_tests.txt
@@ -1 +1 @@
-45c2dd92b2f83548aa9256e529d9da7e
+53dce8653118d4af6c7867ae9a2d0eff
diff --git a/dev/breeze/src/airflow_breeze/commands/common_options.py 
b/dev/breeze/src/airflow_breeze/commands/common_options.py
index f8a4c69edf..32100387c5 100644
--- a/dev/breeze/src/airflow_breeze/commands/common_options.py
+++ b/dev/breeze/src/airflow_breeze/commands/common_options.py
@@ -235,6 +235,12 @@ option_image_tag_for_running = click.option(
     default="latest",
     envvar="IMAGE_TAG",
 )
+option_keep_env_variables = click.option(
+    "--keep-env-variables",
+    help="Do not clear environment variables that might have side effect while 
running tests",
+    envvar="KEEP_ENV_VARIABLES",
+    is_flag=True,
+)
 option_max_time = click.option(
     "--max-time",
     help="Maximum time that the command should take - if it takes longer, the 
command will fail.",
diff --git a/dev/breeze/src/airflow_breeze/commands/developer_commands.py 
b/dev/breeze/src/airflow_breeze/commands/developer_commands.py
index 03f2b63280..a576e34c4b 100644
--- a/dev/breeze/src/airflow_breeze/commands/developer_commands.py
+++ b/dev/breeze/src/airflow_breeze/commands/developer_commands.py
@@ -49,6 +49,7 @@ from airflow_breeze.commands.common_options import (
     option_include_removed_providers,
     option_installation_package_format,
     option_integration,
+    option_keep_env_variables,
     option_max_time,
     option_mount_sources,
     option_mysql_version,
@@ -277,6 +278,7 @@ option_install_airflow_with_constraints_default_true = 
click.option(
 @option_install_selected_providers
 @option_installation_package_format
 @option_integration
+@option_keep_env_variables
 @option_max_time
 @option_mount_sources
 @option_mysql_version
@@ -329,6 +331,7 @@ def shell(
     install_selected_providers: str,
     install_airflow_with_constraints: bool,
     integration: tuple[str, ...],
+    keep_env_variables: bool,
     max_time: int | None,
     mount_sources: str,
     mysql_version: str,
@@ -395,6 +398,7 @@ def shell(
         install_airflow_with_constraints=install_airflow_with_constraints,
         install_selected_providers=install_selected_providers,
         integration=integration,
+        keep_env_variables=keep_env_variables,
         mount_sources=mount_sources,
         mysql_version=mysql_version,
         package_format=package_format,
diff --git 
a/dev/breeze/src/airflow_breeze/commands/developer_commands_config.py 
b/dev/breeze/src/airflow_breeze/commands/developer_commands_config.py
index d4661ba9a4..99ad1964b4 100644
--- a/dev/breeze/src/airflow_breeze/commands/developer_commands_config.py
+++ b/dev/breeze/src/airflow_breeze/commands/developer_commands_config.py
@@ -182,6 +182,7 @@ DEVELOPER_PARAMETERS: dict[str, list[dict[str, str | 
list[str]]]] = {
                 "--forward-credentials",
                 "--max-time",
                 "--verbose-commands",
+                "--keep-env-variables",
             ],
         },
     ],
diff --git a/dev/breeze/src/airflow_breeze/commands/testing_commands.py 
b/dev/breeze/src/airflow_breeze/commands/testing_commands.py
index 63b18a01c2..bb00cb1110 100644
--- a/dev/breeze/src/airflow_breeze/commands/testing_commands.py
+++ b/dev/breeze/src/airflow_breeze/commands/testing_commands.py
@@ -39,6 +39,7 @@ from airflow_breeze.commands.common_options import (
     option_image_tag_for_running,
     option_include_success_outputs,
     option_integration,
+    option_keep_env_variables,
     option_mount_sources,
     option_mysql_version,
     option_parallelism,
@@ -204,6 +205,7 @@ def _run_test(
             python_version=python_version,
             parallel_test_types_list=shell_params.parallel_test_types_list,
             helm_test_package=None,
+            keep_env_variables=shell_params.keep_env_variables,
         )
     )
     run_cmd.extend(list(extra_pytest_args))
@@ -507,6 +509,7 @@ option_force_sa_warnings = click.option(
 @option_include_success_outputs
 @option_integration
 @option_install_airflow_with_constraints
+@option_keep_env_variables
 @option_mount_sources
 @option_mysql_version
 @option_package_format
@@ -562,6 +565,7 @@ def command_for_tests(**kwargs):
 @option_image_tag_for_running
 @option_include_success_outputs
 @option_install_airflow_with_constraints
+@option_keep_env_variables
 @option_mount_sources
 @option_mysql_version
 @option_package_format
@@ -621,6 +625,7 @@ def command_for_db_tests(**kwargs):
 @option_image_tag_for_running
 @option_include_success_outputs
 @option_install_airflow_with_constraints
+@option_keep_env_variables
 @option_mount_sources
 @option_package_format
 @option_parallel_test_types
@@ -675,6 +680,7 @@ def _run_test_command(
     include_success_outputs: bool,
     install_airflow_with_constraints: bool,
     integration: tuple[str, ...],
+    keep_env_variables: bool,
     mount_sources: str,
     parallel_test_types: str,
     parallelism: int,
@@ -726,6 +732,7 @@ def _run_test_command(
         image_tag=image_tag,
         integration=integration,
         install_airflow_with_constraints=install_airflow_with_constraints,
+        keep_env_variables=keep_env_variables,
         mount_sources=mount_sources,
         mysql_version=mysql_version,
         package_format=package_format,
@@ -936,6 +943,7 @@ def helm_tests(
         parallel_test_types_list=[],
         python_version=shell_params.python,
         helm_test_package=helm_test_package,
+        keep_env_variables=False,
     )
     cmd = ["docker", "compose", "run", "--service-ports", "--rm", "airflow", 
*pytest_args, *extra_pytest_args]
     result = run_command(cmd, check=False, env=env, 
output_outside_the_group=True)
diff --git a/dev/breeze/src/airflow_breeze/commands/testing_commands_config.py 
b/dev/breeze/src/airflow_breeze/commands/testing_commands_config.py
index 67f5726cb2..c668f17c6a 100644
--- a/dev/breeze/src/airflow_breeze/commands/testing_commands_config.py
+++ b/dev/breeze/src/airflow_breeze/commands/testing_commands_config.py
@@ -96,6 +96,7 @@ TESTING_PARAMETERS: dict[str, list[dict[str, str | 
list[str]]]] = {
                 "--mount-sources",
                 "--skip-docker-compose-down",
                 "--skip-providers",
+                "--keep-env-variables",
             ],
         },
     ],
@@ -159,6 +160,7 @@ TESTING_PARAMETERS: dict[str, list[dict[str, str | 
list[str]]]] = {
                 "--mount-sources",
                 "--skip-docker-compose-down",
                 "--skip-providers",
+                "--keep-env-variables",
             ],
         },
     ],
@@ -225,6 +227,7 @@ TESTING_PARAMETERS: dict[str, list[dict[str, str | 
list[str]]]] = {
                 "--mount-sources",
                 "--skip-docker-compose-down",
                 "--skip-providers",
+                "--keep-env-variables",
             ],
         },
     ],
diff --git a/dev/breeze/src/airflow_breeze/params/shell_params.py 
b/dev/breeze/src/airflow_breeze/params/shell_params.py
index ec18ccda76..dd1bdbbfa5 100644
--- a/dev/breeze/src/airflow_breeze/params/shell_params.py
+++ b/dev/breeze/src/airflow_breeze/params/shell_params.py
@@ -163,6 +163,7 @@ class ShellParams:
     install_selected_providers: str | None = None
     integration: tuple[str, ...] = ()
     issue_id: str = ""
+    keep_env_variables: bool = False
     load_default_connections: bool = False
     load_example_dags: bool = False
     mount_sources: str = MOUNT_SELECTED
diff --git a/dev/breeze/src/airflow_breeze/utils/run_tests.py 
b/dev/breeze/src/airflow_breeze/utils/run_tests.py
index f9606cdc70..b53c75384a 100644
--- a/dev/breeze/src/airflow_breeze/utils/run_tests.py
+++ b/dev/breeze/src/airflow_breeze/utils/run_tests.py
@@ -309,6 +309,7 @@ def generate_args_for_pytest(
     parallel_test_types_list: list[str],
     python_version: str,
     helm_test_package: str | None,
+    keep_env_variables: bool,
 ):
     result_log_file, warnings_file, coverage_file = test_paths(test_type, 
backend, helm_test_package)
     if skip_db_tests:
@@ -395,6 +396,8 @@ def generate_args_for_pytest(
                 "--disable-warnings",
             ]
         )
+    if keep_env_variables:
+        args.append("--keep-env-variables")
     return args
 
 
diff --git a/docs/apache-airflow/core-concepts/debug.rst 
b/docs/apache-airflow/core-concepts/debug.rst
index 6dcdfa51a4..c064b781b1 100644
--- a/docs/apache-airflow/core-concepts/debug.rst
+++ b/docs/apache-airflow/core-concepts/debug.rst
@@ -36,8 +36,13 @@ To set up ``dag.test``, add these two lines to the bottom of 
your dag file:
   if __name__ == "__main__":
       dag.test()
 
-and that's it! You can add argument such as ``execution_date`` if you want to 
test argument-specific DAG runs, but otherwise
-you can run or debug DAGs as needed.
+and that's it! You can add optional arguments to fine tune the testing but 
otherwise you can run or debug DAGs as
+needed. Here are some examples of arguments:
+
+* ``execution_date`` if you want to test argument-specific DAG runs
+* ``use_executor`` if you want to test the DAG using an executor. By default 
``dag.test`` runs the DAG without an
+  executor, it just runs all the tasks locally.
+  By providing this argument, the DAG is executed using the executor 
configured in the Airflow environment.
 
 Comparison with DebugExecutor
 -----------------------------
diff --git a/tests/cli/commands/test_dag_command.py 
b/tests/cli/commands/test_dag_command.py
index ec382ef6d4..faac573684 100644
--- a/tests/cli/commands/test_dag_command.py
+++ b/tests/cli/commands/test_dag_command.py
@@ -874,7 +874,10 @@ class TestCliDags:
             [
                 mock.call(subdir=cli_args.subdir, 
dag_id="example_bash_operator"),
                 mock.call().test(
-                    execution_date=timezone.parse(DEFAULT_DATE.isoformat()), 
run_conf=None, session=mock.ANY
+                    execution_date=timezone.parse(DEFAULT_DATE.isoformat()),
+                    run_conf=None,
+                    use_executor=False,
+                    session=mock.ANY,
                 ),
             ]
         )
@@ -903,7 +906,9 @@ class TestCliDags:
         mock_get_dag.assert_has_calls(
             [
                 mock.call(subdir=cli_args.subdir, 
dag_id="example_bash_operator"),
-                mock.call().test(execution_date=mock.ANY, run_conf=None, 
session=mock.ANY),
+                mock.call().test(
+                    execution_date=mock.ANY, run_conf=None, 
use_executor=False, session=mock.ANY
+                ),
             ]
         )
 
@@ -927,6 +932,7 @@ class TestCliDags:
                 mock.call().test(
                     execution_date=timezone.parse(DEFAULT_DATE.isoformat()),
                     run_conf={"dag_run_conf_param": "param_value"},
+                    use_executor=False,
                     session=mock.ANY,
                 ),
             ]
@@ -947,7 +953,10 @@ class TestCliDags:
             [
                 mock.call(subdir=cli_args.subdir, 
dag_id="example_bash_operator"),
                 mock.call().test(
-                    execution_date=timezone.parse(DEFAULT_DATE.isoformat()), 
run_conf=None, session=mock.ANY
+                    execution_date=timezone.parse(DEFAULT_DATE.isoformat()),
+                    run_conf=None,
+                    use_executor=False,
+                    session=mock.ANY,
                 ),
             ]
         )
diff --git a/tests/conftest.py b/tests/conftest.py
index 912ebfbe23..9027391575 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -39,34 +39,37 @@ if TYPE_CHECKING:
 # unit test mode config is set as early as possible.
 assert "airflow" not in sys.modules, "No airflow module can be imported before 
these lines"
 
-# Clear all Environment Variables that might have side effect,
-# For example, defined in /files/airflow-breeze-config/variables.env
-_AIRFLOW_CONFIG_PATTERN = re.compile(r"^AIRFLOW__(.+)__(.+)$")
-_KEEP_CONFIGS_SETTINGS: dict[str, dict[str, set[str]]] = {
-    # Keep always these configurations
-    "always": {
-        "database": {"sql_alchemy_conn"},
-        "core": {"sql_alchemy_conn"},
-        "celery": {"result_backend", "broker_url"},
-    },
-    # Keep per enabled integrations
-    "celery": {"celery": {"*"}, "celery_broker_transport_options": {"*"}},
-    "kerberos": {"kerberos": {"*"}},
-}
-_ENABLED_INTEGRATIONS = {e.split("_", 1)[-1].lower() for e in os.environ if 
e.startswith("INTEGRATION_")}
-_KEEP_CONFIGS: dict[str, set[str]] = {}
-for keep_settings_key in ("always", *_ENABLED_INTEGRATIONS):
-    if keep_settings := _KEEP_CONFIGS_SETTINGS.get(keep_settings_key):
-        for section, options in keep_settings.items():
-            if section not in _KEEP_CONFIGS:
-                _KEEP_CONFIGS[section] = options
-            else:
-                _KEEP_CONFIGS[section].update(options)
-for env_key in os.environ.copy():
-    if m := _AIRFLOW_CONFIG_PATTERN.match(env_key):
-        section, option = m.group(1).lower(), m.group(2).lower()
-        if not (ko := _KEEP_CONFIGS.get(section)) or not ("*" in ko or option 
in ko):
-            del os.environ[env_key]
+keep_env_variables = "--keep-env-variables" in sys.argv
+
+if not keep_env_variables:
+    # Clear all Environment Variables that might have side effect,
+    # For example, defined in /files/airflow-breeze-config/variables.env
+    _AIRFLOW_CONFIG_PATTERN = re.compile(r"^AIRFLOW__(.+)__(.+)$")
+    _KEEP_CONFIGS_SETTINGS: dict[str, dict[str, set[str]]] = {
+        # Keep always these configurations
+        "always": {
+            "database": {"sql_alchemy_conn"},
+            "core": {"sql_alchemy_conn"},
+            "celery": {"result_backend", "broker_url"},
+        },
+        # Keep per enabled integrations
+        "celery": {"celery": {"*"}, "celery_broker_transport_options": {"*"}},
+        "kerberos": {"kerberos": {"*"}},
+    }
+    _ENABLED_INTEGRATIONS = {e.split("_", 1)[-1].lower() for e in os.environ 
if e.startswith("INTEGRATION_")}
+    _KEEP_CONFIGS: dict[str, set[str]] = {}
+    for keep_settings_key in ("always", *_ENABLED_INTEGRATIONS):
+        if keep_settings := _KEEP_CONFIGS_SETTINGS.get(keep_settings_key):
+            for section, options in keep_settings.items():
+                if section not in _KEEP_CONFIGS:
+                    _KEEP_CONFIGS[section] = options
+                else:
+                    _KEEP_CONFIGS[section].update(options)
+    for env_key in os.environ.copy():
+        if m := _AIRFLOW_CONFIG_PATTERN.match(env_key):
+            section, option = m.group(1).lower(), m.group(2).lower()
+            if not (ko := _KEEP_CONFIGS.get(section)) or not ("*" in ko or 
option in ko):
+                del os.environ[env_key]
 
 SUPPORTED_DB_BACKENDS = ("sqlite", "postgres", "mysql")
 
@@ -230,6 +233,12 @@ def pytest_addoption(parser: pytest.Parser):
         help="only run tests matching integration specified: "
         "[cassandra,kerberos,mongo,celery,statsd,trino]. ",
     )
+    group.addoption(
+        "--keep-env-variables",
+        action="store_true",
+        dest="keep_env_variables",
+        help="do not clear environment variables that might have side effect 
while running tests",
+    )
     group.addoption(
         "--skip-db-tests",
         action="store_true",
diff --git a/tests/system/utils/__init__.py b/tests/system/utils/__init__.py
index b73a03b5c0..578ee6cc04 100644
--- a/tests/system/utils/__init__.py
+++ b/tests/system/utils/__init__.py
@@ -58,7 +58,9 @@ def get_test_run(dag):
     def test_run():
         dag.on_failure_callback = add_callback(dag.on_failure_callback, 
callback)
         dag.on_success_callback = add_callback(dag.on_success_callback, 
callback)
-        dag_run = dag.test()
+        # If the env variable ``_AIRFLOW__SYSTEM_TEST_USE_EXECUTOR`` is set, 
then use an executor to run the
+        # DAG
+        dag_run = 
dag.test(use_executor=os.environ.get("_AIRFLOW__SYSTEM_TEST_USE_EXECUTOR") == 
"1")
         assert (
             dag_run.state == DagRunState.SUCCESS
         ), "The system test failed, please look at the logs to find out the 
underlying failed task(s)"

Reply via email to