Skip to content

Commit 1dfe755

Browse files
committed
Add teet for api-server with daemon option
1 parent 4ec2ab4 commit 1dfe755

File tree

1 file changed

+88
-2
lines changed

1 file changed

+88
-2
lines changed

airflow-core/tests/unit/cli/commands/test_api_server_command.py

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@
2424
from airflow.cli.commands import api_server_command
2525
from airflow.exceptions import AirflowConfigException
2626

27-
from unit.cli.commands._common_cli_classes import _CommonCLIGunicornTestClass
27+
from unit.cli.commands._common_cli_classes import _CommonCLIUvicornTestClass
2828

2929
console = Console(width=400, color_system="standard")
3030

3131

3232
@pytest.mark.db_test
33-
class TestCliApiServer(_CommonCLIGunicornTestClass):
33+
class TestCliApiServer(_CommonCLIUvicornTestClass):
3434
main_process_regexp = r"airflow api-server"
3535

3636
@pytest.mark.parametrize(
@@ -153,6 +153,92 @@ def test_args_to_uvicorn(self, ssl_cert_and_key):
153153
proxy_headers=False,
154154
)
155155

156+
@pytest.mark.parametrize(
157+
"demonize",
158+
[True, False],
159+
)
160+
@mock.patch("airflow.cli.commands.daemon_utils.TimeoutPIDLockFile")
161+
@mock.patch("airflow.cli.commands.daemon_utils.setup_locations")
162+
@mock.patch("airflow.cli.commands.daemon_utils.daemon")
163+
@mock.patch("airflow.cli.commands.api_server_command.uvicorn")
164+
def test_run_command_daemon(
165+
self, mock_uvicorn, mock_daemon, mock_setup_locations, mock_pid_file, demonize
166+
):
167+
mock_setup_locations.return_value = (
168+
mock.MagicMock(name="pidfile"),
169+
mock.MagicMock(name="stdout"),
170+
mock.MagicMock(name="stderr"),
171+
mock.MagicMock(name="INVALID"),
172+
)
173+
args = self.parser.parse_args(
174+
[
175+
"api-server",
176+
"--host",
177+
"my-hostname",
178+
"--port",
179+
"9090",
180+
"--workers",
181+
"2",
182+
"--worker-timeout",
183+
"60",
184+
]
185+
+ (["--daemon"] if demonize else [])
186+
)
187+
mock_open = mock.mock_open()
188+
with mock.patch("airflow.cli.commands.daemon_utils.open", mock_open):
189+
api_server_command.api_server(args)
190+
191+
mock_uvicorn.run.assert_called_once_with(
192+
"airflow.api_fastapi.main:app",
193+
host="my-hostname",
194+
port=9090,
195+
workers=2,
196+
timeout_keep_alive=60,
197+
timeout_graceful_shutdown=60,
198+
ssl_keyfile=None,
199+
ssl_certfile=None,
200+
access_log="-",
201+
proxy_headers=False,
202+
)
203+
204+
if demonize:
205+
assert mock_daemon.mock_calls[:3] == [
206+
mock.call.DaemonContext(
207+
pidfile=mock_pid_file.return_value,
208+
files_preserve=None,
209+
stdout=mock_open.return_value,
210+
stderr=mock_open.return_value,
211+
umask=0o077,
212+
),
213+
mock.call.DaemonContext().__enter__(),
214+
mock.call.DaemonContext().__exit__(None, None, None),
215+
]
216+
assert mock_setup_locations.mock_calls == [
217+
mock.call(
218+
process="api_server",
219+
pid=None,
220+
stdout=None,
221+
stderr=None,
222+
log=None,
223+
)
224+
]
225+
mock_pid_file.assert_has_calls([mock.call(mock_setup_locations.return_value[0], -1)])
226+
assert mock_open.mock_calls == [
227+
mock.call(mock_setup_locations.return_value[1], "a"),
228+
mock.call().__enter__(),
229+
mock.call(mock_setup_locations.return_value[2], "a"),
230+
mock.call().__enter__(),
231+
mock.call().truncate(0),
232+
mock.call().truncate(0),
233+
mock.call().__exit__(None, None, None),
234+
mock.call().__exit__(None, None, None),
235+
]
236+
else:
237+
assert mock_daemon.mock_calls == []
238+
mock_setup_locations.mock_calls == []
239+
mock_pid_file.assert_not_called()
240+
mock_open.assert_not_called()
241+
156242
@pytest.mark.parametrize(
157243
"ssl_arguments, error_pattern",
158244
[

0 commit comments

Comments
 (0)