chore: migrate GRACE-Poly anchors to hierarchical dotted naming
Systematic rename of all semantic anchors (#region, [DEF], @RELATION) across 1400+ files — backend Python, frontend Svelte/TS, specs, docs: - Flat anchors become Namespace.Module.Entity - @RELATION references updated to match new anchor paths - Zero business logic changes
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# #region Test.MigrationArchiveParser [C:3] [TYPE Module] [SEMANTICS test,migration,archive,parser]
|
||||
# @BRIEF Tests for core/migration/archive_parser.py — MigrationArchiveParser.
|
||||
# @RELATION BINDS_TO -> [MigrationArchiveParserModule]
|
||||
# @RELATION BINDS_TO -> [Core.ArchiveParser.MigrationArchiveParserModule]
|
||||
# @TEST_EDGE: invalid_yaml_skipped -> logger.reflect called
|
||||
# @TEST_EDGE: non_dict_payload -> returns None
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.AsyncNetwork [C:4] [TYPE Module] [SEMANTICS test, async, network, client, httpx]
|
||||
# @BRIEF Tests for core/utils/async_network.py — AsyncAPIClient.
|
||||
# @RELATION BINDS_TO -> [AsyncNetworkModule]
|
||||
# @RELATION BINDS_TO -> [Core.AsyncNetwork.AsyncNetworkModule]
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.AsyncNetwork.Edge [C:4] [TYPE Module] [SEMANTICS test, async, network, auth, upload, coverage]
|
||||
# @BRIEF Additional edge case tests for AsyncAPIClient — cache hit after lock, upload status, and remaining branches.
|
||||
# @RELATION BINDS_TO -> [AsyncNetworkModule]
|
||||
# @RELATION BINDS_TO -> [Core.AsyncNetwork.AsyncNetworkModule]
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.AsyncNetworkExtra [C:2] [TYPE Module] [SEMANTICS test, async, network, edge, upload]
|
||||
# @BRIEF Extra edge-case tests for async_network.py and network.py — auth CSRF refresh, expired cache, upload 201.
|
||||
# @RELATION BINDS_TO -> [AsyncNetworkModule]
|
||||
# @RELATION BINDS_TO -> [Core.AsyncNetwork.AsyncNetworkModule]
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.AsyncSupersetClient [C:3] [TYPE Module] [SEMANTICS test,superset,async,client]
|
||||
# @BRIEF Tests for core/async_superset_client.py — AsyncSupersetClient.
|
||||
# @RELATION BINDS_TO -> [AsyncSupersetClientModule]
|
||||
# @RELATION BINDS_TO -> [Core.AsyncSupersetClient.AsyncSupersetClientModule]
|
||||
# @TEST_EDGE: aclose_called -> delegates to client.aclose
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.AuthConfig [C:3] [TYPE Module] [SEMANTICS test,auth,config,pydantic]
|
||||
# @BRIEF Tests for core/auth/config.py — AuthConfig Pydantic settings.
|
||||
# @RELATION BINDS_TO -> [AuthConfigModule]
|
||||
# @RELATION BINDS_TO -> [Core.Config.AuthConfigModule]
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
@@ -11,7 +11,7 @@ from unittest.mock import patch
|
||||
import pytest
|
||||
|
||||
|
||||
# #region test_auth_config [C:2] [TYPE Function]
|
||||
# #region Test.AuthConfig.TestAuthConfig [C:2] [TYPE Function]
|
||||
# @BRIEF Test AuthConfig validation and default values.
|
||||
class TestAuthConfig:
|
||||
def test_requires_secret_key(self):
|
||||
@@ -89,10 +89,10 @@ class TestAuthConfig:
|
||||
config = AuthConfig()
|
||||
assert config.JWT_AUDIENCE == "superset-tools-api"
|
||||
assert config.JWT_ISSUER == "superset-tools"
|
||||
# #endregion test_auth_config
|
||||
# #endregion Test.AuthConfig.TestAuthConfig
|
||||
|
||||
|
||||
# #region test_auth_config_singleton [C:2] [TYPE Function]
|
||||
# #region Test.AuthConfig.TestAuthConfigSingleton [C:2] [TYPE Function]
|
||||
# @BRIEF Test auth_config singleton creation.
|
||||
class TestAuthConfigSingleton:
|
||||
def test_auth_config_instance(self):
|
||||
@@ -108,5 +108,5 @@ class TestAuthConfigSingleton:
|
||||
importlib.reload(config)
|
||||
assert config.auth_config is not None
|
||||
assert config.auth_config.SECRET_KEY == "test-key-singleton"
|
||||
# #endregion test_auth_config_singleton
|
||||
# #endregion Test.AuthConfig.TestAuthConfigSingleton
|
||||
# #endregion Test.AuthConfig
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.AuthOauth [C:3] [TYPE Module] [SEMANTICS test,auth,oauth,adfs,oidc]
|
||||
# @BRIEF Tests for core/auth/oauth.py — register_adfs, is_adfs_configured.
|
||||
# @RELATION BINDS_TO -> [AuthOauthModule]
|
||||
# @RELATION BINDS_TO -> [Core.Oauth.AuthOauthModule]
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
@@ -11,7 +11,7 @@ from unittest.mock import MagicMock, patch
|
||||
import pytest
|
||||
|
||||
|
||||
# #region test_register_adfs [C:2] [TYPE Function]
|
||||
# #region Test.AuthOauth.TestRegisterAdfs [C:2] [TYPE Function]
|
||||
# @BRIEF Test register_adfs and is_adfs_configured.
|
||||
class TestRegisterAdfs:
|
||||
def test_register_adfs_when_configured(self):
|
||||
@@ -49,14 +49,14 @@ class TestRegisterAdfs:
|
||||
import src.core.auth.oauth as oauth_module
|
||||
with patch.object(oauth_module.oauth, "_registry", {}):
|
||||
assert oauth_module.is_adfs_configured() is False
|
||||
# #endregion test_register_adfs
|
||||
# #endregion Test.AuthOauth.TestRegisterAdfs
|
||||
|
||||
|
||||
# #region test_oauth_module_init [C:2] [TYPE Function]
|
||||
# #region Test.AuthOauth.TestOauthModuleInit [C:2] [TYPE Function]
|
||||
# @BRIEF Test module-level initialization calls register_adfs.
|
||||
class TestOauthModuleInit:
|
||||
def test_oauth_instance_exists(self):
|
||||
import src.core.auth.oauth as oauth_module
|
||||
assert oauth_module.oauth is not None
|
||||
# #endregion test_oauth_module_init
|
||||
# #endregion Test.AuthOauth.TestOauthModuleInit
|
||||
# #endregion Test.AuthOauth
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.Auth.Repository [C:3] [TYPE Module] [SEMANTICS test,auth,repository,sqlalchemy]
|
||||
# @BRIEF Tests for core/auth/repository.py — AuthRepository CRUD methods.
|
||||
# @RELATION BINDS_TO -> [AuthRepositoryModule]
|
||||
# @RELATION BINDS_TO -> [Core.Repository.AuthRepositoryModule]
|
||||
# @TEST_EDGE: user_not_found -> returns None
|
||||
# @TEST_EDGE: empty_ad_groups -> returns []
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.AuthSecurity [C:3] [TYPE Module] [SEMANTICS test,auth,security,bcrypt,password]
|
||||
# @BRIEF Tests for core/auth/security.py — verify_password, get_password_hash.
|
||||
# @RELATION BINDS_TO -> [AuthSecurityModule]
|
||||
# @RELATION BINDS_TO -> [Core.Security.AuthSecurityModule]
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
@@ -11,7 +11,7 @@ from unittest.mock import MagicMock, patch
|
||||
import pytest
|
||||
|
||||
|
||||
# #region test_get_password_hash [C:2] [TYPE Function]
|
||||
# #region Test.AuthSecurity.TestGetPasswordHash [C:2] [TYPE Function]
|
||||
# @BRIEF Test get_password_hash generates valid bcrypt hashes.
|
||||
class TestGetPasswordHash:
|
||||
def test_returns_bcrypt_hash(self):
|
||||
@@ -25,10 +25,10 @@ class TestGetPasswordHash:
|
||||
h1 = get_password_hash("same-password")
|
||||
h2 = get_password_hash("same-password")
|
||||
assert h1 != h2 # bcrypt gensalt produces different salts
|
||||
# #endregion test_get_password_hash
|
||||
# #endregion Test.AuthSecurity.TestGetPasswordHash
|
||||
|
||||
|
||||
# #region test_verify_password [C:2] [TYPE Function]
|
||||
# #region Test.AuthSecurity.TestVerifyPassword [C:2] [TYPE Function]
|
||||
# @BRIEF Test verify_password for correct and incorrect passwords.
|
||||
class TestVerifyPassword:
|
||||
def test_verifies_correct_password(self):
|
||||
@@ -59,5 +59,5 @@ class TestVerifyPassword:
|
||||
hashed = get_password_hash("pässwörd-你好")
|
||||
assert verify_password("pässwörd-你好", hashed) is True
|
||||
assert verify_password("wrong", hashed) is False
|
||||
# #endregion test_verify_password
|
||||
# #endregion Test.AuthSecurity.TestVerifyPassword
|
||||
# #endregion Test.AuthSecurity
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.Core.ClientRegistry [C:3] [TYPE Module] [SEMANTICS test, client, registry, async, superset]
|
||||
# @BRIEF Tests for SupersetClientRegistry — singleton async client management.
|
||||
# @RELATION BINDS_TO -> [SupersetClientRegistryModule]
|
||||
# @RELATION BINDS_TO -> [Core.ClientRegistry.SupersetClientRegistryModule]
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.Core.ConnectionService.Edge [C:3] [TYPE Module] [SEMANTICS test, connections, edge, coverage]
|
||||
# @BRIEF Edge case tests for ConnectionService — encryption fallback, DB refs, dialect tests, unsupported dialect.
|
||||
# @RELATION BINDS_TO -> [ConnectionService]
|
||||
# @RELATION BINDS_TO -> [Core.ConnectionService]
|
||||
|
||||
import os
|
||||
import sys
|
||||
@@ -262,7 +262,7 @@ class TestDeleteEdgeCases:
|
||||
class TestConnectionTimeout:
|
||||
"""Connection test timeout behavior — asyncio.TimeoutError handling."""
|
||||
|
||||
# #region test_timeout_error_response [C:2] [TYPE Function] [SEMANTICS test,connection,timeout,error]
|
||||
# #region Test.Core.TestTimeoutErrorResponse [C:2] [TYPE Function] [SEMANTICS test,connection,timeout,error]
|
||||
# @BRIEF When _test_postgresql hangs, asyncio.TimeoutError is caught and
|
||||
# returns {success: false, error: "Connection test timed out after 15s"}.
|
||||
@pytest.mark.asyncio
|
||||
@@ -287,9 +287,9 @@ class TestConnectionTimeout:
|
||||
assert "Connection test timed out" in result["error"]
|
||||
assert "15" not in result["error"] # we overrode to 0.1
|
||||
assert "after" in result["error"]
|
||||
# #endregion test_timeout_error_response
|
||||
# #endregion Test.Core.TestTimeoutErrorResponse
|
||||
|
||||
# #region test_timeout_still_records_latency [C:2] [TYPE Function] [SEMANTICS test,connection,timeout,latency]
|
||||
# #region Test.Core.TestTimeoutStillRecordsLatency [C:2] [TYPE Function] [SEMANTICS test,connection,timeout,latency]
|
||||
# @BRIEF Even on timeout, latency_ms field is populated with elapsed time.
|
||||
@pytest.mark.asyncio
|
||||
async def test_timeout_still_records_latency(self, mock_cm):
|
||||
@@ -312,6 +312,6 @@ class TestConnectionTimeout:
|
||||
assert "latency_ms" in result
|
||||
assert isinstance(result["latency_ms"], int)
|
||||
assert result["latency_ms"] >= 0 # should be a non-negative elapsed time
|
||||
# #endregion test_timeout_still_records_latency
|
||||
# #endregion Test.Core.TestTimeoutStillRecordsLatency
|
||||
|
||||
# #endregion Test.Core.ConnectionService.Edge
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.DashboardsFiltersMixin [C:3] [TYPE Module] [SEMANTICS test, dashboard, filter, permalink, mixin]
|
||||
# @BRIEF Tests for core/superset_client/_dashboards_filters.py — SupersetDashboardsFiltersMixin.
|
||||
# @RELATION BINDS_TO -> [SupersetDashboardsFiltersMixin]
|
||||
# @RELATION BINDS_TO -> [Core.DashboardsFilters.SupersetDashboardsFiltersMixin]
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.DashboardsWriteMixin [C:3] [TYPE Module] [SEMANTICS test, dashboard, write, markdown, layout]
|
||||
# @BRIEF Tests for core/superset_client/_dashboards_write.py — SupersetDashboardsWriteMixin.
|
||||
# @RELATION BINDS_TO -> [SupersetDashboardsWriteMixin]
|
||||
# @RELATION BINDS_TO -> [Core.DashboardsWrite.SupersetDashboardsWriteMixin]
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.DatasetMapper [C:3] [TYPE Module] [SEMANTICS test, dataset, mapper, sqllab, excel]
|
||||
# @BRIEF Tests for core/utils/dataset_mapper.py — DatasetMapper.
|
||||
# @RELATION BINDS_TO -> [DatasetMapperModule]
|
||||
# @RELATION BINDS_TO -> [Core.DatasetMapper.DatasetMapperModule]
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.DatasetMapperExtra [C:2] [TYPE Module] [SEMANTICS test, dataset, mapper, metrics, edge]
|
||||
# @BRIEF Extra tests for dataset_mapper.py — metrics handling in run_mapping (lines 193-206).
|
||||
# @RELATION BINDS_TO -> [DatasetMapperModule]
|
||||
# @RELATION BINDS_TO -> [Core.DatasetMapper.DatasetMapperModule]
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.DatasetsMixin [C:3] [TYPE Module] [SEMANTICS test, dataset, superset, crud, detail]
|
||||
# @BRIEF Tests for core/superset_client/_datasets.py — SupersetDatasetsMixin.
|
||||
# @RELATION BINDS_TO -> [SupersetDatasetsMixin]
|
||||
# @RELATION BINDS_TO -> [Core.Datasets.SupersetDatasetsMixin]
|
||||
# @TEST_EDGE: missing_param -> Null query param handled
|
||||
# @TEST_EDGE: empty_result -> Empty dataset list returns 0 results
|
||||
# @TEST_EDGE: external_api_error -> Exception in API call caught and logged
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.DatasetsPreviewMixin [C:3] [TYPE Module] [SEMANTICS test, dataset, preview, compile, query]
|
||||
# @BRIEF Tests for core/superset_client/_datasets_preview.py — SupersetDatasetsPreviewMixin.
|
||||
# @RELATION BINDS_TO -> [SupersetDatasetsPreviewMixin]
|
||||
# @RELATION BINDS_TO -> [Core.DatasetsPreview.SupersetDatasetsPreviewMixin]
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.DatasetsPreviewFiltersMixin [C:3] [TYPE Module] [SEMANTICS test, dataset, preview, filter, sql, extract]
|
||||
# @BRIEF Tests for core/superset_client/_datasets_preview_filters.py — filter normalization + SQL extraction.
|
||||
# @RELATION BINDS_TO -> [SupersetDatasetsPreviewFiltersMixin]
|
||||
# @RELATION BINDS_TO -> [Core.DatasetsPreviewFilters.SupersetDatasetsPreviewFiltersMixin]
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.LayoutUtils [C:2] [TYPE Module] [SEMANTICS test, layout, position, json, banner]
|
||||
# @BRIEF Tests for core/superset_client/_layout_utils.py — pure position JSON manipulation.
|
||||
# @RELATION BINDS_TO -> [LayoutUtils]
|
||||
# @RELATION BINDS_TO -> [Core.LayoutUtils]
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
@@ -10,7 +10,7 @@ from src.core.task_manager.log_export import row_to_export_record, redact_text
|
||||
from src.core.task_manager.models import LogEntry
|
||||
|
||||
|
||||
# #region test_trim_buffer_drops_debug_first [C:2]
|
||||
# #region Test.Core.TestTrimBufferDropsDebugFirst [C:2]
|
||||
# @BRIEF Verify buffer trimming drops DEBUG entries first while preserving ERROR/INFO.
|
||||
def test_trim_buffer_drops_debug_first():
|
||||
bus = EventBus(MagicMock())
|
||||
@@ -25,10 +25,10 @@ def test_trim_buffer_drops_debug_first():
|
||||
assert len(trimmed) <= 5
|
||||
assert any(e.level == "ERROR" for e in trimmed)
|
||||
assert bus._dropped_debug >= 1
|
||||
# #endregion test_trim_buffer_drops_debug_first
|
||||
# #endregion Test.Core.TestTrimBufferDropsDebugFirst
|
||||
|
||||
|
||||
# #region test_export_record_cot_and_redaction [C:2]
|
||||
# #region Test.Core.TestExportRecordCotAndRedaction [C:2]
|
||||
# @BRIEF Verify CoT JSON parse, metadata redaction, and credential stripping.
|
||||
def test_export_record_cot_and_redaction():
|
||||
import json
|
||||
@@ -53,10 +53,10 @@ def test_export_record_cot_and_redaction():
|
||||
assert rec["intent"] == "Apply policy"
|
||||
assert rec["metadata"]["password"] == "***"
|
||||
assert "redacted" in redact_text("API Key decrypted (first 8 chars): sk-abcdefgh")
|
||||
# #endregion test_export_record_cot_and_redaction
|
||||
# #endregion Test.Core.TestExportRecordCotAndRedaction
|
||||
|
||||
|
||||
# #region test_add_log_respects_task_log_level [C:2]
|
||||
# #region Test.Core.TestAddLogRespectsTaskLogLevel [C:2]
|
||||
# @BRIEF Verify DEBUG log entries are filtered when task_log_level is INFO.
|
||||
@pytest.mark.asyncio
|
||||
async def test_add_log_respects_task_log_level(monkeypatch):
|
||||
@@ -68,10 +68,10 @@ async def test_add_log_respects_task_log_level(monkeypatch):
|
||||
assert bus._log_buffer.get("t1") in (None, [])
|
||||
await bus.add_log("t1", "INFO", "ok")
|
||||
assert len(bus._log_buffer["t1"]) == 1
|
||||
# #endregion test_add_log_respects_task_log_level
|
||||
# #endregion Test.Core.TestAddLogRespectsTaskLogLevel
|
||||
|
||||
|
||||
# #region test_task_id_contextvar [C:2]
|
||||
# #region Test.Core.TestTaskIdContextvar [C:2]
|
||||
# @BRIEF Verify task_id ContextVar propagates into CotJsonFormatter output.
|
||||
def test_task_id_contextvar_stamps_formatter():
|
||||
import json
|
||||
@@ -101,6 +101,6 @@ def test_task_id_contextvar_stamps_formatter():
|
||||
assert obj.get("payload", {}).get("task_id") == "task-xyz-123"
|
||||
finally:
|
||||
clear_task_id()
|
||||
# #endregion test_task_id_contextvar
|
||||
# #endregion Test.Core.TestTaskIdContextvar
|
||||
# #endregion Test.Core.LogExportBulk
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.Logger.Edge [C:3] [TYPE Module] [SEMANTICS test, logging, belief, cot, edge]
|
||||
# @BRIEF Edge case tests for logger.py — configure_logger, file handler, believed decorator, reflect/explore error extras.
|
||||
# @RELATION BINDS_TO -> [LoggerModule]
|
||||
# @RELATION BINDS_TO -> [Core.Logger.LoggerModule]
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
@@ -30,7 +30,7 @@ def _build_manager():
|
||||
return mgr
|
||||
|
||||
|
||||
# #region test_update_global_settings_hot_applies_log_level [C:2]
|
||||
# #region Test.Core.TestUpdateGlobalSettingsHotAppliesLogLevel [C:2]
|
||||
def test_update_global_settings_hot_applies_log_level():
|
||||
"""FR-005: changing settings.logging.level reconfigures live loggers without restart."""
|
||||
from ss_tools.shared.cot_logger import cot_logger
|
||||
@@ -77,10 +77,10 @@ def test_update_global_settings_hot_applies_log_level():
|
||||
assert "INFO" in names
|
||||
finally:
|
||||
logger.removeHandler(h)
|
||||
# #endregion test_update_global_settings_hot_applies_log_level
|
||||
# #endregion Test.Core.TestUpdateGlobalSettingsHotAppliesLogLevel
|
||||
|
||||
|
||||
# #region test_dashboard_projection_samples_are_debug [C:2]
|
||||
# #region Test.Core.TestDashboardProjectionSamplesAreDebug [C:2]
|
||||
@pytest.mark.asyncio
|
||||
async def test_dashboard_projection_samples_are_debug(caplog):
|
||||
"""Per-dashboard actor samples must not appear at INFO (high-frequency → DEBUG)."""
|
||||
@@ -139,10 +139,10 @@ async def test_dashboard_projection_samples_are_debug(caplog):
|
||||
messages = [r.getMessage() for r in caplog.records]
|
||||
assert not any("Dashboard actor projection sample" in m for m in messages)
|
||||
assert any("Dashboard actor projection complete" in m for m in messages)
|
||||
# #endregion test_dashboard_projection_samples_are_debug
|
||||
# #endregion Test.Core.TestDashboardProjectionSamplesAreDebug
|
||||
|
||||
|
||||
# #region test_security_event_single_atom [C:2]
|
||||
# #region Test.Core.TestSecurityEventSingleAtom [C:2]
|
||||
def test_security_event_single_atom(caplog):
|
||||
"""Security audit emits one REASON atom (not recorded + details pair)."""
|
||||
from src.core.auth.logger import log_security_event
|
||||
@@ -163,10 +163,10 @@ def test_security_event_single_atom(caplog):
|
||||
assert len(security_msgs) == 1
|
||||
assert "LOGIN_SUCCESS" in security_msgs[0]
|
||||
assert "Security event details" not in " ".join(security_msgs)
|
||||
# #endregion test_security_event_single_atom
|
||||
# #endregion Test.Core.TestSecurityEventSingleAtom
|
||||
|
||||
|
||||
# #region test_merge_logging_patch_preserves_file_path [C:2]
|
||||
# #region Test.Core.TestMergeLoggingPatchPreservesFilePath [C:2]
|
||||
def test_merge_logging_patch_preserves_file_path():
|
||||
"""Partial admin-style logging update must not clear file_path."""
|
||||
from src.api.routes.settings import update_logging_config
|
||||
@@ -208,5 +208,5 @@ def test_merge_logging_patch_preserves_file_path():
|
||||
assert result.enable_belief_state is False
|
||||
assert saved["logging"].file_path == "logs/app.log"
|
||||
assert saved["logging"].max_bytes == 12345
|
||||
# #endregion test_merge_logging_patch_preserves_file_path
|
||||
# #endregion Test.Core.TestMergeLoggingPatchPreservesFilePath
|
||||
# #endregion Test.Core.LoggingHotApply
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.IdMappingService [C:4] [TYPE Module] [SEMANTICS test, mapping, service, sync, scheduler]
|
||||
# @BRIEF Tests for core/mapping_service.py — IdMappingService.
|
||||
# @RELATION BINDS_TO -> [IdMappingServiceModule]
|
||||
# @RELATION BINDS_TO -> [Core.MappingService.IdMappingServiceModule]
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.FuzzyMatching [C:3] [TYPE Module] [SEMANTICS test,fuzzy,matching,rapidfuzz]
|
||||
# @BRIEF Tests for core/utils/matching.py — suggest_mappings.
|
||||
# @RELATION BINDS_TO -> [FuzzyMatching]
|
||||
# @RELATION BINDS_TO -> [Core.Matching.FuzzyMatching]
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
@@ -10,7 +10,7 @@ sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src"))
|
||||
import pytest
|
||||
|
||||
|
||||
# #region test_suggest_mappings [C:2] [TYPE Function]
|
||||
# #region Test.FuzzyMatching.TestSuggestMappings [C:2] [TYPE Function]
|
||||
# @BRIEF Test suggest_mappings for various database name scenarios.
|
||||
class TestSuggestMappings:
|
||||
def test_empty_targets_returns_empty(self):
|
||||
@@ -95,5 +95,5 @@ class TestSuggestMappings:
|
||||
[{"uuid": "s1"}], # missing database_name
|
||||
[{"uuid": "t1", "database_name": "db"}],
|
||||
)
|
||||
# #endregion test_suggest_mappings
|
||||
# #endregion Test.FuzzyMatching.TestSuggestMappings
|
||||
# #endregion Test.FuzzyMatching
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.Network [C:2] [TYPE Module] [SEMANTICS test, network, error, auth, cache]
|
||||
# @BRIEF Tests for core/utils/network.py — error classes and SupersetAuthCache.
|
||||
# @RELATION BINDS_TO -> [NetworkModule]
|
||||
# @RELATION BINDS_TO -> [Core.Network.NetworkModule]
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.NotificationProvidersExtra [C:3] [TYPE Module] [SEMANTICS test,notification,provider,http-client]
|
||||
# @BRIEF Additional tests for notifications/providers.py — _get_http_client edge cases.
|
||||
# @RELATION BINDS_TO -> [providers]
|
||||
# @RELATION BINDS_TO -> [Services.Providers]
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
@@ -11,7 +11,7 @@ from unittest.mock import AsyncMock, MagicMock, patch
|
||||
import pytest
|
||||
|
||||
|
||||
# #region test_get_http_client [C:2] [TYPE Function]
|
||||
# #region Test.NotificationProvidersExtra.TestGetHttpClient [C:2] [TYPE Function]
|
||||
# @BRIEF Test _get_http_client singleton behavior.
|
||||
class TestGetHttpClient:
|
||||
@pytest.mark.asyncio
|
||||
@@ -38,6 +38,6 @@ class TestGetHttpClient:
|
||||
client1 = await providers_module._get_http_client()
|
||||
client2 = await providers_module._get_http_client()
|
||||
assert client1 is client2 # Same cached instance
|
||||
# #endregion test_get_http_client
|
||||
# #endregion Test.NotificationProvidersExtra.TestGetHttpClient
|
||||
|
||||
# #endregion Test.NotificationProvidersExtra
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.PluginBase [C:3] [TYPE Module] [SEMANTICS test,plugin,base,abstract]
|
||||
# @BRIEF Tests for core/plugin_base.py — PluginBase, PluginConfig.
|
||||
# @RELATION BINDS_TO -> [PluginBase]
|
||||
# @RELATION BINDS_TO -> [Core.PluginBase]
|
||||
# @TEST_EDGE: missing_required_property -> TypeError on abstract instantiation
|
||||
# @TEST_EDGE: invalid_plugin_config -> ValidationError on missing fields
|
||||
# @TEST_EDGE: abstract_method_call -> super().abstract_method returns None
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.PluginLoader [C:3] [TYPE Module] [SEMANTICS test, plugin, loader, dynamic, import]
|
||||
# @BRIEF Tests for core/plugin_loader.py — PluginLoader.
|
||||
# @RELATION BINDS_TO -> [PluginLoader]
|
||||
# @RELATION BINDS_TO -> [Core.PluginLoader]
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.Migration.RiskAssessor.Edge [C:3] [TYPE Module] [SEMANTICS test, risk, assessor, migration, edge]
|
||||
# @BRIEF Edge case tests for risk assessor — index_by_uuid, extract_owner_identifiers, build_risks, score_risks.
|
||||
# @RELATION BINDS_TO -> [RiskAssessorModule]
|
||||
# @RELATION BINDS_TO -> [Core.RiskAssessor.RiskAssessorModule]
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.Superset.Charts [C:3] [TYPE Module] [SEMANTICS test,superset,charts]
|
||||
# @BRIEF Tests for core/superset_client/_charts.py — SupersetChartsMixin.
|
||||
# @RELATION BINDS_TO -> [SupersetChartsMixin]
|
||||
# @RELATION BINDS_TO -> [Core.Charts.SupersetChartsMixin]
|
||||
# @TEST_EDGE: extract_chart_ids_non_dict_walks -> empty set
|
||||
# @TEST_EDGE: extract_chart_ids_chart_n_pattern -> CHART-123 format
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.SupersetContextExtractorBase [C:3] [TYPE Module] [SEMANTICS test, superset, context, extract, parse]
|
||||
# @BRIEF Tests for core/utils/superset_context_extractor/_base.py — SupersetContextExtractorBase.
|
||||
# @RELATION BINDS_TO -> [SupersetContextExtractorBase]
|
||||
# @RELATION BINDS_TO -> [Core.Base.SupersetContextExtractorBase]
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.SupersetContextFilters [C:3] [TYPE Module] [SEMANTICS test, superset, filter, extract, mixin]
|
||||
# @BRIEF Tests for _filters.py — SupersetContextFiltersExtractMixin._extract_imported_filters.
|
||||
# @RELATION BINDS_TO -> [SupersetContextFiltersExtractMixin]
|
||||
# @RELATION BINDS_TO -> [Core.Filters.SupersetContextFiltersExtractMixin]
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
@@ -229,3 +229,4 @@ class TestExtractImportedFilters:
|
||||
"native_filters": "not_a_list"
|
||||
})
|
||||
assert result == []
|
||||
# #endregion Test.SupersetContextFilters
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.SupersetContextFiltersExtra [C:2] [TYPE Module] [SEMANTICS test, superset, filter, edge]
|
||||
# @BRIEF Extra tests for _filters.py — edge cases that hit lines 76, 107, 144, 167, 173-178, 182-193.
|
||||
# @RELATION BINDS_TO -> [SupersetContextFiltersExtractMixin]
|
||||
# @RELATION BINDS_TO -> [Core.Filters.SupersetContextFiltersExtractMixin]
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.SupersetContextParsing [C:3] [TYPE Module] [SEMANTICS test, superset, context, parse, link]
|
||||
# @BRIEF Tests for _parsing.py — SupersetContextParsingMixin.parse_superset_link full branch coverage.
|
||||
# @RELATION BINDS_TO -> [SupersetContextParsingMixin]
|
||||
# @RELATION BINDS_TO -> [Core.Parsing.SupersetContextParsingMixin]
|
||||
# @TEST_CONTRACT: [link:str] -> [SupersetParsedContext]
|
||||
# @TEST_SCENARIO: dataset_link -> resolves dataset_id and dataset_ref
|
||||
# @TEST_SCENARIO: dashboard_permalink -> resolves via get_dashboard_permalink_state
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.SupersetContextPII [C:2] [TYPE Module] [SEMANTICS test, superset, pii, mask, sanitize]
|
||||
# @BRIEF Tests for _pii.py — mask_pii_value, sanitize_imported_filter_for_assistant, _mask_sensitive_text.
|
||||
# @RELATION BINDS_TO -> [SupersetContextExtractorPII]
|
||||
# @RELATION BINDS_TO -> [Core.Pii.SupersetContextExtractorPII]
|
||||
# @TEST_CONTRACT: [value:Any] -> [tuple[Any, bool]]
|
||||
# @TEST_SCENARIO: email_mask -> replaces local part with ***
|
||||
# @TEST_SCENARIO: uuid_mask -> preserves last 12 chars
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.SupersetContextRecovery [C:3] [TYPE Module] [SEMANTICS test, superset, recovery, filter, dashboard]
|
||||
# @BRIEF Tests for _recovery.py — SupersetContextRecoveryMixin recover_imported_filters and _normalize_imported_filter_payload.
|
||||
# @RELATION BINDS_TO -> [SupersetContextRecoveryMixin]
|
||||
# @RELATION BINDS_TO -> [Core.Recovery.SupersetContextRecoveryMixin]
|
||||
# @TEST_CONTRACT: [SupersetParsedContext] -> [List[Dict]]
|
||||
# @TEST_SCENARIO: dashboard_with_native_filters -> recovers from json_metadata
|
||||
# @TEST_SCENARIO: no_dashboard_id -> URL filters only
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.SupersetContextTemplates [C:3] [TYPE Module] [SEMANTICS test, superset, template, variables, jinja]
|
||||
# @BRIEF Tests for _templates.py — SupersetContextTemplatesMixin pure helpers.
|
||||
# @RELATION BINDS_TO -> [SupersetContextTemplatesMixin]
|
||||
# @RELATION BINDS_TO -> [Core.Templates.SupersetContextTemplatesMixin]
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
@@ -332,3 +332,4 @@ class TestDiscoverTemplateVariables:
|
||||
})
|
||||
country_vars = [v for v in result if v["variable_name"] == "country"]
|
||||
assert len(country_vars) == 1
|
||||
# #endregion Test.SupersetContextTemplates
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.SupersetContextTemplatesExtra [C:2] [TYPE Module] [SEMANTICS test, superset, template, edge]
|
||||
# @BRIEF Extra tests for _templates.py — edge cases covering lines 45, 62, 80, 92, 148.
|
||||
# @RELATION BINDS_TO -> [SupersetContextTemplatesMixin]
|
||||
# @RELATION BINDS_TO -> [Core.Templates.SupersetContextTemplatesMixin]
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# #region Test.Superset.Extended [C:3] [TYPE Module] [SEMANTICS test,superset,sql-lab,dashboard,dataset,database,saved-query]
|
||||
# @BRIEF Unit tests for SupersetClient extended mixins: SQL Lab, dashboards write, datasets, databases, saved queries, audit.
|
||||
# @RELATION BINDS_TO -> [SupersetSqlLabMixin]
|
||||
# @RELATION BINDS_TO -> [SupersetDashboardsWriteMixin]
|
||||
# @RELATION BINDS_TO -> [SupersetDatasetsMixin]
|
||||
# @RELATION BINDS_TO -> [SupersetDatabasesMixin]
|
||||
# @RELATION BINDS_TO -> [SupersetSavedQueriesMixin]
|
||||
# @RELATION BINDS_TO -> [SupersetAuditMixin]
|
||||
# @RELATION BINDS_TO -> [Core.SqlLab.SupersetSqlLabMixin]
|
||||
# @RELATION BINDS_TO -> [Core.DashboardsWrite.SupersetDashboardsWriteMixin]
|
||||
# @RELATION BINDS_TO -> [Core.Datasets.SupersetDatasetsMixin]
|
||||
# @RELATION BINDS_TO -> [Core.Databases.SupersetDatabasesMixin]
|
||||
# @RELATION BINDS_TO -> [Core.SavedQueries.SupersetSavedQueriesMixin]
|
||||
# @RELATION BINDS_TO -> [Core.Audit.SupersetAuditMixin]
|
||||
# @TEST_EDGE: ddl_guard -> execute_sql blocks dangerous SQL via safety.py
|
||||
# @TEST_EDGE: external_fail -> Exception in API call is raised
|
||||
# @TEST_EDGE: missing_field -> Optional parameters omitted from payloads
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.SupersetProfileLookup [C:3] [TYPE Module] [SEMANTICS test, superset, profile, lookup, adapter]
|
||||
# @BRIEF Tests for core/superset_profile_lookup.py — SupersetAccountLookupAdapter.
|
||||
# @RELATION BINDS_TO -> [SupersetProfileLookup]
|
||||
# @RELATION BINDS_TO -> [Core.SupersetProfileLookup]
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.Superset.UserProjection [C:3] [TYPE Module] [SEMANTICS test,superset,user,projection]
|
||||
# @BRIEF Tests for core/superset_client/_user_projection.py — SupersetUserProjectionMixin.
|
||||
# @RELATION BINDS_TO -> [SupersetUserProjection]
|
||||
# @RELATION BINDS_TO -> [Core.UserProjection.SupersetUserProjection]
|
||||
# @TEST_EDGE: owners_payload_none -> []
|
||||
# @TEST_EDGE: owner_single_dict_wrapped -> normalize as list
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.TaskCleanupService [C:3] [TYPE Module] [SEMANTICS test,task,cleanup,retention]
|
||||
# @BRIEF Tests for core/task_manager/cleanup.py — TaskCleanupService.
|
||||
# @RELATION BINDS_TO -> [TaskCleanupModule]
|
||||
# @RELATION BINDS_TO -> [Core.Cleanup.TaskCleanupModule]
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
@@ -11,7 +11,7 @@ from unittest.mock import MagicMock, patch
|
||||
import pytest
|
||||
|
||||
|
||||
# #region test_task_cleanup_service [C:2] [TYPE Function]
|
||||
# #region Test.TaskCleanupService.TestTaskCleanupService [C:2] [TYPE Function]
|
||||
# @BRIEF Test TaskCleanupService.run_cleanup and delete_task_with_logs.
|
||||
class TestTaskCleanupService:
|
||||
@pytest.fixture
|
||||
@@ -79,5 +79,5 @@ class TestTaskCleanupService:
|
||||
mock_persistence.delete_tasks.assert_called_once()
|
||||
deleted_ids = mock_persistence.delete_tasks.call_args[0][0]
|
||||
assert len(deleted_ids) == 1
|
||||
# #endregion test_task_cleanup_service
|
||||
# #endregion Test.TaskCleanupService.TestTaskCleanupService
|
||||
# #endregion Test.TaskCleanupService
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.TaskContext [C:3] [TYPE Module] [SEMANTICS test,task,context]
|
||||
# @BRIEF Tests for core/task_manager/context.py — TaskContext class.
|
||||
# @RELATION BINDS_TO -> [TaskContextModule]
|
||||
# @RELATION BINDS_TO -> [Core.Context.TaskContextModule]
|
||||
# @TEST_EDGE: get_param_default -> returns default when key missing
|
||||
# @TEST_EDGE: create_sub_context_preserves_params
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.TaskLogger [C:3] [TYPE Module] [SEMANTICS test,task,logger]
|
||||
# @BRIEF Tests for core/task_manager/task_logger.py — TaskLogger class.
|
||||
# @RELATION BINDS_TO -> [TaskLoggerModule]
|
||||
# @RELATION BINDS_TO -> [Core.TaskLogger.TaskLoggerModule]
|
||||
# @TEST_EDGE: no_event_loop -> _log drops gracefully
|
||||
# @TEST_EDGE: with_source_creates_independent_logger
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.AppTimezone [C:3] [TYPE Module] [SEMANTICS test,timezone,datetime,utilities]
|
||||
# @BRIEF Tests for core/timezone.py — all timezone utility functions.
|
||||
# @RELATION BINDS_TO -> [AppTimezone]
|
||||
# @RELATION BINDS_TO -> [Core.Timezone.AppTimezone]
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
@@ -14,7 +14,7 @@ import pytest
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
|
||||
# #region test_get_default_tz_name [C:2] [TYPE Function]
|
||||
# #region Test.AppTimezone.TestGetDefaultTzName [C:2] [TYPE Function]
|
||||
# @BRIEF Test _get_default_tz_name reads env var or default.
|
||||
class TestGetDefaultTzName:
|
||||
def test_returns_env_value(self):
|
||||
@@ -31,10 +31,10 @@ class TestGetDefaultTzName:
|
||||
# Let's test directly
|
||||
with patch("src.core.timezone.os.getenv", return_value="Europe/Moscow"):
|
||||
assert _get_default_tz_name() == "Europe/Moscow"
|
||||
# #endregion test_get_default_tz_name
|
||||
# #endregion Test.AppTimezone.TestGetDefaultTzName
|
||||
|
||||
|
||||
# #region test_get_app_timezone [C:2] [TYPE Function]
|
||||
# #region Test.AppTimezone.TestGetAppTimezone [C:2] [TYPE Function]
|
||||
# @BRIEF Test get_app_timezone returns cached ZoneInfo.
|
||||
class TestGetAppTimezone:
|
||||
def test_returns_zoneinfo(self):
|
||||
@@ -49,10 +49,10 @@ class TestGetAppTimezone:
|
||||
tz1 = get_app_timezone()
|
||||
tz2 = get_app_timezone()
|
||||
assert tz1 is tz2 # Same cached object
|
||||
# #endregion test_get_app_timezone
|
||||
# #endregion Test.AppTimezone.TestGetAppTimezone
|
||||
|
||||
|
||||
# #region test_invalidate_timezone_cache [C:2] [TYPE Function]
|
||||
# #region Test.AppTimezone.TestInvalidateTimezoneCache [C:2] [TYPE Function]
|
||||
# @BRIEF Test invalidate_timezone_cache resets the cache.
|
||||
class TestInvalidateTimezoneCache:
|
||||
def test_invalidates_cache(self):
|
||||
@@ -65,10 +65,10 @@ class TestInvalidateTimezoneCache:
|
||||
tz_mod.invalidate_timezone_cache()
|
||||
assert tz_mod._APP_TZ_CACHE is None # Cache cleared again
|
||||
tz_mod._APP_TZ_CACHE = None # Reset for other tests
|
||||
# #endregion test_invalidate_timezone_cache
|
||||
# #endregion Test.AppTimezone.TestInvalidateTimezoneCache
|
||||
|
||||
|
||||
# #region test_validate_timezone [C:2] [TYPE Function]
|
||||
# #region Test.AppTimezone.TestValidateTimezone [C:2] [TYPE Function]
|
||||
# @BRIEF Test validate_timezone for valid/invalid IANA names.
|
||||
class TestValidateTimezone:
|
||||
def test_valid_timezone(self):
|
||||
@@ -85,10 +85,10 @@ class TestValidateTimezone:
|
||||
from src.core.timezone import validate_timezone
|
||||
# This should return False when TypeError is caught
|
||||
assert validate_timezone(None) is False # type: ignore
|
||||
# #endregion test_validate_timezone
|
||||
# #endregion Test.AppTimezone.TestValidateTimezone
|
||||
|
||||
|
||||
# #region test_localize [C:2] [TYPE Function]
|
||||
# #region Test.AppTimezone.TestLocalize [C:2] [TYPE Function]
|
||||
# @BRIEF Test localize converts UTC to app timezone.
|
||||
class TestLocalize:
|
||||
def test_none_returns_none(self):
|
||||
@@ -126,10 +126,10 @@ class TestLocalize:
|
||||
# Should convert to Moscow time
|
||||
assert result.tzinfo is not None
|
||||
assert "Europe/Moscow" in str(result.tzinfo) or "+03" in result.isoformat()
|
||||
# #endregion test_localize
|
||||
# #endregion Test.AppTimezone.TestLocalize
|
||||
|
||||
|
||||
# #region test_now [C:2] [TYPE Function]
|
||||
# #region Test.AppTimezone.TestNow [C:2] [TYPE Function]
|
||||
# @BRIEF Test now returns timezone-aware datetime.
|
||||
class TestNow:
|
||||
def test_returns_aware_datetime(self):
|
||||
@@ -144,10 +144,10 @@ class TestNow:
|
||||
offset = result.utcoffset()
|
||||
assert offset is not None
|
||||
assert offset.total_seconds() == 3 * 3600 # Europe/Moscow
|
||||
# #endregion test_now
|
||||
# #endregion Test.AppTimezone.TestNow
|
||||
|
||||
|
||||
# #region test_format_timezone_offset [C:2] [TYPE Function]
|
||||
# #region Test.AppTimezone.TestFormatTimezoneOffset [C:2] [TYPE Function]
|
||||
# @BRIEF Test format_timezone_offset returns formatted offset string.
|
||||
class TestFormatTimezoneOffset:
|
||||
def test_returns_formatted_offset(self):
|
||||
@@ -162,5 +162,5 @@ class TestFormatTimezoneOffset:
|
||||
invalidate_timezone_cache()
|
||||
result = format_timezone_offset()
|
||||
assert result == "+03:00"
|
||||
# #endregion test_format_timezone_offset
|
||||
# #endregion Test.AppTimezone.TestFormatTimezoneOffset
|
||||
# #endregion Test.AppTimezone
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #region Test.TraceContextMiddleware [C:3] [TYPE Module] [SEMANTICS test,middleware,trace,asgi]
|
||||
# @BRIEF Tests for core/middleware/trace.py — TraceContextMiddleware ASGI middleware.
|
||||
# @RELATION BINDS_TO -> [TraceContextMiddlewareModule]
|
||||
# @RELATION BINDS_TO -> [Core.Trace.TraceContextMiddlewareModule]
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
@@ -11,7 +11,7 @@ import pytest
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
|
||||
# #region test_trace_middleware [C:2] [TYPE Function]
|
||||
# #region Test.TraceContextMiddleware.TestTraceMiddleware [C:2] [TYPE Function]
|
||||
# @BRIEF Test TraceContextMiddleware for various ASGI scenarios.
|
||||
class TestTraceContextMiddleware:
|
||||
@pytest.fixture
|
||||
@@ -105,11 +105,11 @@ class TestTraceContextMiddleware:
|
||||
assert call_args[0][1] == receive
|
||||
# call_args[0][2] is send_with_trace — a wrapper function, not the original send
|
||||
assert callable(call_args[0][2])
|
||||
# #endregion test_trace_middleware
|
||||
# #endregion Test.TraceContextMiddleware.TestTraceMiddleware
|
||||
|
||||
|
||||
|
||||
# #region TestTraceResponseHeaders [C:2] [TYPE Class] [SEMANTICS test,middleware,trace,header]
|
||||
# #region Test.TraceContextMiddleware.TestTraceResponseHeaders [C:2] [TYPE Class] [SEMANTICS test,middleware,trace,header]
|
||||
# @BRIEF Verify X-Trace-Id response header injection — new, preserved, passthrough.
|
||||
class TestTraceResponseHeaders:
|
||||
"""TraceContextMiddleware response header injection."""
|
||||
@@ -123,7 +123,7 @@ class TestTraceResponseHeaders:
|
||||
from src.core.middleware.trace import TraceContextMiddleware
|
||||
return TraceContextMiddleware(mock_app)
|
||||
|
||||
# #region test_sets_x_trace_id_header_on_response [C:2] [TYPE Function] [SEMANTICS test,trace,header]
|
||||
# #region Test.TraceContextMiddleware.TestSetsXTraceIdHeaderOnResponse [C:2] [TYPE Function] [SEMANTICS test,trace,header]
|
||||
# @BRIEF HTTP response receives x-trace-id header with a valid UUID4 value.
|
||||
@pytest.mark.asyncio
|
||||
async def test_sets_x_trace_id_header_on_response(self, middleware, mock_app):
|
||||
@@ -164,9 +164,9 @@ class TestTraceResponseHeaders:
|
||||
# Valid UUID4
|
||||
parsed = uuid.UUID(hex=trace_id)
|
||||
assert parsed.version == 4, f"Trace ID is not UUID4: got version {parsed.version}"
|
||||
# #endregion test_sets_x_trace_id_header_on_response
|
||||
# #endregion Test.TraceContextMiddleware.TestSetsXTraceIdHeaderOnResponse
|
||||
|
||||
# #region test_preserves_incoming_trace_id [C:2] [TYPE Function] [SEMANTICS test,trace,header,preserve]
|
||||
# #region Test.TraceContextMiddleware.TestPreservesIncomingTraceId [C:2] [TYPE Function] [SEMANTICS test,trace,header,preserve]
|
||||
# @BRIEF When request carries X-Trace-ID, the response header uses the same value.
|
||||
@pytest.mark.asyncio
|
||||
async def test_preserves_incoming_trace_id(self, middleware, mock_app):
|
||||
@@ -207,9 +207,9 @@ class TestTraceResponseHeaders:
|
||||
assert response_trace_id == incoming_id, (
|
||||
f"Response trace ID {response_trace_id} != incoming {incoming_id}"
|
||||
)
|
||||
# #endregion test_preserves_incoming_trace_id
|
||||
# #endregion Test.TraceContextMiddleware.TestPreservesIncomingTraceId
|
||||
|
||||
# #region test_non_http_scope_passthrough [C:2] [TYPE Function] [SEMANTICS test,trace,websocket,passthrough]
|
||||
# #region Test.TraceContextMiddleware.TestNonHttpScopePassthrough [C:2] [TYPE Function] [SEMANTICS test,trace,websocket,passthrough]
|
||||
# @BRIEF Non-HTTP scopes (websocket, lifespan) do not inject X-Trace-Id header.
|
||||
@pytest.mark.asyncio
|
||||
async def test_non_http_scope_passthrough(self, middleware, mock_app):
|
||||
@@ -241,7 +241,7 @@ class TestTraceResponseHeaders:
|
||||
|
||||
# The middleware returns early for non-http, calling self.app directly
|
||||
mock_app.assert_called_once_with(scope, receive, send)
|
||||
# #endregion test_non_http_scope_passthrough
|
||||
# #endregion Test.TraceContextMiddleware.TestNonHttpScopePassthrough
|
||||
|
||||
# #endregion TestTraceResponseHeaders
|
||||
# #endregion Test.TraceContextMiddleware.TestTraceResponseHeaders
|
||||
# #endregion Test.TraceContextMiddleware
|
||||
|
||||
@@ -10,7 +10,7 @@ from unittest.mock import MagicMock, patch
|
||||
import pytest
|
||||
|
||||
|
||||
# #region test_websocket_log_handler [C:2]
|
||||
# #region Test.WsLogHandler.TestWebsocketLogHandler [C:2]
|
||||
class TestWebSocketLogHandler:
|
||||
@pytest.fixture
|
||||
def handler(self):
|
||||
@@ -71,5 +71,5 @@ class TestWebSocketLogHandler:
|
||||
|
||||
h = WebSocketLogHandler()
|
||||
assert h.log_buffer.maxlen == 3000
|
||||
# #endregion test_websocket_log_handler
|
||||
# #endregion Test.WsLogHandler.TestWebsocketLogHandler
|
||||
# #endregion Test.WsLogHandler
|
||||
|
||||
Reference in New Issue
Block a user