test contracts
This commit is contained in:
@@ -18,6 +18,18 @@ import os
|
||||
# @TIER: CRITICAL
|
||||
# @PURPOSE: Handles encryption and decryption of sensitive data like API keys.
|
||||
# @INVARIANT: Uses a secret key from environment or a default one (fallback only for dev).
|
||||
#
|
||||
# @TEST_CONTRACT: EncryptionManagerModel ->
|
||||
# {
|
||||
# required_fields: {},
|
||||
# invariants: [
|
||||
# "encrypted data can be decrypted back to the original string"
|
||||
# ]
|
||||
# }
|
||||
# @TEST_FIXTURE: basic_encryption_cycle -> {"data": "my_secret_key"}
|
||||
# @TEST_EDGE: decrypt_invalid_data -> raises Exception
|
||||
# @TEST_EDGE: empty_string_encryption -> {"data": ""}
|
||||
# @TEST_INVARIANT: symmetric_encryption -> verifies: [basic_encryption_cycle, empty_string_encryption]
|
||||
class EncryptionManager:
|
||||
# [DEF:EncryptionManager.__init__:Function]
|
||||
# @PURPOSE: Initialize the encryption manager with a Fernet key.
|
||||
|
||||
@@ -113,6 +113,20 @@ def extract_error_context(task: Task, report_status: ReportStatus) -> Optional[E
|
||||
# @POST: Returns TaskReport with required fields and deterministic fallback behavior.
|
||||
# @PARAM: task (Task) - Source task.
|
||||
# @RETURN: TaskReport - Canonical normalized report.
|
||||
#
|
||||
# @TEST_CONTRACT: NormalizeTaskReport ->
|
||||
# {
|
||||
# required_fields: {task: Task},
|
||||
# invariants: [
|
||||
# "Returns a valid TaskReport object",
|
||||
# "Maps TaskStatus to ReportStatus deterministically",
|
||||
# "Extracts ErrorContext for FAILED/PARTIAL tasks"
|
||||
# ]
|
||||
# }
|
||||
# @TEST_FIXTURE: valid_task -> {"task": "MockTask(id='1', plugin_id='superset-migration', status=TaskStatus.SUCCESS)"}
|
||||
# @TEST_EDGE: task_with_error -> {"task": "MockTask(status=TaskStatus.FAILED, logs=[LogEntry(level='ERROR', message='Failed')])"}
|
||||
# @TEST_EDGE: unknown_plugin_type -> {"task": "MockTask(plugin_id='unknown-plugin', status=TaskStatus.PENDING)"}
|
||||
# @TEST_INVARIANT: deterministic_normalization -> verifies: [valid_task, task_with_error, unknown_plugin_type]
|
||||
def normalize_task_report(task: Task) -> TaskReport:
|
||||
with belief_scope("normalize_task_report"):
|
||||
task_type = resolve_task_type(task.plugin_id)
|
||||
|
||||
@@ -26,6 +26,19 @@ from .normalizer import normalize_task_report
|
||||
# @PRE: TaskManager dependency is initialized.
|
||||
# @POST: Provides deterministic list/detail report responses.
|
||||
# @INVARIANT: Service methods are read-only over task history source.
|
||||
#
|
||||
# @TEST_CONTRACT: ReportsServiceModel ->
|
||||
# {
|
||||
# required_fields: {task_manager: TaskManager},
|
||||
# invariants: [
|
||||
# "list_reports returns a matching ReportCollection",
|
||||
# "get_report_detail returns a valid ReportDetailView or None"
|
||||
# ]
|
||||
# }
|
||||
# @TEST_FIXTURE: valid_service -> {"task_manager": "MockTaskManager()"}
|
||||
# @TEST_EDGE: empty_task_list -> returns empty ReportCollection
|
||||
# @TEST_EDGE: report_not_found -> get_report_detail returns None
|
||||
# @TEST_INVARIANT: consistent_pagination -> verifies: [valid_service]
|
||||
class ReportsService:
|
||||
# [DEF:__init__:Function]
|
||||
# @TIER: CRITICAL
|
||||
|
||||
@@ -71,6 +71,17 @@ TASK_TYPE_PROFILES: Dict[TaskType, Dict[str, Any]] = {
|
||||
# @POST: Always returns one of TaskType enum values.
|
||||
# @PARAM: plugin_id (Optional[str]) - Source plugin/task identifier from task record.
|
||||
# @RETURN: TaskType - Resolved canonical type or UNKNOWN fallback.
|
||||
#
|
||||
# @TEST_CONTRACT: ResolveTaskType ->
|
||||
# {
|
||||
# required_fields: {plugin_id: str},
|
||||
# invariants: ["returns TaskType.UNKNOWN for missing/unmapped plugin_id"]
|
||||
# }
|
||||
# @TEST_FIXTURE: valid_plugin -> {"plugin_id": "superset-migration"}
|
||||
# @TEST_EDGE: empty_plugin -> {"plugin_id": ""}
|
||||
# @TEST_EDGE: none_plugin -> {"plugin_id": None}
|
||||
# @TEST_EDGE: unknown_plugin -> {"plugin_id": "invalid-plugin"}
|
||||
# @TEST_INVARIANT: fallback_to_unknown -> verifies: [empty_plugin, none_plugin, unknown_plugin]
|
||||
def resolve_task_type(plugin_id: Optional[str]) -> TaskType:
|
||||
with belief_scope("resolve_task_type"):
|
||||
normalized = (plugin_id or "").strip()
|
||||
@@ -86,6 +97,15 @@ def resolve_task_type(plugin_id: Optional[str]) -> TaskType:
|
||||
# @POST: Returns a profile dict and never raises for unknown types.
|
||||
# @PARAM: task_type (TaskType) - Canonical task type.
|
||||
# @RETURN: Dict[str, Any] - Profile metadata used by normalization and UI contracts.
|
||||
#
|
||||
# @TEST_CONTRACT: GetTypeProfile ->
|
||||
# {
|
||||
# required_fields: {task_type: TaskType},
|
||||
# invariants: ["returns a valid metadata dictionary even for UNKNOWN"]
|
||||
# }
|
||||
# @TEST_FIXTURE: valid_profile -> {"task_type": "migration"}
|
||||
# @TEST_EDGE: missing_profile -> {"task_type": "some_new_type"}
|
||||
# @TEST_INVARIANT: always_returns_dict -> verifies: [valid_profile, missing_profile]
|
||||
def get_type_profile(task_type: TaskType) -> Dict[str, Any]:
|
||||
with belief_scope("get_type_profile"):
|
||||
return TASK_TYPE_PROFILES.get(task_type, TASK_TYPE_PROFILES[TaskType.UNKNOWN])
|
||||
|
||||
Reference in New Issue
Block a user