Files
merica-pipelines/tests/test_sitomat_operator.py
T

123 lines
4.5 KiB
Python
Raw Normal View History

"""
Unit tests for SitomatCallbackOperator (F16 Pipeline Hub Integration).
Menggunakan unittest.mock standar tanpa dependensi eksternal tambahan.
"""
import os
import sys
import pytest
from unittest.mock import patch, MagicMock
# Ensure airflow/dags directory is on python path
DAGS_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "dags"))
if DAGS_DIR not in sys.path:
sys.path.insert(0, DAGS_DIR)
from helpers.sitomat_callback_operator import SitomatCallbackOperator, create_sitomat_session
class TestSitomatCallbackOperator:
def test_invalid_layer_raises_value_error(self):
with pytest.raises(ValueError, match="Layer 'platinum' tidak valid"):
SitomatCallbackOperator(
task_id="test_invalid_layer",
run_id="run-123",
layer="platinum",
artifact_ref="table.name"
)
def test_mock_mode_execution(self):
operator = SitomatCallbackOperator(
task_id="test_mock",
run_id="run-001",
layer="bronze",
artifact_ref="iceberg.bronze.permits",
checksum="sha256-mock",
mock_mode=True
)
result = operator.execute()
assert result["status"] == "mock_success"
assert result["acknowledged"] is True
assert result["layer"] == "bronze"
assert result["runId"] == "run-001"
@patch("helpers.sitomat_callback_operator.create_sitomat_session")
def test_successful_bronze_callback(self, mock_create_session):
mock_session = MagicMock()
mock_response = MagicMock()
mock_response.status_code = 201
mock_response.json.return_value = {"success": True, "versionId": "v1-uuid", "layer": "bronze"}
mock_session.post.return_value = mock_response
mock_create_session.return_value = mock_session
sitomat_url = "http://sitomat.bpkp.go.id:3000"
run_id = "run-20261005-001"
operator = SitomatCallbackOperator(
task_id="test_bronze_callback",
run_id=run_id,
layer="bronze",
artifact_ref="lakehouse.bronze.permits_cdc",
checksum="sha256-111",
sitomat_base_url=sitomat_url,
api_key="secret-pipeline-key",
metadata_payload={"record_count": 8, "ge_status": "PASSED"},
mock_mode=False
)
result = operator.execute()
assert result["status"] == "success"
assert result["statusCode"] == 201
assert result["response"]["versionId"] == "v1-uuid"
mock_session.post.assert_called_once()
@patch("helpers.sitomat_callback_operator.create_sitomat_session")
def test_idempotent_replay_conflict_409(self, mock_create_session):
mock_session = MagicMock()
mock_response = MagicMock()
mock_response.status_code = 409
mock_response.text = "conflict_artifact: run already registered"
mock_session.post.return_value = mock_response
mock_create_session.return_value = mock_session
sitomat_url = "http://sitomat.bpkp.go.id:3000"
run_id = "run-20261005-002"
operator = SitomatCallbackOperator(
task_id="test_conflict_silver",
run_id=run_id,
layer="silver",
artifact_ref="lakehouse.silver.permits_clean",
derived_from_version_id="v1-uuid",
checksum="sha256-222",
sitomat_base_url=sitomat_url,
mock_mode=False
)
result = operator.execute()
assert result["status"] == "conflict_acknowledged"
assert result["statusCode"] == 409
assert "conflict_artifact" in result["response"]
@patch("helpers.sitomat_callback_operator.create_sitomat_session")
def test_connection_error_graceful_handling(self, mock_create_session):
import requests
mock_session = MagicMock()
mock_session.post.side_effect = requests.exceptions.ConnectionError("Connection refused to Sitomat")
mock_create_session.return_value = mock_session
operator = SitomatCallbackOperator(
task_id="test_conn_error",
run_id="run-unreachable",
layer="gold",
artifact_ref="lakehouse.gold.mart",
sitomat_base_url="http://192.0.2.1:9999",
mock_mode=False
)
result = operator.execute()
assert result["status"] == "connection_warning"
assert result["acknowledged"] is False
assert "Connection refused" in result["error"]