7a0da7932b
Backwards Compatibility / Verify Encryption Constants (push) Waiting to run
Backwards Compatibility / PyPI Version Compatibility (push) Waiting to run
Backwards Compatibility / Database Migration Tests (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
CodeQL Advanced / Analyze (python) (push) Waiting to run
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Blocked by required conditions
Docker Tests (Consolidated) / detect-changes (push) Waiting to run
Docker Tests (Consolidated) / Build Test Image (push) Waiting to run
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Blocked by required conditions
Docker Tests (Consolidated) / Accessibility Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Unit Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Example Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / Production Image Smoke Test (push) Blocked by required conditions
Docker Tests (Consolidated) / Infrastructure Tests (push) Blocked by required conditions
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Waiting to run
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
264 lines
9.0 KiB
Python
Executable File
264 lines
9.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
pytest: skip
|
|
|
|
This is an end-to-end test script, not a pytest test.
|
|
|
|
End-to-end test script for verifying OpenAI API key configuration.
|
|
|
|
This script helps users verify that their OpenAI API key is properly configured
|
|
and working with Local Deep Research.
|
|
|
|
Usage:
|
|
python tests/test_openai_api_key_e2e.py --username YOUR_USERNAME --password YOUR_PASSWORD --api-key YOUR_LDR_LLM_OPENAI_API_KEY
|
|
|
|
Or set environment variables:
|
|
export LDR_USERNAME=your_username
|
|
export LDR_PASSWORD=your_password
|
|
export LDR_LLM_OPENAI_API_KEY=your_api_key
|
|
python tests/test_openai_api_key_e2e.py
|
|
"""
|
|
|
|
import argparse
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
# Add project root to path
|
|
sys.path.insert(0, str(Path(__file__).parent.parent.resolve()))
|
|
|
|
from local_deep_research.database.session_context import get_user_db_session
|
|
from local_deep_research.config.llm_config import get_llm
|
|
from local_deep_research.api.research_functions import quick_summary
|
|
from local_deep_research.settings import SettingsManager
|
|
from loguru import logger
|
|
import pytest
|
|
|
|
# Skip this entire module in pytest
|
|
pytestmark = pytest.mark.skip(
|
|
reason="End-to-end test script, not a pytest test"
|
|
)
|
|
|
|
|
|
def test_openai_api_key_e2e(
|
|
username: str, password: str, api_key: Optional[str] = None
|
|
) -> bool:
|
|
"""
|
|
Test OpenAI API key configuration and usage.
|
|
|
|
Args:
|
|
username: LDR username
|
|
password: LDR password
|
|
api_key: OpenAI API key (optional, can use env var)
|
|
|
|
Returns:
|
|
bool: True if test passed, False otherwise
|
|
"""
|
|
# audit: PUNCHLIST reviewed 2026-05 — issue resolved by prior PR (recommendation: rename file out of test_ prefix).
|
|
print("=" * 60)
|
|
print("OpenAI API Key Configuration Test")
|
|
print("=" * 60)
|
|
|
|
try:
|
|
# Step 1: Authenticate
|
|
print("\n1. Authenticating with LDR...")
|
|
with get_user_db_session(
|
|
username=username, password=password
|
|
) as session:
|
|
print(" ✓ Authentication successful")
|
|
|
|
# Step 2: Configure settings
|
|
print("\n2. Configuring OpenAI settings...")
|
|
settings_manager = SettingsManager(session)
|
|
|
|
# Set OpenAI as provider
|
|
settings_manager.set_setting("llm.provider", "openai")
|
|
print(" ✓ Set provider to OpenAI")
|
|
|
|
# Set API key if provided
|
|
if api_key:
|
|
settings_manager.set_setting("llm.openai.api_key", api_key)
|
|
print(" ✓ Set OpenAI API key")
|
|
else:
|
|
# Check if API key exists in settings or environment
|
|
existing_key = settings_manager.get_setting(
|
|
"llm.openai.api_key"
|
|
)
|
|
env_key = os.getenv("LDR_LLM_OPENAI_API_KEY")
|
|
|
|
if not existing_key and not env_key:
|
|
print(" ✗ No API key found in settings or environment")
|
|
print(
|
|
" Please provide --api-key or set LDR_LLM_OPENAI_API_KEY environment variable"
|
|
)
|
|
return False
|
|
|
|
if existing_key:
|
|
print(" ✓ Using existing API key from settings")
|
|
else:
|
|
print(" ✓ Using API key from environment variable")
|
|
|
|
# Set model
|
|
settings_manager.set_setting("llm.model", "gpt-3.5-turbo")
|
|
print(" ✓ Set model to gpt-3.5-turbo")
|
|
|
|
# Get settings snapshot
|
|
settings_snapshot = settings_manager.get_all_settings()
|
|
|
|
# Step 3: Test LLM initialization
|
|
print("\n3. Testing LLM initialization...")
|
|
try:
|
|
llm = get_llm(settings_snapshot=settings_snapshot)
|
|
print(" ✓ LLM initialized successfully")
|
|
except Exception as e:
|
|
print(f" ✗ Failed to initialize LLM: {str(e)}")
|
|
if "api key" in str(e).lower():
|
|
print(" This appears to be an API key issue")
|
|
return False
|
|
|
|
# Step 4: Test simple LLM call
|
|
print("\n4. Testing LLM response...")
|
|
try:
|
|
from langchain_core.messages.human import HumanMessage
|
|
|
|
response = llm.invoke(
|
|
[
|
|
HumanMessage(
|
|
content="Say 'Hello, LDR!' in 5 words or less"
|
|
)
|
|
]
|
|
)
|
|
print(f" ✓ LLM responded: {response.content}")
|
|
except Exception as e:
|
|
print(f" ✗ Failed to get LLM response: {str(e)}")
|
|
if "401" in str(e) or "unauthorized" in str(e).lower():
|
|
print(" API key appears to be invalid")
|
|
elif "429" in str(e):
|
|
print(
|
|
" Rate limit exceeded - API key is valid but quota exhausted"
|
|
)
|
|
return False
|
|
|
|
# Step 5: Test research functionality
|
|
print("\n5. Testing research functionality...")
|
|
try:
|
|
result = quick_summary(
|
|
query="What is the capital of France?",
|
|
settings_snapshot=settings_snapshot,
|
|
iterations=1,
|
|
questions_per_iteration=1,
|
|
search_tool="wikipedia", # Use Wikipedia to avoid web search rate limits
|
|
)
|
|
|
|
print(" ✓ Research completed successfully")
|
|
print(f" Research ID: {result.get('research_id', 'N/A')}")
|
|
print(
|
|
f" Summary preview: {result.get('summary', '')[:100]}..."
|
|
)
|
|
|
|
if "paris" in result.get("summary", "").lower():
|
|
print(" ✓ Result contains expected content")
|
|
else:
|
|
print(" ⚠ Result may not contain expected content")
|
|
|
|
except Exception as e:
|
|
print(f" ✗ Failed to complete research: {str(e)}")
|
|
return False
|
|
|
|
# Success!
|
|
print("\n" + "=" * 60)
|
|
print(
|
|
"✅ All tests passed! Your OpenAI API key is configured correctly."
|
|
)
|
|
print("=" * 60)
|
|
|
|
# Show configuration summary
|
|
print("\nCurrent Configuration:")
|
|
print(
|
|
f" Provider: {settings_snapshot.get('llm.provider', {}).get('value', 'Not set')}"
|
|
)
|
|
print(
|
|
f" Model: {settings_snapshot.get('llm.model', {}).get('value', 'Not set')}"
|
|
)
|
|
print(f" API Key: {'*' * 20} (hidden)")
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"\n✗ Unexpected error: {str(e)}")
|
|
logger.exception("Test failed with exception")
|
|
return False
|
|
|
|
|
|
def main():
|
|
"""Main entry point for the test script."""
|
|
parser = argparse.ArgumentParser(
|
|
description="Test OpenAI API key configuration with Local Deep Research",
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
epilog="""
|
|
Examples:
|
|
# With command line arguments
|
|
python test_openai_api_key_e2e.py --username myuser --password mypass --api-key sk-...
|
|
|
|
# With environment variables
|
|
export LDR_USERNAME=myuser
|
|
export LDR_PASSWORD=mypass
|
|
export LDR_LLM_OPENAI_API_KEY=sk-...
|
|
python test_openai_api_key_e2e.py
|
|
|
|
Note: The LDR server must be running and you must have a user account created.
|
|
""",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--username",
|
|
default=os.getenv("LDR_USERNAME"),
|
|
help="LDR username (or set LDR_USERNAME env var)",
|
|
)
|
|
parser.add_argument(
|
|
"--password",
|
|
default=os.getenv("LDR_PASSWORD"),
|
|
help="LDR password (or set LDR_PASSWORD env var)",
|
|
)
|
|
parser.add_argument(
|
|
"--api-key",
|
|
default=os.getenv("LDR_LLM_OPENAI_API_KEY"),
|
|
help="OpenAI API key (or set LDR_LLM_OPENAI_API_KEY env var)",
|
|
)
|
|
parser.add_argument(
|
|
"--verbose", action="store_true", help="Enable verbose logging"
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Validate required arguments
|
|
if not args.username or not args.password:
|
|
print("Error: Username and password are required")
|
|
print(
|
|
"Provide them via --username/--password or LDR_USERNAME/LDR_PASSWORD env vars"
|
|
)
|
|
parser.print_help()
|
|
sys.exit(1)
|
|
|
|
# Configure logging
|
|
if not args.verbose:
|
|
logger.remove() # Remove default handler
|
|
# diagnose=False: this e2e harness passes args.api_key and
|
|
# args.password into the test function — both end up as frame locals
|
|
# that loguru's default diagnose=True would dump into error tracebacks
|
|
# (#4185 / #4384).
|
|
logger.add(sys.stderr, level="ERROR", diagnose=False)
|
|
|
|
# Run the test
|
|
success = test_openai_api_key_e2e(
|
|
username=args.username, password=args.password, api_key=args.api_key
|
|
)
|
|
|
|
# Exit with appropriate code
|
|
sys.exit(0 if success else 1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|