123 lines
4.5 KiB
Python
123 lines
4.5 KiB
Python
"""
|
|
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"]
|