moomindani commented on PR #66613:
URL: https://github.com/apache/airflow/pull/66613#issuecomment-4410735105

   ## Real-environment validation
   
   Ran the operators end-to-end through `airflow dags test` against a real 
Databricks workspace, with verification tasks in the same DAG that read the 
workspace state back via the REST API. All seven tasks succeeded.
   
   ### Tasks (DAG `pr66613_realenv`, with DAG-level `params={"env": "prod", 
"batch_size": "100"}`)
   
   | Task | Status |
   |---|---|
   | `create_job` (`DatabricksCreateJobsOperator`) | success |
   | `verify_create_job` — assert workspace `settings.parameters` contains 
`env=prod`, `batch_size=100` | success |
   | `run_now` (`DatabricksRunNowOperator`, `params={"env": "staging", 
"batch_size": "42"}`) | success |
   | `verify_run_now` — assert run's `job_parameters` is `{"env": "staging", 
"batch_size": "42"}` (operator overrides DAG) | success |
   | `submit_run` (`DatabricksSubmitRunOperator`, `params={"env": "dev", 
"shard": "1"}`) | success |
   | `verify_submit_run` — assert task's `notebook_task.base_parameters` is 
`{"env": "dev", "batch_size": "100", "shard": "1"}` (DAG-level `batch_size` is 
inherited where the operator does not override) | success |
   | `cleanup_job` | success |
   
   The verification tasks confirm the params actually arrive at Databricks (not 
just that the request body is constructed locally), and that DAG-level params 
and operator-level params merge correctly.
   
   ### DAG
   
   <details>
   <summary>dev/dag_pr66613_realenv.py</summary>
   
   ```python
   """Real-environment validation DAG for PR #66613 (GH-39002)."""
   from __future__ import annotations
   
   import os
   from datetime import datetime
   
   from airflow.providers.databricks.hooks.databricks import DatabricksHook
   from airflow.providers.databricks.operators.databricks import (
       DatabricksCreateJobsOperator,
       DatabricksRunNowOperator,
       DatabricksSubmitRunOperator,
   )
   from airflow.sdk import DAG, task
   
   NOTEBOOK_PATH = os.environ.get(
       "PR66613_NOTEBOOK_PATH", 
"/Users/<your-user>@example.com/airflow-pr66613-noop"
   )
   
   
   def _hook() -> DatabricksHook:
       return DatabricksHook(databricks_conn_id="databricks_default")
   
   
   with DAG(
       dag_id="pr66613_realenv",
       start_date=datetime(2026, 1, 1),
       schedule=None,
       catchup=False,
       params={"env": "prod", "batch_size": "100"},
       tags=["databricks", "pr66613"],
   ) as dag:
       create_job = DatabricksCreateJobsOperator(
           task_id="create_job",
           json={
               "name": "{{ dag.dag_id }}-{{ ts_nodash }}",
               "tasks": [{"task_key": "noop", "notebook_task": 
{"notebook_path": NOTEBOOK_PATH}}],
           },
       )
   
       @task(task_id="verify_create_job")
       def verify_create_job(job_id: int) -> int:
           job = _hook()._do_api_call(("GET", "2.2/jobs/get"), {"job_id": 
job_id})
           params = job["settings"].get("parameters", [])
           assert {"name": "env", "default": "prod"} in params, params
           assert {"name": "batch_size", "default": "100"} in params, params
           return job_id
   
       run_now = DatabricksRunNowOperator(
           task_id="run_now",
           job_id="{{ ti.xcom_pull(task_ids='verify_create_job') }}",
           params={"env": "staging", "batch_size": "42"},
           wait_for_termination=False,
       )
   
       @task(task_id="verify_run_now")
       def verify_run_now(databricks_run_id: int) -> None:
           run = _hook()._do_api_call(("GET", "2.2/jobs/runs/get"), {"run_id": 
databricks_run_id})
           found = {p["name"]: p.get("value", p.get("default")) for p in 
run.get("job_parameters", [])}
           assert found.get("env") == "staging", found
           assert found.get("batch_size") == "42", found
           _hook().cancel_run(databricks_run_id)
   
       submit_run = DatabricksSubmitRunOperator(
           task_id="submit_run",
           notebook_task={"notebook_path": NOTEBOOK_PATH},
           new_cluster={
               "spark_version": "15.4.x-scala2.12",
               "node_type_id": "i3.xlarge",
               "num_workers": 0,
               "spark_conf": {"spark.master": "local[*]"},
               "custom_tags": {"ResourceClass": "SingleNode"},
           },
           params={"env": "dev", "shard": "1"},
           wait_for_termination=False,
       )
   
       @task(task_id="verify_submit_run")
       def verify_submit_run(databricks_run_id: int) -> None:
           run = _hook()._do_api_call(("GET", "2.2/jobs/runs/get"), {"run_id": 
databricks_run_id})
           base_params = run["tasks"][0]["notebook_task"]["base_parameters"]
           # Operator-level params override DAG-level params for shared keys; 
DAG-level
           # keys not overridden are still inherited (here: batch_size from the 
DAG).
           assert base_params == {"env": "dev", "batch_size": "100", "shard": 
"1"}, base_params
           _hook().cancel_run(databricks_run_id)
   
       @task(task_id="cleanup_job", trigger_rule="all_done")
       def cleanup_job(job_id: int) -> None:
           try:
               _hook()._do_api_call(("POST", "2.2/jobs/delete"), {"job_id": 
job_id})
           except Exception:  # noqa: BLE001
               pass
   
       job_id_xcom = verify_create_job(create_job.output)
       run_now_done = verify_run_now(
           databricks_run_id="{{ ti.xcom_pull(task_ids='run_now', key='run_id') 
}}"
       )
       submit_run_done = verify_submit_run(
           databricks_run_id="{{ ti.xcom_pull(task_ids='submit_run', 
key='run_id') }}"
       )
       create_job >> job_id_xcom >> run_now >> run_now_done
       submit_run >> submit_run_done
       [run_now_done, submit_run_done] >> cleanup_job(job_id_xcom)
   ```
   
   </details>
   
   Run with:
   
   ```bash
   export 
AIRFLOW_CONN_DATABRICKS_DEFAULT='{"conn_type":"databricks","host":"https://<workspace>","password":"<token>"}'
   export PR66613_NOTEBOOK_PATH=/Users/<you>/airflow-pr66613-noop  # any 
notebook in the workspace
   airflow dags test pr66613_realenv
   ```
   


-- 
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