mirror of
https://github.com/ivuorinen/actions.git
synced 2026-01-26 03:23:59 +00:00
* docs: update documentation * feat: validate-inputs has it's own pyproject * security: mask DOCKERHUB_PASSWORD * chore: add tokens, checkout, recrete docs, integration tests * fix: add `statuses: write` permission to pr-lint
253 lines
8.8 KiB
Python
253 lines
8.8 KiB
Python
"""Tests for modular_validator.py main entry point."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest # pylint: disable=import-error
|
|
|
|
# Add validate-inputs directory to path
|
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
|
|
# pylint: disable=wrong-import-position
|
|
from modular_validator import main
|
|
|
|
|
|
class TestModularValidator:
|
|
"""Test cases for modular_validator main function."""
|
|
|
|
def test_missing_action_type(self, tmp_path):
|
|
"""Test that missing action-type causes failure."""
|
|
output_file = tmp_path / "github_output"
|
|
output_file.touch()
|
|
|
|
with patch.dict(
|
|
os.environ,
|
|
{"GITHUB_OUTPUT": str(output_file)},
|
|
clear=True,
|
|
), pytest.raises(SystemExit) as exc_info:
|
|
main()
|
|
|
|
assert exc_info.value.code == 1
|
|
content = output_file.read_text()
|
|
assert "status=failure" in content
|
|
assert "error=action-type is required" in content
|
|
|
|
def test_valid_action_type_success(self, tmp_path):
|
|
"""Test successful validation with valid action-type."""
|
|
output_file = tmp_path / "github_output"
|
|
output_file.touch()
|
|
|
|
# docker-build is a known action with a validator
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"GITHUB_OUTPUT": str(output_file),
|
|
"INPUT_ACTION_TYPE": "docker-build",
|
|
"INPUT_TAG": "v1.0.0",
|
|
"INPUT_IMAGE_NAME": "myapp",
|
|
},
|
|
clear=True,
|
|
), patch("modular_validator.logger") as mock_logger:
|
|
main()
|
|
|
|
content = output_file.read_text()
|
|
assert "status=success" in content
|
|
mock_logger.info.assert_called()
|
|
|
|
def test_valid_action_type_validation_failure(self, tmp_path):
|
|
"""Test validation failure with invalid inputs."""
|
|
output_file = tmp_path / "github_output"
|
|
output_file.touch()
|
|
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"GITHUB_OUTPUT": str(output_file),
|
|
"INPUT_ACTION_TYPE": "docker-build",
|
|
"INPUT_TAG": "invalid_tag!", # Invalid tag format
|
|
},
|
|
clear=True,
|
|
):
|
|
with patch("modular_validator.logger") as mock_logger:
|
|
with pytest.raises(SystemExit) as exc_info:
|
|
main()
|
|
|
|
assert exc_info.value.code == 1
|
|
content = output_file.read_text()
|
|
assert "status=failure" in content
|
|
assert "error=" in content
|
|
mock_logger.error.assert_called()
|
|
|
|
def test_environment_variable_extraction(self, tmp_path):
|
|
"""Test that INPUT_* environment variables are extracted correctly."""
|
|
output_file = tmp_path / "github_output"
|
|
output_file.touch()
|
|
|
|
mock_validator = MagicMock()
|
|
mock_validator.validate_inputs.return_value = True
|
|
mock_validator.errors = []
|
|
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"GITHUB_OUTPUT": str(output_file),
|
|
"INPUT_ACTION_TYPE": "docker-build",
|
|
"INPUT_TAG": "v1.0.0",
|
|
"INPUT_IMAGE_NAME": "myapp",
|
|
"INPUT_BUILD_ARGS": "NODE_ENV=prod",
|
|
"NOT_AN_INPUT": "should_be_ignored",
|
|
},
|
|
clear=True,
|
|
), patch("modular_validator.get_validator", return_value=mock_validator):
|
|
main()
|
|
|
|
# Check that validate_inputs was called with correct inputs
|
|
call_args = mock_validator.validate_inputs.call_args[0][0]
|
|
assert "tag" in call_args
|
|
assert call_args["tag"] == "v1.0.0"
|
|
assert "image_name" in call_args or "image-name" in call_args
|
|
assert "build_args" in call_args or "build-args" in call_args
|
|
assert "not_an_input" not in call_args
|
|
|
|
def test_underscore_to_dash_conversion(self, tmp_path):
|
|
"""Test that underscore names are converted to dash names."""
|
|
output_file = tmp_path / "github_output"
|
|
output_file.touch()
|
|
|
|
mock_validator = MagicMock()
|
|
mock_validator.validate_inputs.return_value = True
|
|
mock_validator.errors = []
|
|
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"GITHUB_OUTPUT": str(output_file),
|
|
"INPUT_ACTION_TYPE": "docker-build",
|
|
"INPUT_BUILD_ARGS": "test=value",
|
|
},
|
|
clear=True,
|
|
), patch("modular_validator.get_validator", return_value=mock_validator):
|
|
main()
|
|
|
|
# Check that both underscore and dash versions are present
|
|
call_args = mock_validator.validate_inputs.call_args[0][0]
|
|
assert "build_args" in call_args or "build-args" in call_args
|
|
|
|
def test_action_type_dash_to_underscore(self, tmp_path):
|
|
"""Test that action-type with dashes is converted to underscores."""
|
|
output_file = tmp_path / "github_output"
|
|
output_file.touch()
|
|
|
|
mock_validator = MagicMock()
|
|
mock_validator.validate_inputs.return_value = True
|
|
mock_validator.errors = []
|
|
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"GITHUB_OUTPUT": str(output_file),
|
|
"INPUT_ACTION_TYPE": "docker-build",
|
|
},
|
|
clear=True,
|
|
), patch("modular_validator.get_validator", return_value=mock_validator) as mock_get:
|
|
main()
|
|
|
|
# get_validator should be called with underscore version
|
|
mock_get.assert_called_once_with("docker_build")
|
|
|
|
def test_exception_handling(self, tmp_path):
|
|
"""Test exception handling writes failure to output."""
|
|
output_file = tmp_path / "github_output"
|
|
output_file.touch()
|
|
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"GITHUB_OUTPUT": str(output_file),
|
|
"INPUT_ACTION_TYPE": "docker-build",
|
|
},
|
|
clear=True,
|
|
), patch("modular_validator.get_validator", side_effect=ValueError("Test error")):
|
|
with pytest.raises(SystemExit) as exc_info:
|
|
main()
|
|
|
|
assert exc_info.value.code == 1
|
|
content = output_file.read_text()
|
|
assert "status=failure" in content
|
|
assert "error=Validation script error" in content
|
|
|
|
def test_exception_handling_no_github_output(self):
|
|
"""Test exception handling when GITHUB_OUTPUT not set."""
|
|
# Create a fallback path in home directory
|
|
fallback_path = Path.home() / "github_output"
|
|
|
|
try:
|
|
with patch.dict(os.environ, {"INPUT_ACTION_TYPE": "docker-build"}, clear=True):
|
|
with patch("modular_validator.get_validator", side_effect=ValueError("Test error")):
|
|
with patch("modular_validator.logger"):
|
|
with pytest.raises(SystemExit) as exc_info:
|
|
main()
|
|
|
|
assert exc_info.value.code == 1
|
|
|
|
# Check that fallback file was created
|
|
if fallback_path.exists():
|
|
content = fallback_path.read_text()
|
|
assert "status=failure" in content
|
|
assert "error=Validation script error" in content
|
|
finally:
|
|
# Cleanup fallback file if it exists
|
|
if fallback_path.exists():
|
|
fallback_path.unlink()
|
|
|
|
def test_validation_errors_written_to_output(self, tmp_path):
|
|
"""Test that validation errors are written to GITHUB_OUTPUT."""
|
|
output_file = tmp_path / "github_output"
|
|
output_file.touch()
|
|
|
|
mock_validator = MagicMock()
|
|
mock_validator.validate_inputs.return_value = False
|
|
mock_validator.errors = ["Error 1", "Error 2"]
|
|
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"GITHUB_OUTPUT": str(output_file),
|
|
"INPUT_ACTION_TYPE": "docker-build",
|
|
},
|
|
clear=True,
|
|
), patch("modular_validator.get_validator", return_value=mock_validator):
|
|
with pytest.raises(SystemExit) as exc_info:
|
|
main()
|
|
|
|
assert exc_info.value.code == 1
|
|
content = output_file.read_text()
|
|
assert "status=failure" in content
|
|
assert "Error 1" in content
|
|
assert "Error 2" in content
|
|
|
|
def test_empty_action_type_string(self, tmp_path):
|
|
"""Test that empty action-type string is treated as missing."""
|
|
output_file = tmp_path / "github_output"
|
|
output_file.touch()
|
|
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"GITHUB_OUTPUT": str(output_file),
|
|
"INPUT_ACTION_TYPE": " ", # Whitespace only
|
|
},
|
|
clear=True,
|
|
):
|
|
with pytest.raises(SystemExit) as exc_info:
|
|
main()
|
|
|
|
assert exc_info.value.code == 1
|
|
content = output_file.read_text()
|
|
assert "status=failure" in content
|
|
assert "action-type is required" in content
|