|
17 | 17 | # under the License.
|
18 | 18 | from __future__ import annotations
|
19 | 19 |
|
| 20 | +import itertools |
20 | 21 | import re
|
21 | 22 | from datetime import datetime
|
22 | 23 | from unittest.mock import Mock
|
23 | 24 | from urllib.parse import parse_qs
|
24 | 25 |
|
| 26 | +import pendulum |
25 | 27 | from bs4 import BeautifulSoup
|
26 | 28 | from markupsafe import Markup
|
27 | 29 |
|
| 30 | +from airflow.models import DagRun |
28 | 31 | from airflow.utils import json as utils_json
|
29 | 32 | from airflow.www import utils
|
30 |
| -from airflow.www.utils import json_f, wrapped_markdown |
| 33 | +from airflow.www.utils import DagRunCustomSQLAInterface, json_f, wrapped_markdown |
31 | 34 |
|
32 | 35 |
|
33 | 36 | class TestUtils:
|
@@ -156,7 +159,6 @@ def test_state_token(self):
|
156 | 159 | assert "<script>alert(1)</script>" not in html
|
157 | 160 |
|
158 | 161 | def test_task_instance_link(self):
|
159 |
| - |
160 | 162 | from airflow.www.app import cached_app
|
161 | 163 |
|
162 | 164 | with cached_app(testing=True).test_request_context():
|
@@ -413,3 +415,44 @@ def test_wrapped_markdown_with_collapsible_section(self):
|
413 | 415 | </div>"""
|
414 | 416 | == rendered
|
415 | 417 | )
|
| 418 | + |
| 419 | + |
| 420 | +def test_dag_run_custom_sqla_interface_delete_no_collateral_damage(dag_maker, session): |
| 421 | + interface = DagRunCustomSQLAInterface(obj=DagRun, session=session) |
| 422 | + dag_ids = (f"test_dag_{x}" for x in range(1, 4)) |
| 423 | + dates = (pendulum.datetime(2023, 1, x) for x in range(1, 4)) |
| 424 | + for dag_id, date in itertools.product(dag_ids, dates): |
| 425 | + with dag_maker(dag_id=dag_id) as dag: |
| 426 | + dag.create_dagrun(execution_date=date, state="running", run_type="scheduled") |
| 427 | + dag_runs = session.query(DagRun).all() |
| 428 | + assert len(dag_runs) == 9 |
| 429 | + assert len(set(x.run_id for x in dag_runs)) == 3 |
| 430 | + run_id_for_single_delete = "scheduled__2023-01-01T00:00:00+00:00" |
| 431 | + # we have 3 runs with this same run_id |
| 432 | + assert len(list(x for x in dag_runs if x.run_id == run_id_for_single_delete)) == 3 |
| 433 | + # each is a different dag |
| 434 | + |
| 435 | + # if we delete one, it shouldn't delete the others |
| 436 | + one_run = [x for x in dag_runs if x.run_id == run_id_for_single_delete][0] |
| 437 | + assert interface.delete(item=one_run) is True |
| 438 | + session.commit() |
| 439 | + dag_runs = session.query(DagRun).all() |
| 440 | + # we should have one fewer dag run now |
| 441 | + assert len(dag_runs) == 8 |
| 442 | + |
| 443 | + # now let's try multi delete |
| 444 | + run_id_for_multi_delete = "scheduled__2023-01-02T00:00:00+00:00" |
| 445 | + # verify we have 3 |
| 446 | + runs_of_interest = [x for x in dag_runs if x.run_id == run_id_for_multi_delete] |
| 447 | + assert len(runs_of_interest) == 3 |
| 448 | + # and that each is different dag |
| 449 | + assert len(set(x.dag_id for x in dag_runs)) == 3 |
| 450 | + |
| 451 | + to_delete = runs_of_interest[:2] |
| 452 | + # now try multi delete |
| 453 | + assert interface.delete_all(items=to_delete) is True |
| 454 | + session.commit() |
| 455 | + dag_runs = session.query(DagRun).all() |
| 456 | + assert len(dag_runs) == 6 |
| 457 | + assert len(set(x.dag_id for x in dag_runs)) == 3 |
| 458 | + assert len(set(x.run_id for x in dag_runs)) == 3 |
0 commit comments