|
|
""" |
|
|
Dev B Test Suite - Run with: .venv/Scripts/python test_devb.py |
|
|
""" |
|
|
|
|
|
import asyncio |
|
|
import sys |
|
|
sys.path.insert(0, '.') |
|
|
|
|
|
from app.llm import generate_documentation, synthesize_answer, get_embedding |
|
|
from app.vectorstore import init_vectorstore, add_embedding, search, count_embeddings, delete_by_project |
|
|
|
|
|
|
|
|
passed = 0 |
|
|
failed = 0 |
|
|
|
|
|
|
|
|
def test(name, condition, details=""): |
|
|
global passed, failed |
|
|
if condition: |
|
|
print(f" [PASS] {name}") |
|
|
passed += 1 |
|
|
else: |
|
|
print(f" [FAIL] {name} - {details}") |
|
|
failed += 1 |
|
|
|
|
|
|
|
|
async def test_llm(): |
|
|
print("\n[1/4] Testing LLM Client (llm.py)") |
|
|
print("-" * 40) |
|
|
|
|
|
|
|
|
try: |
|
|
emb = await get_embedding("test embedding") |
|
|
test("get_embedding returns list", isinstance(emb, list)) |
|
|
test("get_embedding returns 768 dims", len(emb) == 768, f"got {len(emb)}") |
|
|
test("get_embedding returns floats", isinstance(emb[0], float)) |
|
|
except Exception as e: |
|
|
test("get_embedding", False, str(e)) |
|
|
|
|
|
|
|
|
try: |
|
|
doc = await generate_documentation( |
|
|
task_title="Setup API", |
|
|
what_i_did="Created REST endpoints", |
|
|
code_snippet="@app.get('/api')" |
|
|
) |
|
|
test("generate_documentation returns dict", isinstance(doc, dict)) |
|
|
test("generate_documentation has summary", "summary" in doc) |
|
|
test("generate_documentation has details", "details" in doc) |
|
|
test("generate_documentation has tags", "tags" in doc and isinstance(doc["tags"], list)) |
|
|
except Exception as e: |
|
|
test("generate_documentation", False, str(e)) |
|
|
|
|
|
|
|
|
try: |
|
|
answer = await synthesize_answer( |
|
|
context="Task completed: Built login system with JWT authentication", |
|
|
query="What authentication was implemented?" |
|
|
) |
|
|
test("synthesize_answer returns string", isinstance(answer, str)) |
|
|
test("synthesize_answer not empty", len(answer) > 0) |
|
|
except Exception as e: |
|
|
test("synthesize_answer", False, str(e)) |
|
|
|
|
|
|
|
|
async def test_vectorstore(): |
|
|
print("\n[2/4] Testing Vector Store (vectorstore.py)") |
|
|
print("-" * 40) |
|
|
|
|
|
|
|
|
try: |
|
|
init_vectorstore() |
|
|
test("init_vectorstore succeeds", True) |
|
|
except Exception as e: |
|
|
test("init_vectorstore", False, str(e)) |
|
|
return |
|
|
|
|
|
|
|
|
try: |
|
|
delete_by_project("test-project-xyz") |
|
|
except: |
|
|
pass |
|
|
|
|
|
|
|
|
try: |
|
|
emb = await get_embedding("Test document about Python programming") |
|
|
add_embedding( |
|
|
log_entry_id="test-entry-1", |
|
|
text="Test document about Python programming", |
|
|
embedding=emb, |
|
|
metadata={ |
|
|
"project_id": "test-project-xyz", |
|
|
"user_id": "test-user", |
|
|
"task_id": "test-task", |
|
|
"created_at": "2024-01-01T00:00:00" |
|
|
} |
|
|
) |
|
|
test("add_embedding succeeds", True) |
|
|
except Exception as e: |
|
|
test("add_embedding", False, str(e)) |
|
|
|
|
|
|
|
|
try: |
|
|
count = count_embeddings("test-project-xyz") |
|
|
test("count_embeddings returns int", isinstance(count, int)) |
|
|
test("count_embeddings >= 1", count >= 1, f"got {count}") |
|
|
except Exception as e: |
|
|
test("count_embeddings", False, str(e)) |
|
|
|
|
|
|
|
|
try: |
|
|
query_emb = await get_embedding("Python") |
|
|
results = search(query_emb, "test-project-xyz", n_results=5) |
|
|
test("search returns list", isinstance(results, list)) |
|
|
test("search finds results", len(results) > 0, "no results found") |
|
|
if results: |
|
|
test("search result has id", "id" in results[0]) |
|
|
test("search result has metadata", "metadata" in results[0]) |
|
|
test("search result has distance", "distance" in results[0]) |
|
|
except Exception as e: |
|
|
test("search", False, str(e)) |
|
|
|
|
|
|
|
|
try: |
|
|
delete_by_project("test-project-xyz") |
|
|
count_after = count_embeddings("test-project-xyz") |
|
|
test("delete_by_project removes data", count_after == 0, f"still has {count_after}") |
|
|
except Exception as e: |
|
|
test("delete_by_project", False, str(e)) |
|
|
|
|
|
|
|
|
async def test_full_pipeline(): |
|
|
print("\n[3/4] Testing Full Pipeline") |
|
|
print("-" * 40) |
|
|
|
|
|
project_id = "pipeline-test-proj" |
|
|
|
|
|
|
|
|
try: |
|
|
delete_by_project(project_id) |
|
|
except: |
|
|
pass |
|
|
|
|
|
try: |
|
|
|
|
|
doc = await generate_documentation( |
|
|
task_title="Implement user registration", |
|
|
what_i_did="Added signup endpoint with email validation and password hashing", |
|
|
code_snippet="def register(email, password): ..." |
|
|
) |
|
|
test("Pipeline: doc generation", "summary" in doc and "details" in doc) |
|
|
|
|
|
|
|
|
text_to_embed = f"{doc['summary']} {doc['details']}" |
|
|
embedding = await get_embedding(text_to_embed) |
|
|
test("Pipeline: embedding created", len(embedding) == 768) |
|
|
|
|
|
|
|
|
add_embedding( |
|
|
log_entry_id="pipeline-log-1", |
|
|
text=text_to_embed, |
|
|
embedding=embedding, |
|
|
metadata={"project_id": project_id, "user_id": "dev1"} |
|
|
) |
|
|
test("Pipeline: stored in vectorstore", count_embeddings(project_id) == 1) |
|
|
|
|
|
|
|
|
query_emb = await get_embedding("user registration signup") |
|
|
results = search(query_emb, project_id) |
|
|
test("Pipeline: search finds it", len(results) > 0) |
|
|
|
|
|
|
|
|
if results: |
|
|
context = results[0]["metadata"]["text"] |
|
|
answer = await synthesize_answer(context, "What was done for user registration?") |
|
|
test("Pipeline: answer synthesized", len(answer) > 20) |
|
|
|
|
|
|
|
|
delete_by_project(project_id) |
|
|
|
|
|
except Exception as e: |
|
|
test("Pipeline", False, str(e)) |
|
|
|
|
|
|
|
|
async def test_edge_cases(): |
|
|
print("\n[4/4] Testing Edge Cases") |
|
|
print("-" * 40) |
|
|
|
|
|
|
|
|
try: |
|
|
init_vectorstore() |
|
|
emb = await get_embedding("random query") |
|
|
results = search(emb, "nonexistent-project-12345") |
|
|
test("Empty search returns empty list", results == []) |
|
|
except Exception as e: |
|
|
test("Empty search", False, str(e)) |
|
|
|
|
|
|
|
|
try: |
|
|
long_text = "word " * 1000 |
|
|
emb = await get_embedding(long_text) |
|
|
test("Long text embedding works", len(emb) == 768) |
|
|
except Exception as e: |
|
|
test("Long text embedding", False, str(e)) |
|
|
|
|
|
|
|
|
try: |
|
|
special_text = "Code: `const x = 'hello';` // comment <script>alert('xss')</script>" |
|
|
emb = await get_embedding(special_text) |
|
|
test("Special chars embedding works", len(emb) == 768) |
|
|
except Exception as e: |
|
|
test("Special chars embedding", False, str(e)) |
|
|
|
|
|
|
|
|
async def main(): |
|
|
print("=" * 50) |
|
|
print(" DEV B TEST SUITE - Intelligence Layer") |
|
|
print("=" * 50) |
|
|
|
|
|
await test_llm() |
|
|
await test_vectorstore() |
|
|
await test_full_pipeline() |
|
|
await test_edge_cases() |
|
|
|
|
|
print("\n" + "=" * 50) |
|
|
print(f" RESULTS: {passed} passed, {failed} failed") |
|
|
print("=" * 50) |
|
|
|
|
|
if failed > 0: |
|
|
sys.exit(1) |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
asyncio.run(main()) |
|
|
|