Files
temp/tests/features/environment.py
T

165 lines
5.2 KiB
Python

"""
BDD test environment setup for reactive CleverAgents.
"""
import asyncio
import os
import shutil
import sys
import tempfile
from pathlib import Path
# Increase recursion limit to handle deep import chains in langchain/torch/transformers
sys.setrecursionlimit(5000)
def before_all(context):
"""Set up test environment before all tests."""
context.temp_dir = Path(tempfile.mkdtemp())
# Set dummy API keys for testing
os.environ["OPENAI_API_KEY"] = "test-key-openai"
os.environ["ANTHROPIC_API_KEY"] = "test-key-anthropic"
os.environ["GOOGLE_GEMINI_API_KEY"] = "test-key-google"
# Create async event loop for tests
context.loop = asyncio.new_event_loop()
asyncio.set_event_loop(context.loop)
def after_all(context):
"""Clean up test environment after all tests."""
# Clean up temp directory
import shutil
shutil.rmtree(context.temp_dir, ignore_errors=True)
# Close async event loop with proper cleanup
if hasattr(context, "loop"):
# Cancel all remaining tasks
try:
pending = asyncio.all_tasks(context.loop)
for task in pending:
task.cancel()
except Exception:
pass
# Close the loop without waiting for tasks
try:
context.loop.close()
except Exception:
pass
def before_scenario(context, scenario):
"""Set up before each scenario."""
context.config_files = []
context.app = None
context.result = None
context.error = None
context.unsafe = False
# Create scenario-specific temp directory
context.scenario_temp = context.temp_dir / f"scenario_{scenario.name.replace(' ', '_')}"
context.scenario_temp.mkdir(exist_ok=True)
# Set up test context for InlineYAMLJinja tests - not needed for simplified tests
# if "InlineYAMLJinja" in scenario.feature.name or "inline_yaml_jinja" in str(scenario.feature.filename):
# from tests.features.steps.inline_yaml_jinja_coverage_steps import TestContext
# context.test_context = TestContext()
def after_scenario(context, scenario):
"""Clean up after each scenario."""
# Clean up bridge resources if present
if hasattr(context, "bridge") and context.bridge:
try:
context.bridge.cleanup()
except Exception:
pass
# Dispose of app if created
if hasattr(context, "app") and context.app:
try:
# dispose() is async, so we need to run it in the event loop
if hasattr(context, "loop") and context.loop:
context.loop.run_until_complete(context.app.dispose())
else:
asyncio.run(context.app.dispose())
except Exception:
pass
# Cancel any remaining tasks without waiting
if hasattr(context, "loop"):
try:
pending = asyncio.all_tasks(context.loop)
for task in pending:
task.cancel()
except Exception:
pass
# Clean up event loops created by LangGraph tests
if hasattr(context, "event_loops"):
for loop in context.event_loops:
try:
if hasattr(loop, "is_closed") and not loop.is_closed():
# Cancel all tasks in this loop
tasks = asyncio.all_tasks(loop)
for task in tasks:
task.cancel()
loop.close()
except Exception:
pass
# Clean up temp directories from LangGraph tests
if hasattr(context, "temp_dirs"):
for temp_dir in context.temp_dirs:
try:
shutil.rmtree(temp_dir)
except:
pass
# Clean up graphs and their schedulers
if hasattr(context, "graphs"):
for graph in context.graphs:
try:
if hasattr(graph, "scheduler") and hasattr(graph.scheduler, "_loop"):
loop = graph.scheduler._loop
if hasattr(loop, "is_closed") and not loop.is_closed():
# Cancel all tasks
tasks = asyncio.all_tasks(loop)
for task in tasks:
task.cancel()
loop.close()
except Exception:
pass
# Clean up template loader test files
if "template_loaders_coverage" in str(scenario.feature.filename):
# fmt: off
from tests.features.steps.template_loaders_coverage_steps import cleanup_test_files # isort: skip
# fmt: on
cleanup_test_files(context)
# Clean up files tracked for cleanup in tool_agent tests
if hasattr(context, "__dict__") and "_cleanup_files" in context.__dict__:
import os
for filepath in context.__dict__["_cleanup_files"]:
try:
if os.path.exists(filepath):
os.remove(filepath)
except Exception:
pass
context.__dict__["_cleanup_files"] = []
# Clean up scenario temp directory
if hasattr(context, "scenario_temp") and context.scenario_temp.exists():
import shutil
try:
shutil.rmtree(context.scenario_temp, ignore_errors=True)
except Exception:
pass