From 40c733cc80b529d665300378f364194eb5b9ebec Mon Sep 17 00:00:00 2001 From: Florence <153512255+mscsy0104@users.noreply.github.com> Date: Thu, 23 Apr 2026 02:21:57 +0900 Subject: [PATCH] [chart/v1-2x-test] Fix: Prevent Breeze crash when self-upgrade check fails (#65656) * Fix: Prevent Breeze crash when self-upgrade check fails * test: add unit tests for Breeze self-upgrade check * style: rename test file and update breeze images (cherry picked from commit 9aa4dfb) Co-authored-by: Florence <153512255+mscsy0104@users.noreply.github.com> --- .../src/airflow_breeze/utils/path_utils.py | 24 +++++---- .../tests/test_reinstall_if_setup_changed.py | 54 +++++++++++++++++++ 2 files changed, 67 insertions(+), 11 deletions(-) create mode 100644 dev/breeze/tests/test_reinstall_if_setup_changed.py diff --git a/dev/breeze/src/airflow_breeze/utils/path_utils.py b/dev/breeze/src/airflow_breeze/utils/path_utils.py index 03877d6476163..1fec4d480a3d6 100644 --- a/dev/breeze/src/airflow_breeze/utils/path_utils.py +++ b/dev/breeze/src/airflow_breeze/utils/path_utils.py @@ -131,17 +131,19 @@ def reinstall_if_setup_changed() -> bool: Prints warning if detected airflow sources are not the ones that Breeze was installed with. :return: True if warning was printed. """ - - res = subprocess.run( - ["uv", "tool", "upgrade", "apache-airflow-breeze"], - cwd=MY_BREEZE_ROOT_PATH, - check=True, - text=True, - capture_output=True, - ) - if "Modified" in res.stderr: - inform_about_self_upgrade() - return True + try: + res = subprocess.run( + ["uv", "tool", "upgrade", "apache-airflow-breeze"], + cwd=MY_BREEZE_ROOT_PATH, + check=False, + text=True, + capture_output=True, + ) + if res.returncode == 0 and "Modified" in res.stderr: + inform_about_self_upgrade() + return True + except FileNotFoundError: + pass return False diff --git a/dev/breeze/tests/test_reinstall_if_setup_changed.py b/dev/breeze/tests/test_reinstall_if_setup_changed.py new file mode 100644 index 0000000000000..293fc6b1273e1 --- /dev/null +++ b/dev/breeze/tests/test_reinstall_if_setup_changed.py @@ -0,0 +1,54 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +from unittest.mock import MagicMock, patch + +from airflow_breeze.utils.path_utils import reinstall_if_setup_changed + + +def test_reinstall_if_setup_changed_when_uv_not_installed(): + """Test that it returns False without error when the uv command is not found (FileNotFoundError).""" + with patch("subprocess.run", side_effect=FileNotFoundError): + # Should return False without any exception occurring during execution. + result = reinstall_if_setup_changed() + assert result is False + + +def test_reinstall_if_setup_changed_when_not_a_uv_tool(): + """Test when uv is present but 'apache-airflow-breeze' is not installed as a tool (exit 1).""" + mock_res = MagicMock() + mock_res.returncode = 1 + mock_res.stderr = "error: apache-airflow-breeze is not installed" + + with patch("subprocess.run", return_value=mock_res): + # Should return False and not crash even if the subprocess fails (returncode 1). + result = reinstall_if_setup_changed() + assert result is False + + +def test_reinstall_if_setup_changed_success_and_modified(): + """Test that it returns True when successfully upgraded and content is modified.""" + mock_res = MagicMock() + mock_res.returncode = 0 + mock_res.stderr = "Modified /Users/path/to/breeze" + + with patch("subprocess.run", return_value=mock_res): + with patch("airflow_breeze.utils.path_utils.inform_about_self_upgrade") as mock_inform: + result = reinstall_if_setup_changed() + assert result is True + mock_inform.assert_called_once()