#!/usr/bin/env python3 """ Integration tests for ChromaDB and Weaviate upload functionality. Tests real upload capabilities for vector databases. """ import json import os import pytest from pathlib import Path from unittest.mock import Mock, patch # Import adaptors from skill_seekers.cli.adaptors import get_adaptor @pytest.fixture def sample_chroma_package(tmp_path): """Create a sample ChromaDB package for testing.""" package_data = { "collection_name": "test_collection", "documents": ["Test doc 1", "Test doc 2", "Test doc 3"], "metadatas": [ {"source": "test", "category": "overview", "file": "SKILL.md"}, {"source": "test", "category": "api", "file": "API.md"}, {"source": "test", "category": "guide", "file": "GUIDE.md"} ], "ids": ["id1", "id2", "id3"] } package_path = tmp_path / "test-chroma.json" package_path.write_text(json.dumps(package_data)) return package_path @pytest.fixture def sample_weaviate_package(tmp_path): """Create a sample Weaviate package for testing.""" package_data = { "class_name": "TestSkill", "schema": { "class": "TestSkill", "description": "Test skill documentation", "vectorizer": "none", "properties": [ {"name": "content", "dataType": ["text"]}, {"name": "source", "dataType": ["string"]}, {"name": "category", "dataType": ["string"]} ] }, "objects": [ { "id": "00000000-0000-0000-0000-000000000001", "properties": { "content": "Test content 1", "source": "test", "category": "overview" } }, { "id": "00000000-0000-0000-0000-000000000002", "properties": { "content": "Test content 2", "source": "test", "category": "api" } } ] } package_path = tmp_path / "test-weaviate.json" package_path.write_text(json.dumps(package_data)) return package_path class TestChromaUploadBasics: """Test ChromaDB upload basic functionality.""" def test_chroma_adaptor_exists(self): """Test that ChromaDB adaptor can be loaded.""" adaptor = get_adaptor('chroma') assert adaptor is not None assert adaptor.PLATFORM == 'chroma' def test_chroma_upload_without_chromadb_installed(self, sample_chroma_package): """Test upload fails gracefully without chromadb installed.""" adaptor = get_adaptor('chroma') # Temporarily remove chromadb if it exists import sys chromadb_backup = sys.modules.get('chromadb') if 'chromadb' in sys.modules: del sys.modules['chromadb'] try: result = adaptor.upload(sample_chroma_package) assert result['success'] is False assert 'chromadb not installed' in result['message'] assert 'pip install chromadb' in result['message'] finally: if chromadb_backup: sys.modules['chromadb'] = chromadb_backup def test_chroma_upload_api_signature(self, sample_chroma_package): """Test ChromaDB upload has correct API signature.""" adaptor = get_adaptor('chroma') # Verify upload method exists and accepts kwargs assert hasattr(adaptor, 'upload') assert callable(adaptor.upload) # Verify adaptor methods exist assert hasattr(adaptor, '_generate_openai_embeddings') class TestWeaviateUploadBasics: """Test Weaviate upload basic functionality.""" def test_weaviate_adaptor_exists(self): """Test that Weaviate adaptor can be loaded.""" adaptor = get_adaptor('weaviate') assert adaptor is not None assert adaptor.PLATFORM == 'weaviate' def test_weaviate_upload_without_weaviate_installed(self, sample_weaviate_package): """Test upload fails gracefully without weaviate-client installed.""" adaptor = get_adaptor('weaviate') # Temporarily remove weaviate if it exists import sys weaviate_backup = sys.modules.get('weaviate') if 'weaviate' in sys.modules: del sys.modules['weaviate'] try: result = adaptor.upload(sample_weaviate_package) assert result['success'] is False assert 'weaviate-client not installed' in result['message'] assert 'pip install weaviate-client' in result['message'] finally: if weaviate_backup: sys.modules['weaviate'] = weaviate_backup def test_weaviate_upload_api_signature(self, sample_weaviate_package): """Test Weaviate upload has correct API signature.""" adaptor = get_adaptor('weaviate') # Verify upload method exists and accepts kwargs assert hasattr(adaptor, 'upload') assert callable(adaptor.upload) # Verify adaptor methods exist assert hasattr(adaptor, '_generate_openai_embeddings') class TestPackageStructure: """Test that packages are correctly structured for upload.""" def test_chroma_package_structure(self, sample_chroma_package): """Test ChromaDB package has required fields.""" with open(sample_chroma_package) as f: data = json.load(f) assert 'collection_name' in data assert 'documents' in data assert 'metadatas' in data assert 'ids' in data assert len(data['documents']) == len(data['metadatas']) == len(data['ids']) def test_weaviate_package_structure(self, sample_weaviate_package): """Test Weaviate package has required fields.""" with open(sample_weaviate_package) as f: data = json.load(f) assert 'class_name' in data assert 'schema' in data assert 'objects' in data assert len(data['objects']) == 2 # Verify schema structure assert 'class' in data['schema'] assert 'properties' in data['schema'] # Verify object structure for obj in data['objects']: assert 'id' in obj assert 'properties' in obj class TestUploadCommandIntegration: """Test upload command integration.""" def test_upload_skill_api_signature(self): """Test upload_skill_api has correct signature.""" from skill_seekers.cli.upload_skill import upload_skill_api # Verify function exists assert callable(upload_skill_api) # Verify it accepts kwargs for vector DBs import inspect sig = inspect.signature(upload_skill_api) params = list(sig.parameters.keys()) assert 'package_path' in params assert 'target' in params assert 'api_key' in params assert 'kwargs' in params # For platform-specific options def test_upload_command_supports_chroma(self): """Test upload command recognizes chroma as target.""" from skill_seekers.cli.upload_skill import upload_skill_api # This should not raise ValueError adaptor = get_adaptor('chroma') assert adaptor is not None def test_upload_command_supports_weaviate(self): """Test upload command recognizes weaviate as target.""" from skill_seekers.cli.upload_skill import upload_skill_api # This should not raise ValueError adaptor = get_adaptor('weaviate') assert adaptor is not None class TestErrorHandling: """Test error handling in upload functionality.""" def test_chroma_handles_missing_file(self, tmp_path): """Test ChromaDB upload handles missing files gracefully.""" adaptor = get_adaptor('chroma') missing_file = tmp_path / "nonexistent.json" # Should raise FileNotFoundError or return error dict try: result = adaptor.upload(missing_file) # If it returns a dict, it should indicate failure assert result['success'] is False except FileNotFoundError: # This is also acceptable pass def test_weaviate_handles_missing_file(self, tmp_path): """Test Weaviate upload handles missing files gracefully.""" adaptor = get_adaptor('weaviate') missing_file = tmp_path / "nonexistent.json" # Should raise FileNotFoundError or return error dict try: result = adaptor.upload(missing_file) # If it returns a dict, it should indicate failure assert result['success'] is False except FileNotFoundError: # This is also acceptable pass def test_chroma_handles_invalid_json(self, tmp_path): """Test ChromaDB upload handles invalid JSON gracefully.""" adaptor = get_adaptor('chroma') invalid_file = tmp_path / "invalid.json" invalid_file.write_text("not valid json{") # Should raise JSONDecodeError or return error dict try: result = adaptor.upload(invalid_file) # If it returns a dict, it should indicate failure assert result['success'] is False except json.JSONDecodeError: # This is also acceptable pass def test_weaviate_handles_invalid_json(self, tmp_path): """Test Weaviate upload handles invalid JSON gracefully.""" adaptor = get_adaptor('weaviate') invalid_file = tmp_path / "invalid.json" invalid_file.write_text("not valid json{") # Should raise JSONDecodeError or return error dict try: result = adaptor.upload(invalid_file) # If it returns a dict, it should indicate failure assert result['success'] is False except json.JSONDecodeError: # This is also acceptable pass