"""Unit tests for devx.tools.docker_login.""" from unittest.mock import MagicMock, patch import pytest from click.testing import CliRunner from devx.tools.docker_login import ( _resolve_credentials, cli, docker_login, ) class TestDockerLogin: @patch("devx.tools.docker_login.subprocess.run") def test_success(self, mock_run: MagicMock) -> None: mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="") assert docker_login("registry.io", "user", "tok") is True @patch("devx.tools.docker_login.subprocess.run") def test_failure_raises(self, mock_run: MagicMock) -> None: mock_run.return_value = MagicMock(returncode=1, stdout="", stderr="auth failed") with pytest.raises(Exception, match="auth failed"): docker_login("registry.io", "user", "tok") @patch("devx.tools.docker_login.subprocess.run") def test_failure_suppressed(self, mock_run: MagicMock) -> None: mock_run.return_value = MagicMock(returncode=1, stdout="", stderr="auth failed") assert docker_login("registry.io", "user", "tok", suppress_failure=True) is False class TestResolveCredentials: @patch.dict("os.environ", {"CI_GITEA_TOKEN": "tok", "CI_GITEA_USERNAME": "emil"}, clear=True) def test_both_set(self) -> None: user, token = _resolve_credentials("CI_GITEA_TOKEN", "CI_GITEA_USERNAME", None) assert user == "emil" assert token == "tok" @patch.dict("os.environ", {"CI_GITEA_TOKEN": "tok"}, clear=True) def test_token_only_with_default(self) -> None: user, token = _resolve_credentials("CI_GITEA_TOKEN", "CI_GITEA_USERNAME", "emil") assert user == "emil" assert token == "tok" @patch.dict("os.environ", {}, clear=True) def test_no_token(self) -> None: user, token = _resolve_credentials("CI_GITEA_TOKEN", "CI_GITEA_USERNAME", "emil") assert user is None assert token is None @patch.dict("os.environ", {"CI_GITEA_TOKEN": "tok"}, clear=True) def test_no_username_no_default(self) -> None: user, token = _resolve_credentials("CI_GITEA_TOKEN", "CI_GITEA_USERNAME", None) assert user == "" assert token == "tok" class TestCli: @patch("devx.tools.docker_login.docker_login") @patch.dict("os.environ", {"CI_GITEA_TOKEN": "tok", "CI_GITEA_USERNAME": "emil"}, clear=True) def test_required_login(self, mock_login: MagicMock) -> None: mock_login.return_value = True runner = CliRunner() result = runner.invoke( cli, ["--registry", "reg.io", "--token-env", "CI_GITEA_TOKEN", "--username-env", "CI_GITEA_USERNAME"], ) assert result.exit_code == 0 mock_login.assert_called_once() @patch("devx.tools.docker_login.docker_login") @patch.dict("os.environ", {"CI_GITEA_TOKEN": "tok"}, clear=True) def test_default_username(self, mock_login: MagicMock) -> None: mock_login.return_value = True runner = CliRunner() result = runner.invoke( cli, [ "--registry", "reg.io", "--token-env", "CI_GITEA_TOKEN", "--username-env", "CI_GITEA_USERNAME", "--default-username", "emil", ], ) assert result.exit_code == 0 mock_login.assert_called_once_with("reg.io", "emil", "tok", suppress_failure=False) @patch.dict("os.environ", {}, clear=True) def test_required_no_token_raises(self) -> None: runner = CliRunner() result = runner.invoke( cli, ["--registry", "reg.io", "--token-env", "CI_GITEA_TOKEN", "--username-env", "CI_GITEA_USERNAME"], ) assert result.exit_code != 0 @patch.dict("os.environ", {}, clear=True) def test_optional_no_token_skips(self) -> None: runner = CliRunner() result = runner.invoke( cli, [ "--registry", "reg.io", "--token-env", "CI_GITEA_TOKEN", "--username-env", "CI_GITEA_USERNAME", "--optional", ], ) assert result.exit_code == 0 assert "Skipping" in result.output @patch("devx.tools.docker_login.docker_login") @patch.dict("os.environ", {"CI_GITEA_TOKEN": "tok"}, clear=True) def test_no_username_raises(self, mock_login: MagicMock) -> None: runner = CliRunner() result = runner.invoke( cli, ["--registry", "reg.io", "--token-env", "CI_GITEA_TOKEN", "--username-env", "CI_GITEA_USERNAME"], ) assert result.exit_code != 0 mock_login.assert_not_called() @patch("devx.tools.docker_login.docker_login") @patch.dict("os.environ", {"CI_GITEA_TOKEN": "tok", "CI_GITEA_USERNAME": "emil"}, clear=True) def test_suppress_failure(self, mock_login: MagicMock) -> None: mock_login.return_value = False runner = CliRunner() result = runner.invoke( cli, [ "--registry", "reg.io", "--token-env", "CI_GITEA_TOKEN", "--username-env", "CI_GITEA_USERNAME", "--suppress-failure", ], ) assert result.exit_code == 0 mock_login.assert_called_once_with("reg.io", "emil", "tok", suppress_failure=True)