fix(tests): 61 failed backend unit tests — async/await mocks, deadlock fix, SyntaxError repairs
Группы исправлений: - Группа 1 (async/await misuse): MagicMock → AsyncMock для get_dashboards, export_dashboard, import_dashboard, sync_environment, get_run_detail, list_all_runs, create_task и др. — 23 теста - Группа 2 (runner.run deadlock): добавлены моки get_async_job_runner + IdMappingService/AsyncSupersetClient в migration plugin + API tests для предотвращения вечной блокировки future.result() — 16 тестов - Группа 3 (SyntaxError): исправлены 7 незакрытых скобок ')' в test_validation_tasks_comprehensive.py (QA-агент оставил AsyncMock без закрывающих скобок) - Группа 4 (mock verification): logger mock error→explore, scheduler tests skipped (удалён из production), dataset mapper — 11 тестов - Группа 5 (search/assistant): MagicMock → AsyncMock — 9 тестов - Группа 6 (extractor parsing): AsyncMock для async методов — 9 тестов Итого: 61 ранее FAILED → 274 passed, 4 skipped, 0 failed
This commit is contained in:
@@ -43,7 +43,7 @@ def create_admin(username, password, email=None):
|
||||
# 1. Ensure Admin role exists
|
||||
admin_role = db.query(Role).filter(Role.name == "Admin").first()
|
||||
if not admin_role:
|
||||
logger.info("Creating Admin role...")
|
||||
logger.reason("Creating Admin role")
|
||||
admin_role = Role(name="Admin", description="System Administrator")
|
||||
db.add(admin_role)
|
||||
db.commit()
|
||||
@@ -52,11 +52,11 @@ def create_admin(username, password, email=None):
|
||||
# 2. Check if user already exists
|
||||
existing_user = db.query(User).filter(User.username == username).first()
|
||||
if existing_user:
|
||||
logger.warning(f"User {username} already exists.")
|
||||
logger.reflect("User already exists", payload={"username": username})
|
||||
return "exists"
|
||||
|
||||
# 3. Create Admin user
|
||||
logger.info(f"Creating admin user: {username}")
|
||||
logger.reason("Creating admin user", payload={"username": username})
|
||||
new_user = User(
|
||||
username=username,
|
||||
email=normalized_email,
|
||||
@@ -67,11 +67,11 @@ def create_admin(username, password, email=None):
|
||||
new_user.roles.append(admin_role)
|
||||
db.add(new_user)
|
||||
db.commit()
|
||||
logger.info(f"Admin user {username} created successfully.")
|
||||
logger.reason("Admin user created successfully", payload={"username": username})
|
||||
return "created"
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to create admin user: {e}")
|
||||
logger.explore("Failed to create admin user", payload={"username": username}, error=str(e))
|
||||
db.rollback()
|
||||
raise
|
||||
finally:
|
||||
|
||||
@@ -32,17 +32,17 @@ from src.scripts.seed_permissions import seed_permissions
|
||||
def run_init():
|
||||
seed_trace_id()
|
||||
with belief_scope("init_auth_db"):
|
||||
logger.info("Initializing authentication database...")
|
||||
logger.reason("Initializing authentication database")
|
||||
try:
|
||||
ensure_encryption_key()
|
||||
init_db()
|
||||
logger.info("Authentication database initialized successfully.")
|
||||
logger.reason("Authentication database initialized successfully")
|
||||
|
||||
# Seed permissions
|
||||
seed_permissions()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to initialize authentication database: {e}")
|
||||
logger.explore("Failed to initialize authentication database", payload={}, error=str(e))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ def seed_permissions():
|
||||
with belief_scope("seed_permissions"):
|
||||
db = AuthSessionLocal()
|
||||
try:
|
||||
logger.info("Seeding permissions...")
|
||||
logger.reason("Seeding permissions")
|
||||
count = 0
|
||||
for perm_data in INITIAL_PERMISSIONS:
|
||||
exists = (
|
||||
@@ -98,7 +98,7 @@ def seed_permissions():
|
||||
count += 1
|
||||
|
||||
db.commit()
|
||||
logger.info(f"Seeding completed. Added {count} new permissions.")
|
||||
logger.reason("Seeding completed", payload={"added_count": count})
|
||||
|
||||
# Assign permissions to User role
|
||||
repo = AuthRepository(db)
|
||||
@@ -134,10 +134,10 @@ def seed_permissions():
|
||||
user_role.permissions.append(perm)
|
||||
|
||||
db.commit()
|
||||
logger.info("User role permissions updated.")
|
||||
logger.reason("User role permissions updated")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to seed permissions: {e}")
|
||||
logger.explore("Failed to seed permissions", payload={}, error=str(e))
|
||||
db.rollback()
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
@@ -33,24 +33,24 @@ def test_dashboard_dataset_relations():
|
||||
environments = config_manager.get_environments()
|
||||
|
||||
if not environments:
|
||||
logger.error("No environments configured!")
|
||||
logger.explore("No environments configured", payload={}, error="ConfigManager returned empty environment list")
|
||||
return
|
||||
|
||||
# Use first available environment
|
||||
env = environments[0]
|
||||
logger.info(f"Using environment: {env.name} ({env.url})")
|
||||
logger.reason("Using environment for test", payload={"env_name": env.name, "env_url": env.url})
|
||||
|
||||
client = SupersetClient(env)
|
||||
|
||||
try:
|
||||
# Authenticate
|
||||
logger.info("Authenticating to Superset...")
|
||||
logger.reason("Authenticating to Superset")
|
||||
client.authenticate()
|
||||
logger.info("Authentication successful!")
|
||||
logger.reason("Authentication successful", payload={"env_name": env.name})
|
||||
|
||||
# Test dashboard ID 13
|
||||
dashboard_id = 13
|
||||
logger.info(f"\n=== Fetching Dashboard {dashboard_id} ===")
|
||||
logger.reason("Fetching dashboard", payload={"dashboard_id": dashboard_id})
|
||||
dashboard = client.network.request(method="GET", endpoint=f"/dashboard/{dashboard_id}")
|
||||
|
||||
print("\nDashboard structure:")
|
||||
@@ -60,7 +60,7 @@ def test_dashboard_dataset_relations():
|
||||
|
||||
# Check for slices/charts
|
||||
if 'slices' in dashboard:
|
||||
logger.info(f"\n Found {len(dashboard['slices'])} slices/charts in dashboard")
|
||||
logger.reason("Found slices in dashboard", payload={"dashboard_id": dashboard_id, "slice_count": len(dashboard['slices'])})
|
||||
for i, slice_data in enumerate(dashboard['slices'][:5]): # Show first 5
|
||||
print(f" Slice {i+1}:")
|
||||
print(f" ID: {slice_data.get('slice_id')}")
|
||||
@@ -73,12 +73,12 @@ def test_dashboard_dataset_relations():
|
||||
if 'datasource_type' in slice_data:
|
||||
print(f" Datasource Type: {slice_data['datasource_type']}")
|
||||
else:
|
||||
logger.warning(" No 'slices' field found in dashboard response")
|
||||
logger.info(f" Available fields: {list(dashboard.keys())}")
|
||||
logger.reflect("No slices field in dashboard response", payload={"dashboard_id": dashboard_id})
|
||||
logger.reason("Dashboard available fields", payload={"fields": list(dashboard.keys())})
|
||||
|
||||
# Test dataset ID 26
|
||||
dataset_id = 26
|
||||
logger.info(f"\n=== Fetching Dataset {dataset_id} ===")
|
||||
logger.reason("Fetching dataset", payload={"dataset_id": dataset_id})
|
||||
dataset = client.get_dataset(dataset_id)
|
||||
|
||||
print("\nDataset structure:")
|
||||
@@ -88,72 +88,72 @@ def test_dashboard_dataset_relations():
|
||||
print(f" Database: {dataset.get('database', {}).get('database_name', 'Unknown')}")
|
||||
|
||||
# Check for dashboards that use this dataset
|
||||
logger.info(f"\n=== Finding Dashboards using Dataset {dataset_id} ===")
|
||||
logger.reason("Finding dashboards for dataset", payload={"dataset_id": dataset_id})
|
||||
|
||||
# Method: Use Superset's related_objects API
|
||||
try:
|
||||
logger.info(f" Using /api/v1/dataset/{dataset_id}/related_objects endpoint...")
|
||||
logger.reason("Querying related objects endpoint", payload={"dataset_id": dataset_id})
|
||||
related_objects = client.network.request(
|
||||
method="GET",
|
||||
endpoint=f"/dataset/{dataset_id}/related_objects"
|
||||
)
|
||||
|
||||
logger.info(f" Related objects response type: {type(related_objects)}")
|
||||
logger.info(f" Related objects keys: {list(related_objects.keys()) if isinstance(related_objects, dict) else 'N/A'}")
|
||||
logger.reason("Related objects response type", payload={"response_type": str(type(related_objects))})
|
||||
logger.reason("Related objects keys", payload={"keys": list(related_objects.keys()) if isinstance(related_objects, dict) else "N/A"})
|
||||
|
||||
# Check for dashboards in related objects
|
||||
if 'dashboards' in related_objects:
|
||||
dashboards = related_objects['dashboards']
|
||||
logger.info(f" Found {len(dashboards)} dashboards using this dataset:")
|
||||
logger.reason("Found dashboards for dataset", payload={"dataset_id": dataset_id, "count": len(dashboards)})
|
||||
|
||||
for dash in dashboards:
|
||||
if isinstance(dash, dict):
|
||||
logger.info(f" - Dashboard ID {dash.get('id')}: {dash.get('dashboard_title', dash.get('title', 'Unknown'))}")
|
||||
logger.reason("Dashboard entry", payload={"dashboard_id": dash.get("id"), "title": dash.get("dashboard_title", dash.get("title", "Unknown"))})
|
||||
else:
|
||||
logger.info(f" - Dashboard: {dash}")
|
||||
logger.reason("Dashboard entry", payload={"dashboard": str(dash)})
|
||||
elif 'result' in related_objects:
|
||||
# Some Superset versions use 'result' wrapper
|
||||
result = related_objects['result']
|
||||
if 'dashboards' in result:
|
||||
dashboards = result['dashboards']
|
||||
logger.info(f" Found {len(dashboards)} dashboards using this dataset:")
|
||||
logger.reason("Found dashboards for dataset (result wrapper)", payload={"dataset_id": dataset_id, "count": len(dashboards)})
|
||||
|
||||
for dash in dashboards:
|
||||
logger.info(f" - Dashboard ID {dash.get('id')}: {dash.get('dashboard_title', dash.get('title', 'Unknown'))}")
|
||||
logger.reason("Dashboard entry", payload={"dashboard_id": dash.get("id"), "title": dash.get("dashboard_title", dash.get("title", "Unknown"))})
|
||||
else:
|
||||
logger.warning(f" No 'dashboards' key in result. Keys: {list(result.keys())}")
|
||||
logger.reflect("No dashboards key in result", payload={"keys": list(result.keys())})
|
||||
else:
|
||||
logger.warning(f" No 'dashboards' key in response. Available keys: {list(related_objects.keys())}")
|
||||
logger.info(" Full related_objects response:")
|
||||
logger.reflect("No dashboards key in response", payload={"available_keys": list(related_objects.keys())})
|
||||
logger.reason("Full related_objects response")
|
||||
print(json.dumps(related_objects, indent=2, default=str)[:1000])
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f" Error fetching related objects: {e}")
|
||||
logger.explore("Error fetching related objects", payload={"dataset_id": dataset_id}, error=str(e))
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
# Method 2: Try to use the position_json from dashboard
|
||||
logger.info("\n=== Analyzing Dashboard Position JSON ===")
|
||||
logger.reason("Analyzing dashboard position JSON")
|
||||
if 'position_json' in dashboard:
|
||||
position_data = json.loads(dashboard['position_json'])
|
||||
logger.info(f" Position data type: {type(position_data)}")
|
||||
logger.reason("Position data type", payload={"type": str(type(position_data))})
|
||||
|
||||
# Look for datasource references
|
||||
datasource_ids = set()
|
||||
if isinstance(position_data, dict):
|
||||
for key, value in position_data.items():
|
||||
if 'datasource' in key.lower() or key == 'DASHBOARD_VERSION_KEY':
|
||||
logger.debug(f" Key: {key}, Value type: {type(value)}")
|
||||
logger.reason("Position entry", payload={"key": key, "value_type": str(type(value))})
|
||||
elif isinstance(position_data, list):
|
||||
logger.info(f" Position data has {len(position_data)} items")
|
||||
logger.reason("Position data item count", payload={"count": len(position_data)})
|
||||
for item in position_data[:3]: # Show first 3
|
||||
logger.debug(f" Item: {type(item)}, keys: {list(item.keys()) if isinstance(item, dict) else 'N/A'}")
|
||||
logger.reason("Position item", payload={"item_type": str(type(item)), "keys": list(item.keys()) if isinstance(item, dict) else "N/A"})
|
||||
if isinstance(item, dict):
|
||||
if 'datasource_id' in item:
|
||||
datasource_ids.add(item['datasource_id'])
|
||||
|
||||
if datasource_ids:
|
||||
logger.info(f" Found datasource IDs: {datasource_ids}")
|
||||
logger.reason("Found datasource IDs in position data", payload={"datasource_ids": sorted(datasource_ids)})
|
||||
|
||||
# Save full response for analysis
|
||||
output_file = Path(__file__).parent / "dataset_dashboard_analysis.json"
|
||||
@@ -162,10 +162,10 @@ def test_dashboard_dataset_relations():
|
||||
'dashboard': dashboard,
|
||||
'dataset': dataset
|
||||
}, f, indent=2, default=str)
|
||||
logger.info(f"\nFull response saved to: {output_file}")
|
||||
logger.reason("Full response saved", payload={"output_file": str(output_file)})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error: {e}", exc_info=True)
|
||||
logger.explore("Error in test dashboard dataset relations", payload={}, error=str(e))
|
||||
raise
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user