Public Access
DEVX-110: feat: centralize venv management in devx.mak
Post-merge / detect-type (push) Successful in 9s
Build Images / detect-type (push) Failing after 13s
Build Images / build-and-push (push) Has been skipped
Post-merge / validate-commit-msg (push) Successful in 10s
Build Images / cleanup (push) Has been skipped
Post-merge / vikunja (push) Successful in 15s
Post-merge / configure-repo (push) Successful in 18s
Post-merge / sync-wiki (push) Successful in 29s
Post-merge / release (push) Successful in 32s
Post-merge / badges (push) Successful in 39s
Post-merge / publish (push) Successful in 17s
Post-merge / detect-type (push) Successful in 9s
Build Images / detect-type (push) Failing after 13s
Build Images / build-and-push (push) Has been skipped
Post-merge / validate-commit-msg (push) Successful in 10s
Build Images / cleanup (push) Has been skipped
Post-merge / vikunja (push) Successful in 15s
Post-merge / configure-repo (push) Successful in 18s
Post-merge / sync-wiki (push) Successful in 29s
Post-merge / release (push) Successful in 32s
Post-merge / badges (push) Successful in 39s
Post-merge / publish (push) Successful in 17s
This commit was merged in pull request #167.
This commit is contained in:
@@ -0,0 +1,262 @@
|
||||
"""Unit tests for devx.tools.setup_image."""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from click.testing import CliRunner
|
||||
|
||||
from devx.tools.setup_image import (
|
||||
_build_pip_extra_index_url,
|
||||
_fallback_to_setup_ci,
|
||||
_install_in_image,
|
||||
cli,
|
||||
)
|
||||
|
||||
|
||||
class TestBuildPipExtraIndexUrl:
|
||||
def test_basic_url(self) -> None:
|
||||
url = _build_pip_extra_index_url(
|
||||
"git.oblachno.oblachno.fyi",
|
||||
"oblachno-oss",
|
||||
"emil",
|
||||
"tok123",
|
||||
)
|
||||
assert url == "https://emil:tok123@git.oblachno.oblachno.fyi/api/packages/oblachno-oss/pypi/simple/"
|
||||
|
||||
def test_custom_host_org(self) -> None:
|
||||
url = _build_pip_extra_index_url(
|
||||
"gitea.example.com",
|
||||
"my-org",
|
||||
"user",
|
||||
"secret",
|
||||
)
|
||||
assert url == "https://user:secret@gitea.example.com/api/packages/my-org/pypi/simple/"
|
||||
|
||||
|
||||
class TestInstallInImage:
|
||||
@patch("devx.tools.setup_image.subprocess.run")
|
||||
@patch("devx.tools.setup_image.Path")
|
||||
def test_link_and_install_no_token(self, mock_path: MagicMock, mock_run: MagicMock, tmp_path: Path) -> None:
|
||||
venv_link = tmp_path / ".venv"
|
||||
mock_path.return_value.exists.return_value = False
|
||||
mock_path.return_value.is_symlink.return_value = False
|
||||
mock_path.return_value.symlink_to = MagicMock()
|
||||
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
_install_in_image(str(venv_link), "/opt/venv", "", "host", "org")
|
||||
|
||||
mock_path.return_value.symlink_to.assert_called_once_with("/opt/venv")
|
||||
mock_run.assert_called_once()
|
||||
cmd = mock_run.call_args[0][0]
|
||||
assert "--no-cache-dir" in cmd
|
||||
assert "-e" in cmd
|
||||
assert "." in cmd
|
||||
# No extras → spec is "."
|
||||
assert ".[]" not in " ".join(cmd)
|
||||
|
||||
@patch("devx.tools.setup_image.subprocess.run")
|
||||
@patch("devx.tools.setup_image.Path")
|
||||
def test_link_and_install_with_extras(
|
||||
self,
|
||||
mock_path: MagicMock,
|
||||
mock_run: MagicMock,
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
venv_link = tmp_path / ".venv"
|
||||
mock_path.return_value.exists.return_value = False
|
||||
mock_path.return_value.is_symlink.return_value = False
|
||||
mock_path.return_value.symlink_to = MagicMock()
|
||||
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
_install_in_image(str(venv_link), "/opt/venv", "ci,lint", "host", "org")
|
||||
|
||||
cmd = mock_run.call_args[0][0]
|
||||
assert ".[ci,lint]" in cmd
|
||||
|
||||
@patch("devx.tools.setup_image.subprocess.run")
|
||||
@patch("devx.tools.setup_image.Path")
|
||||
def test_install_with_token_sets_pip_extra_index_url(
|
||||
self,
|
||||
mock_path: MagicMock,
|
||||
mock_run: MagicMock,
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
venv_link = tmp_path / ".venv"
|
||||
mock_path.return_value.exists.return_value = False
|
||||
mock_path.return_value.is_symlink.return_value = False
|
||||
mock_path.return_value.symlink_to = MagicMock()
|
||||
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
{"CI_GITEA_TOKEN": "tok123", "CI_GITEA_USERNAME": "emil"},
|
||||
clear=True,
|
||||
):
|
||||
_install_in_image(str(venv_link), "/opt/venv", "lint", "git.host", "org")
|
||||
|
||||
env = mock_run.call_args[1]["env"]
|
||||
assert "PIP_EXTRA_INDEX_URL" in env
|
||||
assert "emil:tok123@git.host" in env["PIP_EXTRA_INDEX_URL"]
|
||||
|
||||
@patch("devx.tools.setup_image.subprocess.run")
|
||||
@patch("devx.tools.setup_image.Path")
|
||||
def test_install_with_token_defaults_username(
|
||||
self,
|
||||
mock_path: MagicMock,
|
||||
mock_run: MagicMock,
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
venv_link = tmp_path / ".venv"
|
||||
mock_path.return_value.exists.return_value = False
|
||||
mock_path.return_value.is_symlink.return_value = False
|
||||
mock_path.return_value.symlink_to = MagicMock()
|
||||
|
||||
with patch.dict(os.environ, {"CI_GITEA_TOKEN": "tok123"}, clear=True):
|
||||
_install_in_image(str(venv_link), "/opt/venv", "", "host", "org")
|
||||
|
||||
env = mock_run.call_args[1]["env"]
|
||||
assert "emil:tok123@host" in env["PIP_EXTRA_INDEX_URL"]
|
||||
|
||||
@patch("devx.tools.setup_image.subprocess.run")
|
||||
@patch("devx.tools.setup_image.Path")
|
||||
def test_install_removes_existing_link(
|
||||
self,
|
||||
mock_path: MagicMock,
|
||||
mock_run: MagicMock,
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
venv_link = tmp_path / ".venv"
|
||||
mock_path.return_value.exists.return_value = True
|
||||
mock_path.return_value.is_symlink.return_value = False
|
||||
mock_path.return_value.unlink = MagicMock()
|
||||
mock_path.return_value.symlink_to = MagicMock()
|
||||
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
_install_in_image(str(venv_link), "/opt/venv", "", "host", "org")
|
||||
|
||||
mock_path.return_value.unlink.assert_called_once()
|
||||
|
||||
@patch("devx.tools.setup_image.subprocess.run")
|
||||
@patch("devx.tools.setup_image.Path")
|
||||
def test_install_removes_existing_symlink(
|
||||
self,
|
||||
mock_path: MagicMock,
|
||||
mock_run: MagicMock,
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
venv_link = tmp_path / ".venv"
|
||||
mock_path.return_value.exists.return_value = False
|
||||
mock_path.return_value.is_symlink.return_value = True
|
||||
mock_path.return_value.unlink = MagicMock()
|
||||
mock_path.return_value.symlink_to = MagicMock()
|
||||
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
_install_in_image(str(venv_link), "/opt/venv", "", "host", "org")
|
||||
|
||||
mock_path.return_value.unlink.assert_called_once()
|
||||
|
||||
@patch("devx.tools.setup_image.subprocess.run")
|
||||
@patch("devx.tools.setup_image.Path")
|
||||
def test_install_failure_raises(self, mock_path: MagicMock, mock_run: MagicMock, tmp_path: Path) -> None:
|
||||
venv_link = tmp_path / ".venv"
|
||||
mock_path.return_value.exists.return_value = False
|
||||
mock_path.return_value.is_symlink.return_value = False
|
||||
mock_path.return_value.symlink_to = MagicMock()
|
||||
mock_run.side_effect = subprocess.CalledProcessError(1, ["pip"])
|
||||
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
_install_in_image(str(venv_link), "/opt/venv", "", "host", "org")
|
||||
|
||||
|
||||
class TestFallbackToSetupCi:
|
||||
@patch("devx.tools.setup_image.subprocess.run")
|
||||
def test_fallback_runs_make_setup_ci(self, mock_run: MagicMock) -> None:
|
||||
_fallback_to_setup_ci()
|
||||
mock_run.assert_called_once_with(["make", "setup-ci"], check=True)
|
||||
|
||||
@patch("devx.tools.setup_image.subprocess.run")
|
||||
def test_fallback_failure_raises(self, mock_run: MagicMock) -> None:
|
||||
mock_run.side_effect = subprocess.CalledProcessError(1, ["make"])
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
_fallback_to_setup_ci()
|
||||
|
||||
|
||||
class TestCli:
|
||||
@patch("devx.tools.setup_image._install_in_image")
|
||||
@patch("devx.tools.setup_image.Path")
|
||||
def test_cli_with_opt_venv_present(
|
||||
self,
|
||||
mock_path: MagicMock,
|
||||
mock_install: MagicMock,
|
||||
) -> None:
|
||||
mock_path.return_value.is_dir.return_value = True
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, ["--extras", "ci,lint"])
|
||||
assert result.exit_code == 0
|
||||
mock_install.assert_called_once()
|
||||
|
||||
@patch("devx.tools.setup_image._fallback_to_setup_ci")
|
||||
@patch("devx.tools.setup_image.Path")
|
||||
def test_cli_falls_back_when_no_opt_venv(
|
||||
self,
|
||||
mock_path: MagicMock,
|
||||
mock_fallback: MagicMock,
|
||||
) -> None:
|
||||
mock_path.return_value.is_dir.return_value = False
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, [])
|
||||
assert result.exit_code == 0
|
||||
mock_fallback.assert_called_once()
|
||||
|
||||
@patch("devx.tools.setup_image._install_in_image")
|
||||
@patch("devx.tools.setup_image.Path")
|
||||
def test_cli_default_values(
|
||||
self,
|
||||
mock_path: MagicMock,
|
||||
mock_install: MagicMock,
|
||||
) -> None:
|
||||
mock_path.return_value.is_dir.return_value = True
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, [])
|
||||
assert result.exit_code == 0
|
||||
call_args = mock_install.call_args[0]
|
||||
assert call_args[0] == ".venv"
|
||||
assert call_args[1] == "/opt/venv"
|
||||
assert call_args[2] == "" # no extras
|
||||
assert call_args[3] == "git.oblachno.oblachno.fyi"
|
||||
assert call_args[4] == "oblachno-oss"
|
||||
|
||||
@patch("devx.tools.setup_image._install_in_image")
|
||||
@patch("devx.tools.setup_image.Path")
|
||||
def test_cli_custom_venv_and_gitea(
|
||||
self,
|
||||
mock_path: MagicMock,
|
||||
mock_install: MagicMock,
|
||||
) -> None:
|
||||
mock_path.return_value.is_dir.return_value = True
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(
|
||||
cli,
|
||||
["--venv", ".custom-venv", "--gitea-host", "gitea.io", "--gitea-org", "myorg"],
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
call_args = mock_install.call_args[0]
|
||||
assert call_args[0] == ".custom-venv"
|
||||
assert call_args[3] == "gitea.io"
|
||||
assert call_args[4] == "myorg"
|
||||
|
||||
@patch("devx.tools.setup_image._install_in_image")
|
||||
@patch("devx.tools.setup_image.Path")
|
||||
def test_cli_with_extras(
|
||||
self,
|
||||
mock_path: MagicMock,
|
||||
mock_install: MagicMock,
|
||||
) -> None:
|
||||
mock_path.return_value.is_dir.return_value = True
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, ["--extras", "lint"])
|
||||
assert result.exit_code == 0
|
||||
assert mock_install.call_args[0][2] == "lint"
|
||||
Reference in New Issue
Block a user