diff --git a/promociones_procesadas/promotion_example.json b/promociones_procesadas/promotion_example.json new file mode 100644 index 0000000000..8fed1fb753 --- /dev/null +++ b/promociones_procesadas/promotion_example.json @@ -0,0 +1,6 @@ +{ + "title": "Summer Sale 2024", + "description": "Get 50% off on all items this summer!", + "discount_code": "SUMMER50", + "valid_until": "2024-08-31T23:59:59Z" +} diff --git a/scripts/auto_deploy_v2.py b/scripts/auto_deploy_v2.py new file mode 100755 index 0000000000..d0638d84a3 --- /dev/null +++ b/scripts/auto_deploy_v2.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +# scripts/auto_deploy_v2.py +import os +import sys +import json +import urllib.error +import urllib.request +from typing import Any, Dict + + +def validar_promocion(data: Dict[str, Any]) -> None: + campos_requeridos = ["title", "description", "discount_code", "valid_until"] + for campo in campos_requeridos: + if campo not in data: + raise ValueError(f"Falta el campo requerido: {campo}") + +def main(): + if len(sys.argv) < 2: + print("Uso: python3 auto_deploy_v2.py ") + sys.exit(1) + + archivo = sys.argv[1] + + try: + with open(archivo, 'r', encoding='utf-8') as f: + data = json.load(f) + except FileNotFoundError: + print(f"Error: No se encontró el archivo '{archivo}'.") + sys.exit(1) + except json.JSONDecodeError as e: + print(f"Error: El archivo no es un JSON válido. Detalles: {e}") + sys.exit(1) + + try: + validar_promocion(data) + except ValueError as e: + print(f"Error de validación: {e}") + sys.exit(1) + + api_key = os.environ.get("TRYONYOU_API_KEY") + if not api_key: + print("Error: La variable de entorno TRYONYOU_API_KEY no está definida.") + sys.exit(1) + + api_url = "https://api.tryonyou.pro/v1/promotions" + headers = { + "Content-Type": "application/json", + "Authorization": f"Bearer {api_key}" + } + + try: + req = urllib.request.Request(api_url, data=json.dumps(data).encode("utf-8"), headers=headers, method="POST") + response = urllib.request.urlopen(req) + response_body = response.read().decode('utf-8') + print(f"Despliegue exitoso. Respuesta de la API: {response_body}") + except urllib.error.URLError as e: + print(f"Error en el despliegue de red o HTTP: {e}") + sys.exit(1) + except Exception as e: + print(f"Error inesperado durante el despliegue: {e}") + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/scripts/auto_deploy_v2.sh b/scripts/auto_deploy_v2.sh new file mode 100755 index 0000000000..edcf629009 --- /dev/null +++ b/scripts/auto_deploy_v2.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# scripts/auto_deploy_v2.sh + +if [ -z "$1" ]; then + echo "Error: Debes proporcionar la ruta a un archivo JSON de promoción." + echo "Uso: $0 " + exit 1 +fi + +FILE_PATH="$1" + +# Obtenemos la ruta absoluta del directorio del script bash +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PYTHON_SCRIPT="$SCRIPT_DIR/auto_deploy_v2.py" + +echo "Iniciando despliegue de promoción: $FILE_PATH" + +python3 "$PYTHON_SCRIPT" "$FILE_PATH" +EXIT_CODE=$? + +if [ $EXIT_CODE -eq 0 ]; then + echo "=========================================" + echo "✅ Despliegue exitoso." + echo "=========================================" + exit 0 +else + echo "=========================================" + echo "❌ Error en el despliegue. Revisa los logs arriba." + echo "=========================================" + exit $EXIT_CODE +fi diff --git a/tests/test_auto_deploy_v2.py b/tests/test_auto_deploy_v2.py new file mode 100644 index 0000000000..aef5b043bc --- /dev/null +++ b/tests/test_auto_deploy_v2.py @@ -0,0 +1,107 @@ +import os +import json +import pathlib +import subprocess +from unittest import mock + +import pytest + +# Assuming we want to run the python script via subprocess for end-to-end tests +# or import and test specific functions if needed. We'll use subprocess for simplicity +# to cover arguments, env vars and outputs properly. + +SCRIPT_PATH = os.path.join(os.path.dirname(__file__), "..", "scripts", "auto_deploy_v2.py") + +@pytest.fixture +def valid_json_path(tmp_path: pathlib.Path) -> str: + data = { + "title": "Test Promo", + "description": "50% off", + "discount_code": "TEST50", + "valid_until": "2024-12-31T23:59:59Z" + } + p = tmp_path / "valid_promo.json" + p.write_text(json.dumps(data), encoding='utf-8') + return str(p) + +@pytest.fixture +def invalid_json_path(tmp_path: pathlib.Path) -> str: + data = { + "title": "Test Promo", + "discount_code": "TEST50" + # missing description and valid_until + } + p = tmp_path / "invalid_promo.json" + p.write_text(json.dumps(data), encoding='utf-8') + return str(p) + +def test_missing_argument() -> None: + result = subprocess.run( + ["python3", SCRIPT_PATH], + capture_output=True, + text=True + ) + assert result.returncode == 1 + assert "Uso:" in result.stdout + +def test_file_not_found() -> None: + result = subprocess.run( + ["python3", SCRIPT_PATH, "nonexistent_file.json"], + capture_output=True, + text=True + ) + assert result.returncode == 1 + assert "No se encontró el archivo" in result.stdout + +def test_invalid_json(invalid_json_path: str) -> None: + result = subprocess.run( + ["python3", SCRIPT_PATH, invalid_json_path], + capture_output=True, + text=True + ) + assert result.returncode == 1 + assert "Error de validación" in result.stdout + assert "Falta el campo requerido" in result.stdout + +def test_missing_api_key(valid_json_path: str, monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.delenv("TRYONYOU_API_KEY", raising=False) + result = subprocess.run( + ["python3", SCRIPT_PATH, valid_json_path], + capture_output=True, + text=True, + env=os.environ + ) + assert result.returncode == 1 + assert "TRYONYOU_API_KEY no está definida" in result.stdout + +@mock.patch("urllib.request.urlopen") +def test_successful_deploy(mock_urlopen: mock.MagicMock, valid_json_path: str, monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setenv("TRYONYOU_API_KEY", "test_key") + + mock_response = mock.MagicMock() + mock_response.read.return_value = b'{"status": "success"}' + mock_urlopen.return_value = mock_response + + # Import script as module to mock urlopen easily instead of subprocess + import sys + import importlib.util + spec = importlib.util.spec_from_file_location("auto_deploy", SCRIPT_PATH) + assert spec is not None + auto_deploy = importlib.util.module_from_spec(spec) + + # Mock sys.argv + test_args = ["auto_deploy_v2.py", valid_json_path] + with mock.patch.object(sys, 'argv', test_args): + # We need to capture stdout for asserting + from io import StringIO + with mock.patch('sys.stdout', new_callable=StringIO) as mock_stdout: + assert spec.loader is not None + spec.loader.exec_module(auto_deploy) + + # Since auto_deploy is constructed dynamically, mypy/pyright doesn't know it has main() + auto_deploy.main() + output = mock_stdout.getvalue() + + assert "Despliegue exitoso" in output + assert '{"status": "success"}' in output + mock_urlopen.assert_called_once()