|
|
|
|
@@ -1,8 +1,11 @@
|
|
|
|
|
# #region TestDatasetsApi [C:2] [TYPE Module]
|
|
|
|
|
# @RELATION DEPENDS_ON -> [DatasetsApi]
|
|
|
|
|
# @SEMANTICS: tests, datasets, api, metrics, inline-edit
|
|
|
|
|
# @PURPOSE: Contract tests for dataset endpoints (list+stats, detail+metrics, inline-edit descriptions).
|
|
|
|
|
# @LAYER Tests
|
|
|
|
|
# #region Test.DatasetsApi [C:3] [TYPE Module] [SEMANTICS test, datasets, api, metrics, inline-edit]
|
|
|
|
|
# @BRIEF Contract tests for dataset endpoints — list+stats, detail+metrics, inline-edit descriptions, map-columns, generate-docs.
|
|
|
|
|
# @RELATION BINDS_TO -> [DatasetsApi]
|
|
|
|
|
# @TEST_EDGE: missing_env -> 404 when env not found
|
|
|
|
|
# @TEST_EDGE: invalid_page -> 400 when page < 1 or page_size > 100
|
|
|
|
|
# @TEST_EDGE: external_superset_fail -> 503 when Superset/API fails
|
|
|
|
|
# @TEST_EDGE: html_injection -> HTML tags stripped from descriptions
|
|
|
|
|
# @TEST_EDGE: oversized_description -> 400 when description exceeds 2000 chars
|
|
|
|
|
import pytest
|
|
|
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
|
|
|
|
|
|
|
|
@@ -20,7 +23,7 @@ from src.dependencies import (
|
|
|
|
|
client = TestClient(app)
|
|
|
|
|
|
|
|
|
|
# #region mock_user [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Create a mock user with Admin role and all permissions for testing.
|
|
|
|
|
# @BRIEF Create a mock user with Admin role and all permissions for testing.
|
|
|
|
|
def _make_mock_user():
|
|
|
|
|
admin_role = MagicMock()
|
|
|
|
|
admin_role.name = "Admin"
|
|
|
|
|
@@ -33,7 +36,7 @@ def _make_mock_user():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region mock_deps [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Provide dependency override fixture for dataset route tests.
|
|
|
|
|
# @BRIEF Provide dependency override fixture for dataset route tests.
|
|
|
|
|
# @TEST_FIXTURE: dataset_route_overrides -> INLINE_JSON
|
|
|
|
|
@pytest.fixture
|
|
|
|
|
def mock_deps():
|
|
|
|
|
@@ -98,7 +101,7 @@ def mock_deps():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_get_datasets_returns_stats [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify GET /api/datasets returns stats object with correct counts.
|
|
|
|
|
# @BRIEF Verify GET /api/datasets returns stats object with correct counts.
|
|
|
|
|
# @TEST_CONTRACT: datasets_list -> datasets with stats payload
|
|
|
|
|
# @TEST_SCENARIO: datasets_with_stats -> HTTP 200 returns datasets, stats, and pagination.
|
|
|
|
|
# @TEST_INVARIANT: stats_counts_correct -> VERIFIED_BY: [datasets_with_stats]
|
|
|
|
|
@@ -120,7 +123,7 @@ def test_get_datasets_returns_stats(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_get_datasets_filter_unmapped [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify server-side filtering by unmapped datasets.
|
|
|
|
|
# @BRIEF Verify server-side filtering by unmapped datasets.
|
|
|
|
|
# @TEST_SCENARIO: filter_unmapped -> Only returns datasets with mapped=0.
|
|
|
|
|
def test_get_datasets_filter_unmapped(mock_deps):
|
|
|
|
|
response = client.get(
|
|
|
|
|
@@ -137,7 +140,7 @@ def test_get_datasets_filter_unmapped(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_get_datasets_filter_mapped [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify server-side filtering by mapped datasets.
|
|
|
|
|
# @BRIEF Verify server-side filtering by mapped datasets.
|
|
|
|
|
def test_get_datasets_filter_mapped(mock_deps):
|
|
|
|
|
response = client.get(
|
|
|
|
|
"/api/datasets?env_id=ss-dev&filter=mapped&page=1&page_size=10"
|
|
|
|
|
@@ -150,7 +153,7 @@ def test_get_datasets_filter_mapped(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_get_datasets_filter_linked [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify server-side filtering by datasets linked to dashboards.
|
|
|
|
|
# @BRIEF Verify server-side filtering by datasets linked to dashboards.
|
|
|
|
|
def test_get_datasets_filter_linked(mock_deps):
|
|
|
|
|
response = client.get(
|
|
|
|
|
"/api/datasets?env_id=ss-dev&filter=linked&page=1&page_size=10"
|
|
|
|
|
@@ -163,7 +166,7 @@ def test_get_datasets_filter_linked(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_get_datasets_filter_all [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify filter=all returns all datasets (same as no filter).
|
|
|
|
|
# @BRIEF Verify filter=all returns all datasets (same as no filter).
|
|
|
|
|
def test_get_datasets_filter_all(mock_deps):
|
|
|
|
|
response = client.get(
|
|
|
|
|
"/api/datasets?env_id=ss-dev&filter=all&page=1&page_size=10"
|
|
|
|
|
@@ -174,7 +177,7 @@ def test_get_datasets_filter_all(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_get_dataset_detail_returns_metrics [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify GET /api/datasets/{id} returns metrics and metric_count.
|
|
|
|
|
# @BRIEF Verify GET /api/datasets/{id} returns metrics and metric_count.
|
|
|
|
|
# @TEST_SCENARIO: detail_with_metrics -> Response includes metrics list and metric_count.
|
|
|
|
|
def test_get_dataset_detail_returns_metrics(mock_deps):
|
|
|
|
|
with patch("src.api.routes.datasets.AsyncSupersetClient") as MockClient:
|
|
|
|
|
@@ -218,7 +221,7 @@ def test_get_dataset_detail_returns_metrics(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_column_description [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify PUT /api/datasets/{id}/columns/{col_id}/description saves description.
|
|
|
|
|
# @BRIEF Verify PUT /api/datasets/{id}/columns/{col_id}/description saves description.
|
|
|
|
|
# @TEST_SCENARIO: save_column_desc -> Saves and returns updated description.
|
|
|
|
|
def test_update_column_description(mock_deps):
|
|
|
|
|
with patch("src.api.routes.datasets.AsyncSupersetClient") as MockClient:
|
|
|
|
|
@@ -255,7 +258,7 @@ def test_update_column_description(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_metric_description [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify PUT /api/datasets/{id}/metrics/{metric_id}/description saves correctly.
|
|
|
|
|
# @BRIEF Verify PUT /api/datasets/{id}/metrics/{metric_id}/description saves correctly.
|
|
|
|
|
# @TEST_SCENARIO: save_metric_desc -> Saves and returns updated description.
|
|
|
|
|
def test_update_metric_description(mock_deps):
|
|
|
|
|
with patch("src.api.routes.datasets.AsyncSupersetClient") as MockClient:
|
|
|
|
|
@@ -285,7 +288,7 @@ def test_update_metric_description(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_column_description_not_found [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 404 when column not found.
|
|
|
|
|
# @BRIEF Verify 404 when column not found.
|
|
|
|
|
def test_update_column_description_not_found(mock_deps):
|
|
|
|
|
with patch("src.api.routes.datasets.AsyncSupersetClient") as MockClient:
|
|
|
|
|
mock_client = AsyncMock()
|
|
|
|
|
@@ -308,7 +311,7 @@ def test_update_column_description_not_found(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_column_description_validation [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 400 when description exceeds max length.
|
|
|
|
|
# @BRIEF Verify 400 when description exceeds max length.
|
|
|
|
|
def test_update_column_description_validation(mock_deps):
|
|
|
|
|
response = client.put(
|
|
|
|
|
"/api/datasets/1/columns/10/description?env_id=ss-dev",
|
|
|
|
|
@@ -318,7 +321,7 @@ def test_update_column_description_validation(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_get_datasets_superset_503 [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify GET /api/datasets returns 503 when Superset/ResourceService throws.
|
|
|
|
|
# @BRIEF Verify GET /api/datasets returns 503 when Superset/ResourceService throws.
|
|
|
|
|
# @TEST_SCENARIO: upstream_superset_failure -> 503 with error detail.
|
|
|
|
|
# @TEST_INVARIANT: upstream_failure_503 -> VERIFIED_BY: [superset_failure]
|
|
|
|
|
def test_get_datasets_superset_503(mock_deps):
|
|
|
|
|
@@ -343,7 +346,7 @@ def test_get_datasets_superset_503(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_column_description_superset_502 [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify PUT column description returns 502 when SupersetClient.update_dataset throws.
|
|
|
|
|
# @BRIEF Verify PUT column description returns 502 when SupersetClient.update_dataset throws.
|
|
|
|
|
# @TEST_SCENARIO: superset_put_failure -> 502 with error detail.
|
|
|
|
|
def test_update_column_description_superset_502(mock_deps):
|
|
|
|
|
with patch("src.api.routes.datasets.AsyncSupersetClient") as MockClient:
|
|
|
|
|
@@ -372,7 +375,7 @@ def test_update_column_description_superset_502(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_column_description_strips_html [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify HTML tags are stripped from description before saving.
|
|
|
|
|
# @BRIEF Verify HTML tags are stripped from description before saving.
|
|
|
|
|
# @TEST_SCENARIO: html_in_description -> HTML tags stripped, clean text saved.
|
|
|
|
|
def test_update_column_description_strips_html(mock_deps):
|
|
|
|
|
with patch("src.api.routes.datasets.AsyncSupersetClient") as MockClient:
|
|
|
|
|
@@ -407,7 +410,7 @@ def test_update_column_description_strips_html(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_dataset_item_has_metric_count [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify DatasetItem in list response includes metric_count field.
|
|
|
|
|
# @BRIEF Verify DatasetItem in list response includes metric_count field.
|
|
|
|
|
def test_dataset_item_has_metric_count(mock_deps):
|
|
|
|
|
response = client.get(
|
|
|
|
|
"/api/datasets?env_id=ss-dev&page=1&page_size=10"
|
|
|
|
|
@@ -420,7 +423,7 @@ def test_dataset_item_has_metric_count(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_get_dataset_ids [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify GET /api/datasets/ids returns list of dataset IDs.
|
|
|
|
|
# @BRIEF Verify GET /api/datasets/ids returns list of dataset IDs.
|
|
|
|
|
def test_get_dataset_ids(mock_deps):
|
|
|
|
|
response = client.get("/api/datasets/ids?env_id=ss-dev")
|
|
|
|
|
assert response.status_code == 200
|
|
|
|
|
@@ -432,7 +435,7 @@ def test_get_dataset_ids(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_get_dataset_ids_search [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify GET /api/datasets/ids with search filter.
|
|
|
|
|
# @BRIEF Verify GET /api/datasets/ids with search filter.
|
|
|
|
|
def test_get_dataset_ids_search(mock_deps):
|
|
|
|
|
response = client.get("/api/datasets/ids?env_id=ss-dev&search=users")
|
|
|
|
|
assert response.status_code == 200
|
|
|
|
|
@@ -441,14 +444,14 @@ def test_get_dataset_ids_search(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_get_dataset_ids_env_not_found [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 404 when env not found.
|
|
|
|
|
# @BRIEF Verify 404 when env not found.
|
|
|
|
|
def test_get_dataset_ids_env_not_found(mock_deps):
|
|
|
|
|
response = client.get("/api/datasets/ids?env_id=nonexistent")
|
|
|
|
|
assert response.status_code == 404
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_get_dataset_ids_503 [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 503 when Superset fails.
|
|
|
|
|
# @BRIEF Verify 503 when Superset fails.
|
|
|
|
|
def test_get_dataset_ids_503(mock_deps):
|
|
|
|
|
from src.dependencies import get_resource_service
|
|
|
|
|
failing = MagicMock()
|
|
|
|
|
@@ -464,28 +467,28 @@ def test_get_dataset_ids_503(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_get_datasets_invalid_page [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 400 when page < 1.
|
|
|
|
|
# @BRIEF Verify 400 when page < 1.
|
|
|
|
|
def test_get_datasets_invalid_page(mock_deps):
|
|
|
|
|
response = client.get("/api/datasets?env_id=ss-dev&page=0")
|
|
|
|
|
assert response.status_code == 400
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_get_datasets_invalid_page_size [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 400 when page_size > 100.
|
|
|
|
|
# @BRIEF Verify 400 when page_size > 100.
|
|
|
|
|
def test_get_datasets_invalid_page_size(mock_deps):
|
|
|
|
|
response = client.get("/api/datasets?env_id=ss-dev&page_size=200")
|
|
|
|
|
assert response.status_code == 400
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_get_datasets_env_not_found [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 404 when environment not found.
|
|
|
|
|
# @BRIEF Verify 404 when environment not found.
|
|
|
|
|
def test_get_datasets_env_not_found(mock_deps):
|
|
|
|
|
response = client.get("/api/datasets?env_id=nonexistent&page=1&page_size=10")
|
|
|
|
|
assert response.status_code == 404
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_get_datasets_search_filter [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify search filter narrows results.
|
|
|
|
|
# @BRIEF Verify search filter narrows results.
|
|
|
|
|
def test_get_datasets_search_filter(mock_deps):
|
|
|
|
|
response = client.get("/api/datasets?env_id=ss-dev&search=users&page=1&page_size=10")
|
|
|
|
|
assert response.status_code == 200
|
|
|
|
|
@@ -495,7 +498,7 @@ def test_get_datasets_search_filter(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_get_datasets_pagination [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify pagination works.
|
|
|
|
|
# @BRIEF Verify pagination works.
|
|
|
|
|
def test_get_datasets_pagination(mock_deps):
|
|
|
|
|
response = client.get("/api/datasets?env_id=ss-dev&page=1&page_size=2")
|
|
|
|
|
assert response.status_code == 200
|
|
|
|
|
@@ -505,7 +508,7 @@ def test_get_datasets_pagination(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_map_columns [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify POST /api/datasets/map-columns creates mapping task.
|
|
|
|
|
# @BRIEF Verify POST /api/datasets/map-columns creates mapping task.
|
|
|
|
|
def test_map_columns(mock_deps):
|
|
|
|
|
from src.dependencies import get_task_manager
|
|
|
|
|
task_manager_mock = MagicMock()
|
|
|
|
|
@@ -542,7 +545,7 @@ def test_map_columns(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_map_columns_no_dataset_ids [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 400 when no dataset IDs provided.
|
|
|
|
|
# @BRIEF Verify 400 when no dataset IDs provided.
|
|
|
|
|
def test_map_columns_no_dataset_ids(mock_deps):
|
|
|
|
|
from src.dependencies import has_permission
|
|
|
|
|
app.dependency_overrides[has_permission("plugin:mapper", "EXECUTE")] = lambda: True
|
|
|
|
|
@@ -558,7 +561,7 @@ def test_map_columns_no_dataset_ids(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_map_columns_invalid_source_type [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 400 when invalid source type.
|
|
|
|
|
# @BRIEF Verify 400 when invalid source type.
|
|
|
|
|
def test_map_columns_invalid_source_type(mock_deps):
|
|
|
|
|
from src.dependencies import has_permission
|
|
|
|
|
app.dependency_overrides[has_permission("plugin:mapper", "EXECUTE")] = lambda: True
|
|
|
|
|
@@ -574,7 +577,7 @@ def test_map_columns_invalid_source_type(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_map_columns_missing_database_id [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 400 when sqllab source without database_id.
|
|
|
|
|
# @BRIEF Verify 400 when sqllab source without database_id.
|
|
|
|
|
def test_map_columns_missing_database_id(mock_deps):
|
|
|
|
|
from src.dependencies import has_permission
|
|
|
|
|
app.dependency_overrides[has_permission("plugin:mapper", "EXECUTE")] = lambda: True
|
|
|
|
|
@@ -590,7 +593,7 @@ def test_map_columns_missing_database_id(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_map_columns_env_not_found [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 404 when environment not found.
|
|
|
|
|
# @BRIEF Verify 404 when environment not found.
|
|
|
|
|
def test_map_columns_env_not_found(mock_deps):
|
|
|
|
|
from src.dependencies import has_permission
|
|
|
|
|
app.dependency_overrides[has_permission("plugin:mapper", "EXECUTE")] = lambda: True
|
|
|
|
|
@@ -611,7 +614,7 @@ def test_map_columns_env_not_found(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_map_columns_xlsx_source [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify xlsx source type works.
|
|
|
|
|
# @BRIEF Verify xlsx source type works.
|
|
|
|
|
def test_map_columns_xlsx_source(mock_deps):
|
|
|
|
|
from src.dependencies import get_task_manager, has_permission
|
|
|
|
|
task_manager_mock = MagicMock()
|
|
|
|
|
@@ -640,7 +643,7 @@ def test_map_columns_xlsx_source(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_map_columns_503 [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 503 when task creation fails.
|
|
|
|
|
# @BRIEF Verify 503 when task creation fails.
|
|
|
|
|
def test_map_columns_503(mock_deps):
|
|
|
|
|
from src.dependencies import get_task_manager, has_permission
|
|
|
|
|
task_manager_mock = MagicMock()
|
|
|
|
|
@@ -666,7 +669,7 @@ def test_map_columns_503(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_generate_docs [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify POST /api/datasets/generate-docs creates doc generation task.
|
|
|
|
|
# @BRIEF Verify POST /api/datasets/generate-docs creates doc generation task.
|
|
|
|
|
def test_generate_docs(mock_deps):
|
|
|
|
|
from src.dependencies import get_task_manager, has_permission
|
|
|
|
|
task_manager_mock = MagicMock()
|
|
|
|
|
@@ -695,7 +698,7 @@ def test_generate_docs(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_generate_docs_no_dataset_ids [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 400 when no dataset IDs provided.
|
|
|
|
|
# @BRIEF Verify 400 when no dataset IDs provided.
|
|
|
|
|
def test_generate_docs_no_dataset_ids(mock_deps):
|
|
|
|
|
from src.dependencies import has_permission
|
|
|
|
|
app.dependency_overrides[has_permission("plugin:llm_analysis", "EXECUTE")] = lambda: True
|
|
|
|
|
@@ -711,7 +714,7 @@ def test_generate_docs_no_dataset_ids(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_generate_docs_env_not_found [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 404 when environment not found.
|
|
|
|
|
# @BRIEF Verify 404 when environment not found.
|
|
|
|
|
def test_generate_docs_env_not_found(mock_deps):
|
|
|
|
|
from src.dependencies import has_permission
|
|
|
|
|
app.dependency_overrides[has_permission("plugin:llm_analysis", "EXECUTE")] = lambda: True
|
|
|
|
|
@@ -727,7 +730,7 @@ def test_generate_docs_env_not_found(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_generate_docs_503 [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 503 when task creation fails.
|
|
|
|
|
# @BRIEF Verify 503 when task creation fails.
|
|
|
|
|
def test_generate_docs_503(mock_deps):
|
|
|
|
|
from src.dependencies import get_task_manager, has_permission
|
|
|
|
|
task_manager_mock = MagicMock()
|
|
|
|
|
@@ -748,7 +751,7 @@ def test_generate_docs_503(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_metric_description_not_found [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 404 when metric not found.
|
|
|
|
|
# @BRIEF Verify 404 when metric not found.
|
|
|
|
|
def test_update_metric_description_not_found(mock_deps):
|
|
|
|
|
with patch("src.api.routes.datasets.AsyncSupersetClient") as MockClient:
|
|
|
|
|
mock_client = AsyncMock()
|
|
|
|
|
@@ -771,7 +774,7 @@ def test_update_metric_description_not_found(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_metric_description_validation [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 400 when description exceeds max length for metric.
|
|
|
|
|
# @BRIEF Verify 400 when description exceeds max length for metric.
|
|
|
|
|
def test_update_metric_description_validation(mock_deps):
|
|
|
|
|
response = client.put(
|
|
|
|
|
"/api/datasets/1/metrics/100/description?env_id=ss-dev",
|
|
|
|
|
@@ -781,7 +784,7 @@ def test_update_metric_description_validation(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_metric_description_superset_502_get [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 502 when Superset GET fails for metric.
|
|
|
|
|
# @BRIEF Verify 502 when Superset GET fails for metric.
|
|
|
|
|
def test_update_metric_description_superset_502_get(mock_deps):
|
|
|
|
|
with patch("src.api.routes.datasets.AsyncSupersetClient") as MockClient:
|
|
|
|
|
mock_client = AsyncMock()
|
|
|
|
|
@@ -796,7 +799,7 @@ def test_update_metric_description_superset_502_get(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_metric_description_superset_502_put [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 502 when Superset PUT fails for metric.
|
|
|
|
|
# @BRIEF Verify 502 when Superset PUT fails for metric.
|
|
|
|
|
def test_update_metric_description_superset_502_put(mock_deps):
|
|
|
|
|
with patch("src.api.routes.datasets.AsyncSupersetClient") as MockClient:
|
|
|
|
|
mock_client = AsyncMock()
|
|
|
|
|
@@ -819,7 +822,7 @@ def test_update_metric_description_superset_502_put(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_column_description_env_not_found [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 404 when environment not found in update_column_description.
|
|
|
|
|
# @BRIEF Verify 404 when environment not found in update_column_description.
|
|
|
|
|
def test_update_column_description_env_not_found(mock_deps):
|
|
|
|
|
response = client.put(
|
|
|
|
|
"/api/datasets/1/columns/10/description?env_id=nonexistent",
|
|
|
|
|
@@ -829,7 +832,7 @@ def test_update_column_description_env_not_found(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_column_description_get_fails [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 502 when Superset GET fails in update_column_description.
|
|
|
|
|
# @BRIEF Verify 502 when Superset GET fails in update_column_description.
|
|
|
|
|
def test_update_column_description_get_fails(mock_deps):
|
|
|
|
|
with patch("src.api.routes.datasets.AsyncSupersetClient") as MockClient:
|
|
|
|
|
mock_client = AsyncMock()
|
|
|
|
|
@@ -844,7 +847,7 @@ def test_update_column_description_get_fails(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_column_description_response_without_result_key [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Cover line 562: elif branch when response has no "result" key.
|
|
|
|
|
# @BRIEF Cover line 562: elif branch when response has no "result" key.
|
|
|
|
|
def test_update_column_description_response_without_result_key(mock_deps):
|
|
|
|
|
with patch("src.api.routes.datasets.AsyncSupersetClient") as MockClient:
|
|
|
|
|
mock_client = AsyncMock()
|
|
|
|
|
@@ -861,7 +864,7 @@ def test_update_column_description_response_without_result_key(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_column_description_dataset_not_found [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 404 when dataset has no id after GET.
|
|
|
|
|
# @BRIEF Verify 404 when dataset has no id after GET.
|
|
|
|
|
def test_update_column_description_dataset_not_found(mock_deps):
|
|
|
|
|
with patch("src.api.routes.datasets.AsyncSupersetClient") as MockClient:
|
|
|
|
|
mock_client = AsyncMock()
|
|
|
|
|
@@ -876,7 +879,7 @@ def test_update_column_description_dataset_not_found(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_column_description_unexpected_error [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 500 on unexpected error.
|
|
|
|
|
# @BRIEF Verify 500 on unexpected error.
|
|
|
|
|
def test_update_column_description_unexpected_error(mock_deps):
|
|
|
|
|
with patch("src.api.routes.datasets.AsyncSupersetClient") as MockClient:
|
|
|
|
|
mock_client = AsyncMock()
|
|
|
|
|
@@ -891,7 +894,7 @@ def test_update_column_description_unexpected_error(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_metric_description_env_not_found [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 404 when env not found for metric update.
|
|
|
|
|
# @BRIEF Verify 404 when env not found for metric update.
|
|
|
|
|
def test_update_metric_description_env_not_found(mock_deps):
|
|
|
|
|
response = client.put(
|
|
|
|
|
"/api/datasets/1/metrics/100/description?env_id=nonexistent",
|
|
|
|
|
@@ -901,7 +904,7 @@ def test_update_metric_description_env_not_found(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_metric_description_no_result_key [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Cover line 650: elif branch when response has no "result" key for metric.
|
|
|
|
|
# @BRIEF Cover line 650: elif branch when response has no "result" key for metric.
|
|
|
|
|
def test_update_metric_description_no_result_key(mock_deps):
|
|
|
|
|
with patch("src.api.routes.datasets.AsyncSupersetClient") as MockClient:
|
|
|
|
|
mock_client = AsyncMock()
|
|
|
|
|
@@ -917,7 +920,7 @@ def test_update_metric_description_no_result_key(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_metric_description_dataset_not_found [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 404 when dataset not found for metric update.
|
|
|
|
|
# @BRIEF Verify 404 when dataset not found for metric update.
|
|
|
|
|
def test_update_metric_description_dataset_not_found(mock_deps):
|
|
|
|
|
with patch("src.api.routes.datasets.AsyncSupersetClient") as MockClient:
|
|
|
|
|
mock_client = AsyncMock()
|
|
|
|
|
@@ -932,7 +935,7 @@ def test_update_metric_description_dataset_not_found(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_metric_description_unexpected_error [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 500 on unexpected error for metric update.
|
|
|
|
|
# @BRIEF Verify 500 on unexpected error for metric update.
|
|
|
|
|
def test_update_metric_description_unexpected_error(mock_deps):
|
|
|
|
|
with patch("src.api.routes.datasets.AsyncSupersetClient") as MockClient:
|
|
|
|
|
mock_client = AsyncMock()
|
|
|
|
|
@@ -947,7 +950,7 @@ def test_update_metric_description_unexpected_error(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_column_description_type_error [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 500 on TypeError in update_column_description (covers lines 597-599).
|
|
|
|
|
# @BRIEF Verify 500 on TypeError in update_column_description (covers lines 597-599).
|
|
|
|
|
def test_update_column_description_type_error(mock_deps):
|
|
|
|
|
with patch("src.api.routes.datasets.AsyncSupersetClient") as MockClient:
|
|
|
|
|
mock_client = AsyncMock()
|
|
|
|
|
@@ -963,7 +966,7 @@ def test_update_column_description_type_error(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_update_metric_description_type_error [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 500 on TypeError in update_metric_description (covers lines 684-686).
|
|
|
|
|
# @BRIEF Verify 500 on TypeError in update_metric_description (covers lines 684-686).
|
|
|
|
|
def test_update_metric_description_type_error(mock_deps):
|
|
|
|
|
with patch("src.api.routes.datasets.AsyncSupersetClient") as MockClient:
|
|
|
|
|
mock_client = AsyncMock()
|
|
|
|
|
@@ -978,7 +981,7 @@ def test_update_metric_description_type_error(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_get_dataset_detail_database_object [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify database field normalization when it's a dict.
|
|
|
|
|
# @BRIEF Verify database field normalization when it's a dict.
|
|
|
|
|
def test_get_dataset_detail_database_object(mock_deps):
|
|
|
|
|
with patch("src.api.routes.datasets.AsyncSupersetClient") as MockClient:
|
|
|
|
|
mock_client = AsyncMock()
|
|
|
|
|
@@ -1006,7 +1009,7 @@ def test_get_dataset_detail_database_object(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_get_dataset_detail_503 [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 503 when Superset fails for dataset detail.
|
|
|
|
|
# @BRIEF Verify 503 when Superset fails for dataset detail.
|
|
|
|
|
def test_get_dataset_detail_503(mock_deps):
|
|
|
|
|
with patch("src.api.routes.datasets.AsyncSupersetClient") as MockClient:
|
|
|
|
|
mock_client = AsyncMock()
|
|
|
|
|
@@ -1018,14 +1021,14 @@ def test_get_dataset_detail_503(mock_deps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_get_dataset_detail_env_not_found [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Verify 404 when env not found for dataset detail.
|
|
|
|
|
# @BRIEF Verify 404 when env not found for dataset detail.
|
|
|
|
|
def test_get_dataset_detail_env_not_found(mock_deps):
|
|
|
|
|
response = client.get("/api/datasets/1?env_id=nonexistent")
|
|
|
|
|
assert response.status_code == 404
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# #region test_strip_html_tags_function [C:2] [TYPE Function]
|
|
|
|
|
# @PURPOSE: Test _strip_html_tags directly.
|
|
|
|
|
# @BRIEF Test _strip_html_tags directly.
|
|
|
|
|
def test_strip_html_tags_empty():
|
|
|
|
|
from src.api.routes.datasets import _strip_html_tags
|
|
|
|
|
assert _strip_html_tags("") == ""
|
|
|
|
|
|