Eason09053360 opened a new pull request, #72656:
URL: https://github.com/apache/airflow/pull/72656

   Airflow 3 allows Dag runs to have no logical date — runs triggered manually
   from the UI and asset-triggered runs both store `NULL`. The helper behind
   `airflow tasks test` and `DAG.test()` was written when a logical date was
   always present, and treats an absent one as "match anything" in two places.
   
   **1. The collision lookup deletes an unrelated run.**
   
   `get_or_create_dagrun` replaces any run occupying the logical date it is 
about
   to use, because `(dag_id, logical_date)` is unique. The lookup compares with
   `==`, which SQLAlchemy renders as `IS NULL` for a missing date, so a dateless
   test picks an arbitrary dateless run and deletes it. `DagRun.task_instances`
   cascades, so the run's task instances go with it.
   
   Testing one task can therefore destroy a run a user triggered from the UI.
   NULL dates never collide under a unique constraint, so there is nothing to
   replace in that case and the lookup is now skipped.
   
   **2. The pre-test clear resets every run's task instances.**
   
   `DAG.test()` clears existing task instances before running by passing the
   logical date as both bounds to `clear_dags`. Those bounds are applied under
   `if start_date:` / `if end_date:`, so a `None` drops both and the query
   reduces to `TaskInstance.dag_id == <dag_id>` — every run of the Dag.
   
   Verified against an unrelated finished run: its task instance went from
   `success` to `None` while the run itself still read `success`. Fixing only
   the first issue would have left the runs alive with their history destroyed,
   so the clear is guarded the same way.
   
   Both fixes are the same one-line shape, and each has a regression test that
   fails without it.
   
   ##### Notes for reviewers
   
   - `session.commit()` in the helper became `session.flush()`. The line moves 
in
     this diff and `airflow-core` forbids a callee committing a session it was
     handed. It is also safer: the delete now rolls back with the caller if the
     subsequent create fails. It cannot affect visibility of the new run, since
     it ran *before* the run was created.
   - Repeated dateless `dag.test()` calls now accumulate runs instead of each 
one
     deleting the last. That is the intended cost — the old sweep was just as
     likely to delete the user's own dateless run, which is the bug being fixed.
   - `airflow dags test --logical-date <D>` still replaces a real run sitting at
     `D`. That is a genuine collision under the unique constraint and the
     documented behaviour of the helper, so it is deliberately left alone.
   - For a non-`None` date the `clear_dags` call is arguably redundant, since 
the
     run it clears is deleted (and cascaded) on the next statement. It is 
guarded
     rather than removed, to keep this PR to one story; removing it is a 
separate
     cleanup worth discussing on its own.
   
   ---
   
   ##### Was generative AI tooling used to co-author this PR?
   
   - [X] Yes — Claude Code (Opus 5)
   
   Generated-by: Claude Code (Opus 5) following [the 
guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to