Skip to content

Commit 9aa4dfb

Browse files
authored
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
1 parent e80e894 commit 9aa4dfb

2 files changed

Lines changed: 67 additions & 11 deletions

File tree

dev/breeze/src/airflow_breeze/utils/path_utils.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -131,17 +131,19 @@ def reinstall_if_setup_changed() -> bool:
131131
Prints warning if detected airflow sources are not the ones that Breeze was installed with.
132132
:return: True if warning was printed.
133133
"""
134-
135-
res = subprocess.run(
136-
["uv", "tool", "upgrade", "apache-airflow-breeze"],
137-
cwd=MY_BREEZE_ROOT_PATH,
138-
check=True,
139-
text=True,
140-
capture_output=True,
141-
)
142-
if "Modified" in res.stderr:
143-
inform_about_self_upgrade()
144-
return True
134+
try:
135+
res = subprocess.run(
136+
["uv", "tool", "upgrade", "apache-airflow-breeze"],
137+
cwd=MY_BREEZE_ROOT_PATH,
138+
check=False,
139+
text=True,
140+
capture_output=True,
141+
)
142+
if res.returncode == 0 and "Modified" in res.stderr:
143+
inform_about_self_upgrade()
144+
return True
145+
except FileNotFoundError:
146+
pass
145147
return False
146148

147149

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
from __future__ import annotations
18+
19+
from unittest.mock import MagicMock, patch
20+
21+
from airflow_breeze.utils.path_utils import reinstall_if_setup_changed
22+
23+
24+
def test_reinstall_if_setup_changed_when_uv_not_installed():
25+
"""Test that it returns False without error when the uv command is not found (FileNotFoundError)."""
26+
with patch("subprocess.run", side_effect=FileNotFoundError):
27+
# Should return False without any exception occurring during execution.
28+
result = reinstall_if_setup_changed()
29+
assert result is False
30+
31+
32+
def test_reinstall_if_setup_changed_when_not_a_uv_tool():
33+
"""Test when uv is present but 'apache-airflow-breeze' is not installed as a tool (exit 1)."""
34+
mock_res = MagicMock()
35+
mock_res.returncode = 1
36+
mock_res.stderr = "error: apache-airflow-breeze is not installed"
37+
38+
with patch("subprocess.run", return_value=mock_res):
39+
# Should return False and not crash even if the subprocess fails (returncode 1).
40+
result = reinstall_if_setup_changed()
41+
assert result is False
42+
43+
44+
def test_reinstall_if_setup_changed_success_and_modified():
45+
"""Test that it returns True when successfully upgraded and content is modified."""
46+
mock_res = MagicMock()
47+
mock_res.returncode = 0
48+
mock_res.stderr = "Modified /Users/path/to/breeze"
49+
50+
with patch("subprocess.run", return_value=mock_res):
51+
with patch("airflow_breeze.utils.path_utils.inform_about_self_upgrade") as mock_inform:
52+
result = reinstall_if_setup_changed()
53+
assert result is True
54+
mock_inform.assert_called_once()

0 commit comments

Comments
 (0)