blob: 37ecf0ee6f7de982d052b63d75a193840e367f9b [file] [log] [blame]
# 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
import json
from unittest import mock
from unittest.mock import call
import pytest
from airflow_breeze.utils.docker_command_utils import (
autodetect_docker_context,
check_docker_compose_version,
check_docker_version,
)
@mock.patch("airflow_breeze.utils.docker_command_utils.check_docker_permission_denied")
@mock.patch("airflow_breeze.utils.docker_command_utils.run_command")
@mock.patch("airflow_breeze.utils.docker_command_utils.get_console")
def test_check_docker_version_unknown(
mock_get_console, mock_run_command, mock_check_docker_permission_denied
):
mock_check_docker_permission_denied.return_value = False
with pytest.raises(SystemExit) as e:
check_docker_version()
assert e.value.code == 1
expected_run_command_calls = [
call(
["docker", "version", "--format", "{{.Client.Version}}"],
no_output_dump_on_exception=True,
capture_output=True,
text=True,
check=False,
dry_run_override=False,
),
]
mock_run_command.assert_has_calls(expected_run_command_calls)
mock_get_console.return_value.print.assert_called_with(
"""
[warning]Your version of docker is unknown. If the scripts fail, please make sure to[/]
[warning]install docker at least: 25.0.0 version.[/]
"""
)
@mock.patch("airflow_breeze.utils.docker_command_utils.check_docker_permission_denied")
@mock.patch("airflow_breeze.utils.docker_command_utils.run_command")
@mock.patch("airflow_breeze.utils.docker_command_utils.get_console")
def test_check_docker_version_too_low(
mock_get_console, mock_run_command, mock_check_docker_permission_denied
):
mock_check_docker_permission_denied.return_value = False
mock_run_command.return_value.returncode = 0
mock_run_command.return_value.stdout = "0.9"
with pytest.raises(SystemExit) as e:
check_docker_version()
assert e.value.code == 1
mock_check_docker_permission_denied.assert_called()
mock_run_command.assert_called_with(
["docker", "version", "--format", "{{.Client.Version}}"],
no_output_dump_on_exception=True,
capture_output=True,
text=True,
check=False,
dry_run_override=False,
)
mock_get_console.return_value.print.assert_called_with(
"""
[error]Your version of docker is too old: 0.9.\n[/]\n[warning]Please upgrade to at least 25.0.0.\n[/]\n\
You can find installation instructions here: https://docs.docker.com/engine/install/
"""
)
@mock.patch("airflow_breeze.utils.docker_command_utils.check_docker_permission_denied")
@mock.patch("airflow_breeze.utils.docker_command_utils.run_command")
@mock.patch("airflow_breeze.utils.docker_command_utils.get_console")
def test_check_docker_version_ok(mock_get_console, mock_run_command, mock_check_docker_permission_denied):
mock_check_docker_permission_denied.return_value = False
mock_run_command.return_value.returncode = 0
mock_run_command.return_value.stdout = "25.0.0"
check_docker_version()
mock_check_docker_permission_denied.assert_called()
mock_run_command.assert_called_with(
["docker", "version", "--format", "{{.Client.Version}}"],
no_output_dump_on_exception=True,
capture_output=True,
text=True,
check=False,
dry_run_override=False,
)
mock_get_console.return_value.print.assert_called_with("[success]Good version of Docker: 25.0.0.[/]")
@mock.patch("airflow_breeze.utils.docker_command_utils.check_docker_permission_denied")
@mock.patch("airflow_breeze.utils.docker_command_utils.run_command")
@mock.patch("airflow_breeze.utils.docker_command_utils.get_console")
def test_check_docker_version_higher(mock_get_console, mock_run_command, mock_check_docker_permission_denied):
mock_check_docker_permission_denied.return_value = False
mock_run_command.return_value.returncode = 0
mock_run_command.return_value.stdout = "25.0.0"
check_docker_version()
mock_check_docker_permission_denied.assert_called()
mock_run_command.assert_called_with(
["docker", "version", "--format", "{{.Client.Version}}"],
no_output_dump_on_exception=True,
capture_output=True,
text=True,
check=False,
dry_run_override=False,
)
mock_get_console.return_value.print.assert_called_with("[success]Good version of Docker: 25.0.0.[/]")
@mock.patch("airflow_breeze.utils.docker_command_utils.check_docker_permission_denied")
@mock.patch("airflow_breeze.utils.docker_command_utils.run_command")
@mock.patch("airflow_breeze.utils.docker_command_utils.get_console")
def test_check_docker_version_higher_rancher_desktop(
mock_get_console, mock_run_command, mock_check_docker_permission_denied
):
mock_check_docker_permission_denied.return_value = False
mock_run_command.return_value.returncode = 0
mock_run_command.return_value.stdout = "25.0.0-rd"
check_docker_version()
mock_check_docker_permission_denied.assert_called()
mock_run_command.assert_called_with(
["docker", "version", "--format", "{{.Client.Version}}"],
no_output_dump_on_exception=True,
capture_output=True,
text=True,
check=False,
dry_run_override=False,
)
mock_get_console.return_value.print.assert_called_with("[success]Good version of Docker: 25.0.0-r.[/]")
@mock.patch("airflow_breeze.utils.docker_command_utils.run_command")
@mock.patch("airflow_breeze.utils.docker_command_utils.get_console")
def test_check_docker_compose_version_unknown(mock_get_console, mock_run_command):
with pytest.raises(SystemExit) as e:
check_docker_compose_version()
assert e.value.code == 1
expected_run_command_calls = [
call(
["docker", "compose", "version"],
no_output_dump_on_exception=True,
capture_output=True,
text=True,
dry_run_override=False,
),
]
mock_run_command.assert_has_calls(expected_run_command_calls)
mock_get_console.return_value.print.assert_called_with(
"""
[error]Unknown docker-compose version.[/]\n[warning]At least 2.20.2 needed! Please upgrade!\n[/]
See https://docs.docker.com/compose/install/ for installation instructions.\n
Make sure docker-compose you install is first on the PATH variable of yours.\n
"""
)
@mock.patch("airflow_breeze.utils.docker_command_utils.run_command")
@mock.patch("airflow_breeze.utils.docker_command_utils.get_console")
def test_check_docker_compose_version_low(mock_get_console, mock_run_command):
mock_run_command.return_value.returncode = 0
mock_run_command.return_value.stdout = "1.28.5"
with pytest.raises(SystemExit) as e:
check_docker_compose_version()
assert e.value.code == 1
mock_run_command.assert_called_with(
["docker", "compose", "version"],
no_output_dump_on_exception=True,
capture_output=True,
text=True,
dry_run_override=False,
)
mock_get_console.return_value.print.assert_called_with(
"""
[error]You have too old version of docker-compose: 1.28.5!\n[/]
[warning]At least 2.20.2 needed! Please upgrade!\n[/]
See https://docs.docker.com/compose/install/ for installation instructions.\n
Make sure docker-compose you install is first on the PATH variable of yours.\n
"""
)
@mock.patch("airflow_breeze.utils.docker_command_utils.run_command")
@mock.patch("airflow_breeze.utils.docker_command_utils.get_console")
def test_check_docker_compose_version_ok(mock_get_console, mock_run_command):
mock_run_command.return_value.returncode = 0
mock_run_command.return_value.stdout = "2.20.2"
check_docker_compose_version()
mock_run_command.assert_called_with(
["docker", "compose", "version"],
no_output_dump_on_exception=True,
capture_output=True,
text=True,
dry_run_override=False,
)
mock_get_console.return_value.print.assert_called_with(
"[success]Good version of docker-compose: 2.20.2[/]"
)
def _fake_ctx_output(*names: str) -> str:
return "\n".join(json.dumps({"Name": name, "DockerEndpoint": f"unix://{name}"}) for name in names)
@pytest.mark.parametrize(
"context_output, selected_context, console_output",
[
(
_fake_ctx_output("default"),
"default",
"[info]Using 'default' as context",
),
("\n", "default", "[warning]Could not detect docker builder"),
(
_fake_ctx_output("a", "b"),
"a",
"[warning]Could not use any of the preferred docker contexts",
),
(
_fake_ctx_output("a", "desktop-linux"),
"desktop-linux",
"[info]Using 'desktop-linux' as context",
),
(
_fake_ctx_output("a", "default"),
"default",
"[info]Using 'default' as context",
),
(
_fake_ctx_output("a", "default", "desktop-linux"),
"desktop-linux",
"[info]Using 'desktop-linux' as context",
),
(
'[{"Name": "desktop-linux", "DockerEndpoint": "unix://desktop-linux"}]',
"desktop-linux",
"[info]Using 'desktop-linux' as context",
),
],
)
def test_autodetect_docker_context(context_output: str, selected_context: str, console_output: str):
with mock.patch("airflow_breeze.utils.docker_command_utils.run_command") as mock_run_command:
mock_run_command.return_value.returncode = 0
mock_run_command.return_value.stdout = context_output
with mock.patch("airflow_breeze.utils.docker_command_utils.get_console") as mock_get_console:
mock_get_console.return_value.input.return_value = selected_context
assert autodetect_docker_context() == selected_context
mock_get_console.return_value.print.assert_called_once()
assert console_output in mock_get_console.return_value.print.call_args[0][0]
SOCKET_INFO = json.dumps(
[
{
"Name": "default",
"Metadata": {},
"Endpoints": {"docker": {"Host": "unix:///not-standard/docker.sock", "SkipTLSVerify": False}},
"TLSMaterial": {},
"Storage": {"MetadataPath": "\u003cIN MEMORY\u003e", "TLSPath": "\u003cIN MEMORY\u003e"},
}
]
)
SOCKET_INFO_DESKTOP_LINUX = json.dumps(
[
{
"Name": "desktop-linux",
"Metadata": {},
"Endpoints": {
"docker": {"Host": "unix:///VERY_NON_STANDARD/docker.sock", "SkipTLSVerify": False}
},
"TLSMaterial": {},
"Storage": {"MetadataPath": "\u003cIN MEMORY\u003e", "TLSPath": "\u003cIN MEMORY\u003e"},
}
]
)