chore: fixed imports and tests configuration
This commit is contained in:
@@ -41,10 +41,6 @@ docs/
|
|||||||
*.md
|
*.md
|
||||||
!README.md
|
!README.md
|
||||||
|
|
||||||
# Tests
|
|
||||||
tests/
|
|
||||||
pytest.ini
|
|
||||||
|
|
||||||
# Data (will be mounted as volumes)
|
# Data (will be mounted as volumes)
|
||||||
memory_data/
|
memory_data/
|
||||||
logs/
|
logs/
|
||||||
|
|||||||
16
Dockerfile
16
Dockerfile
@@ -59,12 +59,8 @@ RUN --mount=type=cache,target=/root/.cache/pip \
|
|||||||
uv pip install --system -e .[dev]; \
|
uv pip install --system -e .[dev]; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
COPY alfred/agent/ ./agent/
|
COPY alfred/ ./alfred
|
||||||
COPY alfred/application/ ./application/
|
COPY tests/ ./tests
|
||||||
COPY alfred/domain/ ./domain/
|
|
||||||
COPY alfred/infrastructure/ ./infrastructure/
|
|
||||||
COPY alfred/app.py .
|
|
||||||
COPY tests/ ./tests/
|
|
||||||
|
|
||||||
# ===========================================
|
# ===========================================
|
||||||
# Stage 3: Runtime
|
# Stage 3: Runtime
|
||||||
@@ -96,18 +92,14 @@ RUN mkdir -p /data/memory /data/logs \
|
|||||||
USER appuser
|
USER appuser
|
||||||
|
|
||||||
# Set working directory (owned by appuser)
|
# Set working directory (owned by appuser)
|
||||||
WORKDIR /home/appuser/app
|
WORKDIR /home/appuser
|
||||||
|
|
||||||
# Copy Python packages from builder stage
|
# Copy Python packages from builder stage
|
||||||
COPY --from=builder /usr/local/lib/python${PYTHON_VERSION_SHORT}/site-packages /usr/local/lib/python${PYTHON_VERSION_SHORT}/site-packages
|
COPY --from=builder /usr/local/lib/python${PYTHON_VERSION_SHORT}/site-packages /usr/local/lib/python${PYTHON_VERSION_SHORT}/site-packages
|
||||||
COPY --from=builder /usr/local/bin /usr/local/bin
|
COPY --from=builder /usr/local/bin /usr/local/bin
|
||||||
|
|
||||||
# Copy application code (already owned by appuser)
|
# Copy application code (already owned by appuser)
|
||||||
COPY --chown=appuser:appuser alfred/agent/ ./agent/
|
COPY --chown=appuser:appuser alfred/ ./alfred
|
||||||
COPY --chown=appuser:appuser alfred/application/ ./application/
|
|
||||||
COPY --chown=appuser:appuser alfred/domain/ ./domain/
|
|
||||||
COPY --chown=appuser:appuser alfred/infrastructure/ ./infrastructure/
|
|
||||||
COPY --chown=appuser:appuser alfred/app.py .
|
|
||||||
|
|
||||||
# Create volumes for persistent data
|
# Create volumes for persistent data
|
||||||
VOLUME ["/data/memory", "/data/logs"]
|
VOLUME ["/data/memory", "/data/logs"]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import logging
|
|||||||
from collections.abc import AsyncGenerator
|
from collections.abc import AsyncGenerator
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from infrastructure.persistence import get_memory
|
from alfred.infrastructure.persistence import get_memory
|
||||||
|
|
||||||
from .config import settings
|
from .config import settings
|
||||||
from .prompts import PromptBuilder
|
from .prompts import PromptBuilder
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import json
|
import json
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from infrastructure.persistence import get_memory
|
from alfred.infrastructure.persistence import get_memory
|
||||||
|
|
||||||
from .registry import Tool
|
from .registry import Tool
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from application.movies import SearchMovieUseCase
|
from alfred.application.movies import SearchMovieUseCase
|
||||||
from application.torrents import AddTorrentUseCase, SearchTorrentsUseCase
|
from alfred.application.torrents import AddTorrentUseCase, SearchTorrentsUseCase
|
||||||
from infrastructure.api.knaben import knaben_client
|
from alfred.infrastructure.api.knaben import knaben_client
|
||||||
from infrastructure.api.qbittorrent import qbittorrent_client
|
from alfred.infrastructure.api.qbittorrent import qbittorrent_client
|
||||||
from infrastructure.api.tmdb import tmdb_client
|
from alfred.infrastructure.api.tmdb import tmdb_client
|
||||||
from infrastructure.persistence import get_memory
|
from alfred.infrastructure.persistence import get_memory
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from application.filesystem import ListFolderUseCase, SetFolderPathUseCase
|
from alfred.application.filesystem import ListFolderUseCase, SetFolderPathUseCase
|
||||||
from infrastructure.filesystem import FileManager
|
from alfred.infrastructure.filesystem import FileManager
|
||||||
|
|
||||||
|
|
||||||
def set_path_for_folder(folder_name: str, path_value: str) -> dict[str, Any]:
|
def set_path_for_folder(folder_name: str, path_value: str) -> dict[str, Any]:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from infrastructure.persistence import get_memory
|
from alfred.infrastructure.persistence import get_memory
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -5,19 +5,18 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from fastapi import FastAPI, HTTPException
|
from fastapi import FastAPI, HTTPException
|
||||||
from fastapi.responses import JSONResponse, StreamingResponse
|
from fastapi.responses import JSONResponse, StreamingResponse
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from pydantic import BaseModel, Field, validator
|
from pydantic import BaseModel, Field, validator
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from agent.agent import Agent
|
from alfred.agent.agent import Agent
|
||||||
from agent.config import settings
|
from alfred.agent.config import settings
|
||||||
from agent.llm.deepseek import DeepSeekClient
|
from alfred.agent.llm.deepseek import DeepSeekClient
|
||||||
from agent.llm.exceptions import LLMAPIError, LLMConfigurationError
|
from alfred.agent.llm.exceptions import LLMAPIError, LLMConfigurationError
|
||||||
from agent.llm.ollama import OllamaClient
|
from alfred.agent.llm.ollama import OllamaClient
|
||||||
from infrastructure.persistence import get_memory, init_memory
|
from alfred.infrastructure.persistence import get_memory, init_memory
|
||||||
|
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from infrastructure.filesystem import FileManager
|
from alfred.infrastructure.filesystem import FileManager
|
||||||
|
|
||||||
from .dto import ListFolderResponse
|
from .dto import ListFolderResponse
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from infrastructure.filesystem import FileManager
|
from alfred.infrastructure.filesystem import FileManager
|
||||||
|
|
||||||
from .dto import SetFolderPathResponse
|
from .dto import SetFolderPathResponse
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from infrastructure.api.tmdb import (
|
from alfred.infrastructure.api.tmdb import (
|
||||||
TMDBAPIError,
|
TMDBAPIError,
|
||||||
TMDBClient,
|
TMDBClient,
|
||||||
TMDBConfigurationError,
|
TMDBConfigurationError,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from infrastructure.api.qbittorrent import (
|
from alfred.infrastructure.api.qbittorrent import (
|
||||||
QBittorrentAPIError,
|
QBittorrentAPIError,
|
||||||
QBittorrentAuthError,
|
QBittorrentAuthError,
|
||||||
QBittorrentClient,
|
QBittorrentClient,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from infrastructure.api.knaben import KnabenAPIError, KnabenClient, KnabenNotFoundError
|
from alfred.infrastructure.api.knaben import KnabenAPIError, KnabenClient, KnabenNotFoundError
|
||||||
|
|
||||||
from .dto import SearchTorrentsResponse
|
from .dto import SearchTorrentsResponse
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
"""Knaben torrent search API client."""
|
"""Knaben torrent search API client."""
|
||||||
|
|
||||||
import logging
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
|
import logging
|
||||||
import requests
|
import requests
|
||||||
from requests.exceptions import HTTPError, RequestException, Timeout
|
from requests.exceptions import HTTPError, RequestException, Timeout
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from agent.config import Settings, settings
|
from alfred.agent.config import Settings, settings
|
||||||
|
|
||||||
from .dto import TorrentResult
|
from .dto import TorrentResult
|
||||||
from .exceptions import KnabenAPIError, KnabenNotFoundError
|
from .exceptions import KnabenAPIError, KnabenNotFoundError
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
"""qBittorrent Web API client."""
|
"""qBittorrent Web API client."""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from requests.exceptions import HTTPError, RequestException, Timeout
|
from requests.exceptions import HTTPError, RequestException, Timeout
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from agent.config import Settings, settings
|
from alfred.agent.config import Settings, settings
|
||||||
|
|
||||||
from .dto import TorrentInfo
|
from .dto import TorrentInfo
|
||||||
from .exceptions import QBittorrentAPIError, QBittorrentAuthError
|
from .exceptions import QBittorrentAPIError, QBittorrentAuthError
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
"""TMDB (The Movie Database) API client."""
|
"""TMDB (The Movie Database) API client."""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from requests.exceptions import HTTPError, RequestException, Timeout
|
from requests.exceptions import HTTPError, RequestException, Timeout
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from agent.config import Settings, settings
|
|
||||||
|
|
||||||
|
from alfred.agent.config import Settings, settings
|
||||||
from .dto import MediaResult
|
from .dto import MediaResult
|
||||||
from .exceptions import (
|
from .exceptions import (
|
||||||
TMDBAPIError,
|
TMDBAPIError,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from enum import Enum
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from infrastructure.persistence import get_memory
|
from alfred.infrastructure.persistence import get_memory
|
||||||
|
|
||||||
from .exceptions import PathTraversalError
|
from .exceptions import PathTraversalError
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from domain.movies.entities import Movie
|
from alfred.domain.movies.entities import Movie
|
||||||
from domain.tv_shows.entities import Episode, Season, TVShow
|
from alfred.domain.tv_shows.entities import Episode, Season, TVShow
|
||||||
from domain.tv_shows.value_objects import SeasonNumber
|
from alfred.domain.tv_shows.value_objects import SeasonNumber
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ without passing it explicitly through all function calls.
|
|||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
# At application startup
|
# At application startup
|
||||||
from infrastructure.persistence import init_memory, get_memory
|
from alfred.infrastructure.persistence import init_memory, get_memory
|
||||||
|
|
||||||
init_memory("memory_data")
|
init_memory("memory_data")
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import logging
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from domain.movies.entities import Movie
|
from alfred.domain.movies.entities import Movie
|
||||||
from domain.movies.repositories import MovieRepository
|
from alfred.domain.movies.repositories import MovieRepository
|
||||||
from domain.movies.value_objects import MovieTitle, Quality, ReleaseYear
|
from alfred.domain.movies.value_objects import MovieTitle, Quality, ReleaseYear
|
||||||
from domain.shared.value_objects import FilePath, FileSize, ImdbId
|
from alfred.domain.shared.value_objects import FilePath, FileSize, ImdbId
|
||||||
from infrastructure.persistence import get_memory
|
from alfred.infrastructure.persistence import get_memory
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from domain.shared.value_objects import FilePath, ImdbId
|
from alfred.domain.shared.value_objects import FilePath, ImdbId
|
||||||
from domain.subtitles.entities import Subtitle
|
from alfred.domain.subtitles.entities import Subtitle
|
||||||
from domain.subtitles.repositories import SubtitleRepository
|
from alfred.domain.subtitles.repositories import SubtitleRepository
|
||||||
from domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset
|
from alfred.domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset
|
||||||
from infrastructure.persistence import get_memory
|
from alfred.infrastructure.persistence import get_memory
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import logging
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from domain.shared.value_objects import ImdbId
|
from alfred.domain.shared.value_objects import ImdbId
|
||||||
from domain.tv_shows.entities import TVShow
|
from alfred.domain.tv_shows.entities import TVShow
|
||||||
from domain.tv_shows.repositories import TVShowRepository
|
from alfred.domain.tv_shows.repositories import TVShowRepository
|
||||||
from domain.tv_shows.value_objects import ShowStatus
|
from alfred.domain.tv_shows.value_objects import ShowStatus
|
||||||
from infrastructure.persistence import get_memory
|
from alfred.infrastructure.persistence import get_memory
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ build-backend = "poetry.core.masonry.api"
|
|||||||
[tool.pytest.ini_options]
|
[tool.pytest.ini_options]
|
||||||
# Chemins où pytest cherche les tests
|
# Chemins où pytest cherche les tests
|
||||||
testpaths = ["tests"]
|
testpaths = ["tests"]
|
||||||
|
# Ajouter le répertoire racine au PYTHONPATH pour les imports
|
||||||
|
pythonpath = ["."]
|
||||||
|
|
||||||
# Patterns de fichiers/classes/fonctions à considérer comme tests
|
# Patterns de fichiers/classes/fonctions à considérer comme tests
|
||||||
python_files = ["test_*.py"] # Fichiers commençant par "test_"
|
python_files = ["test_*.py"] # Fichiers commençant par "test_"
|
||||||
|
|||||||
@@ -1,20 +1,16 @@
|
|||||||
"""Pytest configuration and shared fixtures."""
|
"""Pytest configuration and shared fixtures."""
|
||||||
|
|
||||||
import sys
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
# TODO: Moved directory, should not be necessary anymore but need to check !!
|
# TODO: Moved directory, should not be necessary anymore but need to check !!
|
||||||
# Ajouter le dossier parent (brain) au PYTHONPATH
|
# Ajouter le dossier parent (brain) au PYTHONPATH
|
||||||
# sys.path.insert(0, str(Path(__file__).parent.parent))
|
# sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||||
|
import pytest
|
||||||
import shutil
|
import shutil
|
||||||
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest.mock import MagicMock, Mock
|
from unittest.mock import MagicMock, Mock
|
||||||
|
|
||||||
import pytest
|
from alfred.infrastructure.persistence import Memory, set_memory
|
||||||
|
|
||||||
from infrastructure.persistence import Memory, set_memory
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@@ -255,7 +251,6 @@ def mock_deepseek():
|
|||||||
def test_something(mock_deepseek):
|
def test_something(mock_deepseek):
|
||||||
# Your test code here
|
# Your test code here
|
||||||
"""
|
"""
|
||||||
import sys
|
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
|
|
||||||
# Save the original module if it exists
|
# Save the original module if it exists
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
|
|
||||||
from agent.agent import Agent
|
from alfred.agent.agent import Agent
|
||||||
from infrastructure.persistence import get_memory
|
from alfred.infrastructure.persistence import get_memory
|
||||||
|
|
||||||
|
|
||||||
class TestAgentInit:
|
class TestAgentInit:
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
"""Edge case tests for the Agent."""
|
"""Edge case tests for the Agent."""
|
||||||
|
import pytest
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
|
|
||||||
import pytest
|
from alfred.agent.agent import Agent
|
||||||
|
from alfred.infrastructure.persistence import get_memory
|
||||||
from agent.agent import Agent
|
|
||||||
from infrastructure.persistence import get_memory
|
|
||||||
|
|
||||||
|
|
||||||
class TestExecuteToolCallEdgeCases:
|
class TestExecuteToolCallEdgeCases:
|
||||||
@@ -16,7 +14,7 @@ class TestExecuteToolCallEdgeCases:
|
|||||||
agent = Agent(llm=mock_llm)
|
agent = Agent(llm=mock_llm)
|
||||||
|
|
||||||
# Mock a tool that returns None
|
# Mock a tool that returns None
|
||||||
from agent.registry import Tool
|
from alfred.agent.registry import Tool
|
||||||
|
|
||||||
agent.tools["test_tool"] = Tool(
|
agent.tools["test_tool"] = Tool(
|
||||||
name="test_tool", description="Test", func=lambda: None, parameters={}
|
name="test_tool", description="Test", func=lambda: None, parameters={}
|
||||||
@@ -34,7 +32,7 @@ class TestExecuteToolCallEdgeCases:
|
|||||||
"""Should propagate KeyboardInterrupt."""
|
"""Should propagate KeyboardInterrupt."""
|
||||||
agent = Agent(llm=mock_llm)
|
agent = Agent(llm=mock_llm)
|
||||||
|
|
||||||
from agent.registry import Tool
|
from alfred.agent.registry import Tool
|
||||||
|
|
||||||
def raise_interrupt():
|
def raise_interrupt():
|
||||||
raise KeyboardInterrupt()
|
raise KeyboardInterrupt()
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class TestHealthEndpoint:
|
|||||||
|
|
||||||
def test_health_check(self, memory):
|
def test_health_check(self, memory):
|
||||||
"""Should return healthy status."""
|
"""Should return healthy status."""
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ class TestModelsEndpoint:
|
|||||||
|
|
||||||
def test_list_models(self, memory):
|
def test_list_models(self, memory):
|
||||||
"""Should return model list."""
|
"""Should return model list."""
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ class TestMemoryEndpoints:
|
|||||||
|
|
||||||
def test_get_memory_state(self, memory):
|
def test_get_memory_state(self, memory):
|
||||||
"""Should return full memory state."""
|
"""Should return full memory state."""
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ class TestMemoryEndpoints:
|
|||||||
|
|
||||||
def test_get_search_results_empty(self, memory):
|
def test_get_search_results_empty(self, memory):
|
||||||
"""Should return empty when no search results."""
|
"""Should return empty when no search results."""
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ class TestMemoryEndpoints:
|
|||||||
|
|
||||||
def test_get_search_results_with_data(self, memory_with_search_results):
|
def test_get_search_results_with_data(self, memory_with_search_results):
|
||||||
"""Should return search results when available."""
|
"""Should return search results when available."""
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ class TestMemoryEndpoints:
|
|||||||
|
|
||||||
def test_clear_session(self, memory_with_search_results):
|
def test_clear_session(self, memory_with_search_results):
|
||||||
"""Should clear session memories."""
|
"""Should clear session memories."""
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -102,10 +102,10 @@ class TestChatCompletionsEndpoint:
|
|||||||
|
|
||||||
def test_chat_completion_success(self, memory):
|
def test_chat_completion_success(self, memory):
|
||||||
"""Should return chat completion."""
|
"""Should return chat completion."""
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
# Patch the agent's step method directly
|
# Patch the agent's step method directly
|
||||||
with patch("app.agent.step", return_value="Hello! How can I help?"):
|
with patch("alfred.app.agent.step", return_value="Hello! How can I help?"):
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
response = client.post(
|
response = client.post(
|
||||||
@@ -123,7 +123,7 @@ class TestChatCompletionsEndpoint:
|
|||||||
|
|
||||||
def test_chat_completion_no_user_message(self, memory):
|
def test_chat_completion_no_user_message(self, memory):
|
||||||
"""Should return error if no user message."""
|
"""Should return error if no user message."""
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -146,7 +146,7 @@ class TestChatCompletionsEndpoint:
|
|||||||
|
|
||||||
def test_chat_completion_empty_messages(self, memory):
|
def test_chat_completion_empty_messages(self, memory):
|
||||||
"""Should return error for empty messages."""
|
"""Should return error for empty messages."""
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ class TestChatCompletionsEndpoint:
|
|||||||
|
|
||||||
def test_chat_completion_invalid_json(self, memory):
|
def test_chat_completion_invalid_json(self, memory):
|
||||||
"""Should return error for invalid JSON."""
|
"""Should return error for invalid JSON."""
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -176,9 +176,9 @@ class TestChatCompletionsEndpoint:
|
|||||||
|
|
||||||
def test_chat_completion_streaming(self, memory):
|
def test_chat_completion_streaming(self, memory):
|
||||||
"""Should support streaming mode."""
|
"""Should support streaming mode."""
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
with patch("app.agent.step", return_value="Streaming response"):
|
with patch("alfred.app.agent.step", return_value="Streaming response"):
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
response = client.post(
|
response = client.post(
|
||||||
@@ -195,9 +195,9 @@ class TestChatCompletionsEndpoint:
|
|||||||
|
|
||||||
def test_chat_completion_extracts_last_user_message(self, memory):
|
def test_chat_completion_extracts_last_user_message(self, memory):
|
||||||
"""Should use last user message."""
|
"""Should use last user message."""
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
with patch("app.agent.step", return_value="Response") as mock_step:
|
with patch("alfred.app.agent.step", return_value="Response") as mock_step:
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
response = client.post(
|
response = client.post(
|
||||||
@@ -218,9 +218,9 @@ class TestChatCompletionsEndpoint:
|
|||||||
|
|
||||||
def test_chat_completion_response_format(self, memory):
|
def test_chat_completion_response_format(self, memory):
|
||||||
"""Should return OpenAI-compatible format."""
|
"""Should return OpenAI-compatible format."""
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
with patch("app.agent.step", return_value="Test response"):
|
with patch("alfred.app.agent.step", return_value="Test response"):
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
response = client.post(
|
response = client.post(
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ class TestChatCompletionsEdgeCases:
|
|||||||
|
|
||||||
def test_very_long_message(self, memory):
|
def test_very_long_message(self, memory):
|
||||||
"""Should handle very long user message."""
|
"""Should handle very long user message."""
|
||||||
from app import agent, app
|
from alfred.app import app
|
||||||
|
from alfred.agent import agent
|
||||||
|
|
||||||
# Patch the agent's LLM directly
|
# Patch the agent's LLM directly
|
||||||
mock_llm = Mock()
|
mock_llm = Mock()
|
||||||
@@ -32,7 +33,8 @@ class TestChatCompletionsEdgeCases:
|
|||||||
|
|
||||||
def test_unicode_message(self, memory):
|
def test_unicode_message(self, memory):
|
||||||
"""Should handle unicode in message."""
|
"""Should handle unicode in message."""
|
||||||
from app import agent, app
|
from alfred.app import app
|
||||||
|
from alfred.agent import agent
|
||||||
|
|
||||||
mock_llm = Mock()
|
mock_llm = Mock()
|
||||||
mock_llm.complete.return_value = {
|
mock_llm.complete.return_value = {
|
||||||
@@ -57,7 +59,8 @@ class TestChatCompletionsEdgeCases:
|
|||||||
|
|
||||||
def test_special_characters_in_message(self, memory):
|
def test_special_characters_in_message(self, memory):
|
||||||
"""Should handle special characters."""
|
"""Should handle special characters."""
|
||||||
from app import agent, app
|
from alfred.app import app
|
||||||
|
from alfred.agent import agent
|
||||||
|
|
||||||
mock_llm = Mock()
|
mock_llm = Mock()
|
||||||
mock_llm.complete.return_value = {"role": "assistant", "content": "Response"}
|
mock_llm.complete.return_value = {"role": "assistant", "content": "Response"}
|
||||||
@@ -78,12 +81,12 @@ class TestChatCompletionsEdgeCases:
|
|||||||
|
|
||||||
def test_empty_content_in_message(self, memory):
|
def test_empty_content_in_message(self, memory):
|
||||||
"""Should handle empty content in message."""
|
"""Should handle empty content in message."""
|
||||||
with patch("app.DeepSeekClient") as mock_llm_class:
|
with patch("alfred.app.DeepSeekClient") as mock_llm_class:
|
||||||
mock_llm = Mock()
|
mock_llm = Mock()
|
||||||
mock_llm.complete.return_value = "Response"
|
mock_llm.complete.return_value = "Response"
|
||||||
mock_llm_class.return_value = mock_llm
|
mock_llm_class.return_value = mock_llm
|
||||||
|
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -100,11 +103,11 @@ class TestChatCompletionsEdgeCases:
|
|||||||
|
|
||||||
def test_null_content_in_message(self, memory):
|
def test_null_content_in_message(self, memory):
|
||||||
"""Should handle null content in message."""
|
"""Should handle null content in message."""
|
||||||
with patch("app.DeepSeekClient") as mock_llm_class:
|
with patch("alfred.app.DeepSeekClient") as mock_llm_class:
|
||||||
mock_llm = Mock()
|
mock_llm = Mock()
|
||||||
mock_llm_class.return_value = mock_llm
|
mock_llm_class.return_value = mock_llm
|
||||||
|
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -120,11 +123,11 @@ class TestChatCompletionsEdgeCases:
|
|||||||
|
|
||||||
def test_missing_content_field(self, memory):
|
def test_missing_content_field(self, memory):
|
||||||
"""Should handle missing content field."""
|
"""Should handle missing content field."""
|
||||||
with patch("app.DeepSeekClient") as mock_llm_class:
|
with patch("alfred.app.DeepSeekClient") as mock_llm_class:
|
||||||
mock_llm = Mock()
|
mock_llm = Mock()
|
||||||
mock_llm_class.return_value = mock_llm
|
mock_llm_class.return_value = mock_llm
|
||||||
|
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -141,11 +144,11 @@ class TestChatCompletionsEdgeCases:
|
|||||||
|
|
||||||
def test_missing_role_field(self, memory):
|
def test_missing_role_field(self, memory):
|
||||||
"""Should handle missing role field."""
|
"""Should handle missing role field."""
|
||||||
with patch("app.DeepSeekClient") as mock_llm_class:
|
with patch("alfred.app.DeepSeekClient") as mock_llm_class:
|
||||||
mock_llm = Mock()
|
mock_llm = Mock()
|
||||||
mock_llm_class.return_value = mock_llm
|
mock_llm_class.return_value = mock_llm
|
||||||
|
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -162,12 +165,12 @@ class TestChatCompletionsEdgeCases:
|
|||||||
|
|
||||||
def test_invalid_role(self, memory):
|
def test_invalid_role(self, memory):
|
||||||
"""Should handle invalid role."""
|
"""Should handle invalid role."""
|
||||||
with patch("app.DeepSeekClient") as mock_llm_class:
|
with patch("alfred.app.DeepSeekClient") as mock_llm_class:
|
||||||
mock_llm = Mock()
|
mock_llm = Mock()
|
||||||
mock_llm.complete.return_value = "Response"
|
mock_llm.complete.return_value = "Response"
|
||||||
mock_llm_class.return_value = mock_llm
|
mock_llm_class.return_value = mock_llm
|
||||||
|
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -184,7 +187,8 @@ class TestChatCompletionsEdgeCases:
|
|||||||
|
|
||||||
def test_many_messages(self, memory):
|
def test_many_messages(self, memory):
|
||||||
"""Should handle many messages in conversation."""
|
"""Should handle many messages in conversation."""
|
||||||
from app import agent, app
|
from alfred.app import app
|
||||||
|
from alfred.agent import agent
|
||||||
|
|
||||||
mock_llm = Mock()
|
mock_llm = Mock()
|
||||||
mock_llm.complete.return_value = {"role": "assistant", "content": "Response"}
|
mock_llm.complete.return_value = {"role": "assistant", "content": "Response"}
|
||||||
@@ -210,11 +214,11 @@ class TestChatCompletionsEdgeCases:
|
|||||||
|
|
||||||
def test_only_system_messages(self, memory):
|
def test_only_system_messages(self, memory):
|
||||||
"""Should reject if only system messages."""
|
"""Should reject if only system messages."""
|
||||||
with patch("app.DeepSeekClient") as mock_llm_class:
|
with patch("alfred.app.DeepSeekClient") as mock_llm_class:
|
||||||
mock_llm = Mock()
|
mock_llm = Mock()
|
||||||
mock_llm_class.return_value = mock_llm
|
mock_llm_class.return_value = mock_llm
|
||||||
|
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -233,11 +237,11 @@ class TestChatCompletionsEdgeCases:
|
|||||||
|
|
||||||
def test_only_assistant_messages(self, memory):
|
def test_only_assistant_messages(self, memory):
|
||||||
"""Should reject if only assistant messages."""
|
"""Should reject if only assistant messages."""
|
||||||
with patch("app.DeepSeekClient") as mock_llm_class:
|
with patch("alfred.app.DeepSeekClient") as mock_llm_class:
|
||||||
mock_llm = Mock()
|
mock_llm = Mock()
|
||||||
mock_llm_class.return_value = mock_llm
|
mock_llm_class.return_value = mock_llm
|
||||||
|
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -255,11 +259,11 @@ class TestChatCompletionsEdgeCases:
|
|||||||
|
|
||||||
def test_messages_not_array(self, memory):
|
def test_messages_not_array(self, memory):
|
||||||
"""Should reject if messages is not array."""
|
"""Should reject if messages is not array."""
|
||||||
with patch("app.DeepSeekClient") as mock_llm_class:
|
with patch("alfred.app.DeepSeekClient") as mock_llm_class:
|
||||||
mock_llm = Mock()
|
mock_llm = Mock()
|
||||||
mock_llm_class.return_value = mock_llm
|
mock_llm_class.return_value = mock_llm
|
||||||
|
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -276,11 +280,11 @@ class TestChatCompletionsEdgeCases:
|
|||||||
|
|
||||||
def test_message_not_object(self, memory):
|
def test_message_not_object(self, memory):
|
||||||
"""Should handle message that is not object."""
|
"""Should handle message that is not object."""
|
||||||
with patch("app.DeepSeekClient") as mock_llm_class:
|
with patch("alfred.app.DeepSeekClient") as mock_llm_class:
|
||||||
mock_llm = Mock()
|
mock_llm = Mock()
|
||||||
mock_llm_class.return_value = mock_llm
|
mock_llm_class.return_value = mock_llm
|
||||||
|
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -297,7 +301,8 @@ class TestChatCompletionsEdgeCases:
|
|||||||
|
|
||||||
def test_extra_fields_in_request(self, memory):
|
def test_extra_fields_in_request(self, memory):
|
||||||
"""Should ignore extra fields in request."""
|
"""Should ignore extra fields in request."""
|
||||||
from app import agent, app
|
from alfred.app import app
|
||||||
|
from alfred.agent import agent
|
||||||
|
|
||||||
mock_llm = Mock()
|
mock_llm = Mock()
|
||||||
mock_llm.complete.return_value = {"role": "assistant", "content": "Response"}
|
mock_llm.complete.return_value = {"role": "assistant", "content": "Response"}
|
||||||
@@ -320,8 +325,9 @@ class TestChatCompletionsEdgeCases:
|
|||||||
|
|
||||||
def test_streaming_with_tool_call(self, memory, real_folder):
|
def test_streaming_with_tool_call(self, memory, real_folder):
|
||||||
"""Should handle streaming with tool execution."""
|
"""Should handle streaming with tool execution."""
|
||||||
from app import agent, app
|
from alfred.app import app
|
||||||
from infrastructure.persistence import get_memory
|
from alfred.agent import agent
|
||||||
|
from alfred.infrastructure.persistence import get_memory
|
||||||
|
|
||||||
mem = get_memory()
|
mem = get_memory()
|
||||||
mem.ltm.set_config("download_folder", str(real_folder["downloads"]))
|
mem.ltm.set_config("download_folder", str(real_folder["downloads"]))
|
||||||
@@ -365,7 +371,8 @@ class TestChatCompletionsEdgeCases:
|
|||||||
|
|
||||||
def test_concurrent_requests_simulation(self, memory):
|
def test_concurrent_requests_simulation(self, memory):
|
||||||
"""Should handle rapid sequential requests."""
|
"""Should handle rapid sequential requests."""
|
||||||
from app import agent, app
|
from alfred.app import app
|
||||||
|
from alfred.agent import agent
|
||||||
|
|
||||||
mock_llm = Mock()
|
mock_llm = Mock()
|
||||||
mock_llm.complete.return_value = {"role": "assistant", "content": "Response"}
|
mock_llm.complete.return_value = {"role": "assistant", "content": "Response"}
|
||||||
@@ -385,7 +392,8 @@ class TestChatCompletionsEdgeCases:
|
|||||||
|
|
||||||
def test_llm_returns_json_in_response(self, memory):
|
def test_llm_returns_json_in_response(self, memory):
|
||||||
"""Should handle LLM returning JSON in text response."""
|
"""Should handle LLM returning JSON in text response."""
|
||||||
from app import agent, app
|
from alfred.app import app
|
||||||
|
from alfred.agent import agent
|
||||||
|
|
||||||
mock_llm = Mock()
|
mock_llm = Mock()
|
||||||
mock_llm.complete.return_value = {
|
mock_llm.complete.return_value = {
|
||||||
@@ -414,9 +422,9 @@ class TestMemoryEndpointsEdgeCases:
|
|||||||
|
|
||||||
def test_memory_state_with_large_data(self, memory):
|
def test_memory_state_with_large_data(self, memory):
|
||||||
"""Should handle large memory state."""
|
"""Should handle large memory state."""
|
||||||
with patch("app.DeepSeekClient") as mock_llm:
|
with patch("alfred.app.DeepSeekClient") as mock_llm:
|
||||||
mock_llm.return_value = Mock()
|
mock_llm.return_value = Mock()
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
# Add lots of data to memory
|
# Add lots of data to memory
|
||||||
for i in range(100):
|
for i in range(100):
|
||||||
@@ -432,9 +440,9 @@ class TestMemoryEndpointsEdgeCases:
|
|||||||
|
|
||||||
def test_memory_state_with_unicode(self, memory):
|
def test_memory_state_with_unicode(self, memory):
|
||||||
"""Should handle unicode in memory state."""
|
"""Should handle unicode in memory state."""
|
||||||
with patch("app.DeepSeekClient") as mock_llm:
|
with patch("alfred.app.DeepSeekClient") as mock_llm:
|
||||||
mock_llm.return_value = Mock()
|
mock_llm.return_value = Mock()
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
memory.ltm.set_config("japanese", "日本語テスト")
|
memory.ltm.set_config("japanese", "日本語テスト")
|
||||||
memory.stm.add_message("user", "🎬 Movie request")
|
memory.stm.add_message("user", "🎬 Movie request")
|
||||||
@@ -448,9 +456,9 @@ class TestMemoryEndpointsEdgeCases:
|
|||||||
|
|
||||||
def test_search_results_with_special_chars(self, memory):
|
def test_search_results_with_special_chars(self, memory):
|
||||||
"""Should handle special characters in search results."""
|
"""Should handle special characters in search results."""
|
||||||
with patch("app.DeepSeekClient") as mock_llm:
|
with patch("alfred.app.DeepSeekClient") as mock_llm:
|
||||||
mock_llm.return_value = Mock()
|
mock_llm.return_value = Mock()
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
memory.episodic.store_search_results(
|
memory.episodic.store_search_results(
|
||||||
"Test <script>alert('xss')</script>",
|
"Test <script>alert('xss')</script>",
|
||||||
@@ -467,9 +475,9 @@ class TestMemoryEndpointsEdgeCases:
|
|||||||
|
|
||||||
def test_clear_session_idempotent(self, memory):
|
def test_clear_session_idempotent(self, memory):
|
||||||
"""Should be idempotent - multiple clears should work."""
|
"""Should be idempotent - multiple clears should work."""
|
||||||
with patch("app.DeepSeekClient") as mock_llm:
|
with patch("alfred.app.DeepSeekClient") as mock_llm:
|
||||||
mock_llm.return_value = Mock()
|
mock_llm.return_value = Mock()
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -480,9 +488,9 @@ class TestMemoryEndpointsEdgeCases:
|
|||||||
|
|
||||||
def test_clear_session_preserves_ltm(self, memory):
|
def test_clear_session_preserves_ltm(self, memory):
|
||||||
"""Should preserve LTM after clear."""
|
"""Should preserve LTM after clear."""
|
||||||
with patch("app.DeepSeekClient") as mock_llm:
|
with patch("alfred.app.DeepSeekClient") as mock_llm:
|
||||||
mock_llm.return_value = Mock()
|
mock_llm.return_value = Mock()
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
memory.ltm.set_config("important", "data")
|
memory.ltm.set_config("important", "data")
|
||||||
memory.stm.add_message("user", "Hello")
|
memory.stm.add_message("user", "Hello")
|
||||||
@@ -502,9 +510,9 @@ class TestHealthEndpointEdgeCases:
|
|||||||
|
|
||||||
def test_health_returns_version(self, memory):
|
def test_health_returns_version(self, memory):
|
||||||
"""Should return version in health check."""
|
"""Should return version in health check."""
|
||||||
with patch("app.DeepSeekClient") as mock_llm:
|
with patch("alfred.app.DeepSeekClient") as mock_llm:
|
||||||
mock_llm.return_value = Mock()
|
mock_llm.return_value = Mock()
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -515,9 +523,9 @@ class TestHealthEndpointEdgeCases:
|
|||||||
|
|
||||||
def test_health_with_query_params(self, memory):
|
def test_health_with_query_params(self, memory):
|
||||||
"""Should ignore query parameters."""
|
"""Should ignore query parameters."""
|
||||||
with patch("app.DeepSeekClient") as mock_llm:
|
with patch("alfred.app.DeepSeekClient") as mock_llm:
|
||||||
mock_llm.return_value = Mock()
|
mock_llm.return_value = Mock()
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
@@ -531,9 +539,9 @@ class TestModelsEndpointEdgeCases:
|
|||||||
|
|
||||||
def test_models_response_format(self, memory):
|
def test_models_response_format(self, memory):
|
||||||
"""Should return OpenAI-compatible format."""
|
"""Should return OpenAI-compatible format."""
|
||||||
with patch("app.DeepSeekClient") as mock_llm:
|
with patch("alfred.app.DeepSeekClient") as mock_llm:
|
||||||
mock_llm.return_value = Mock()
|
mock_llm.return_value = Mock()
|
||||||
from app import app
|
from alfred.app import app
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
"""Critical tests for configuration validation."""
|
"""Critical tests for configuration validation."""
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from agent.config import ConfigurationError, Settings
|
from alfred.agent.config import ConfigurationError, Settings
|
||||||
|
|
||||||
|
|
||||||
class TestConfigValidation:
|
class TestConfigValidation:
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
"""Edge case tests for configuration and parameters."""
|
"""Edge case tests for configuration and parameters."""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import pytest
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import pytest
|
from alfred.agent.config import ConfigurationError, Settings
|
||||||
|
from alfred.agent.parameters import (
|
||||||
from agent.config import ConfigurationError, Settings
|
|
||||||
from agent.parameters import (
|
|
||||||
REQUIRED_PARAMETERS,
|
REQUIRED_PARAMETERS,
|
||||||
ParameterSchema,
|
ParameterSchema,
|
||||||
format_parameters_for_prompt,
|
format_parameters_for_prompt,
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
"""Edge case tests for domain entities and value objects."""
|
"""Edge case tests for domain entities and value objects."""
|
||||||
|
import pytest
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import pytest
|
from alfred.domain.movies.entities import Movie
|
||||||
|
from alfred.domain.movies.value_objects import MovieTitle, Quality, ReleaseYear
|
||||||
from domain.movies.entities import Movie
|
from alfred.domain.shared.exceptions import ValidationError
|
||||||
from domain.movies.value_objects import MovieTitle, Quality, ReleaseYear
|
from alfred.domain.shared.value_objects import FilePath, FileSize, ImdbId
|
||||||
from domain.shared.exceptions import ValidationError
|
from alfred.domain.subtitles.entities import Subtitle
|
||||||
from domain.shared.value_objects import FilePath, FileSize, ImdbId
|
from alfred.domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset
|
||||||
from domain.subtitles.entities import Subtitle
|
from alfred.domain.tv_shows.entities import TVShow
|
||||||
from domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset
|
from alfred.domain.tv_shows.value_objects import ShowStatus
|
||||||
from domain.tv_shows.entities import TVShow
|
|
||||||
from domain.tv_shows.value_objects import ShowStatus
|
|
||||||
|
|
||||||
|
|
||||||
class TestImdbIdEdgeCases:
|
class TestImdbIdEdgeCases:
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
"""Tests for the Memory system."""
|
"""Tests for the Memory system."""
|
||||||
|
import pytest
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import pytest
|
from alfred.infrastructure.persistence import (
|
||||||
|
|
||||||
from infrastructure.persistence import (
|
|
||||||
EpisodicMemory,
|
EpisodicMemory,
|
||||||
LongTermMemory,
|
LongTermMemory,
|
||||||
Memory,
|
Memory,
|
||||||
@@ -13,7 +11,7 @@ from infrastructure.persistence import (
|
|||||||
has_memory,
|
has_memory,
|
||||||
init_memory,
|
init_memory,
|
||||||
)
|
)
|
||||||
from infrastructure.persistence.context import _memory_ctx
|
from alfred.infrastructure.persistence.context import _memory_ctx
|
||||||
|
|
||||||
|
|
||||||
def is_iso_format(s: str) -> bool:
|
def is_iso_format(s: str) -> bool:
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from alfred.infrastructure.persistence import (
|
||||||
from infrastructure.persistence import (
|
|
||||||
EpisodicMemory,
|
EpisodicMemory,
|
||||||
LongTermMemory,
|
LongTermMemory,
|
||||||
Memory,
|
Memory,
|
||||||
@@ -14,7 +13,7 @@ from infrastructure.persistence import (
|
|||||||
init_memory,
|
init_memory,
|
||||||
set_memory,
|
set_memory,
|
||||||
)
|
)
|
||||||
from infrastructure.persistence.context import _memory_ctx
|
from alfred.infrastructure.persistence.context import _memory_ctx
|
||||||
|
|
||||||
|
|
||||||
class TestLongTermMemoryEdgeCases:
|
class TestLongTermMemoryEdgeCases:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""Tests for PromptBuilder."""
|
"""Tests for PromptBuilder."""
|
||||||
|
|
||||||
from agent.prompts import PromptBuilder
|
from alfred.agent.prompts import PromptBuilder
|
||||||
from agent.registry import make_tools
|
from alfred.agent.registry import make_tools
|
||||||
|
|
||||||
|
|
||||||
class TestPromptBuilder:
|
class TestPromptBuilder:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""Critical tests for prompt builder - Tests that would have caught bugs."""
|
"""Critical tests for prompt builder - Tests that would have caught bugs."""
|
||||||
|
|
||||||
from agent.prompts import PromptBuilder
|
from alfred.agent.prompts import PromptBuilder
|
||||||
from agent.registry import make_tools
|
from alfred.agent.registry import make_tools
|
||||||
|
|
||||||
|
|
||||||
class TestPromptBuilderToolsInjection:
|
class TestPromptBuilderToolsInjection:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""Edge case tests for PromptBuilder."""
|
"""Edge case tests for PromptBuilder."""
|
||||||
|
|
||||||
from agent.prompts import PromptBuilder
|
from alfred.agent.prompts import PromptBuilder
|
||||||
from agent.registry import make_tools
|
from alfred.agent.registry import make_tools
|
||||||
|
|
||||||
|
|
||||||
class TestPromptBuilderEdgeCases:
|
class TestPromptBuilderEdgeCases:
|
||||||
@@ -266,7 +266,7 @@ class TestFormatToolsDescriptionEdgeCases:
|
|||||||
|
|
||||||
def test_format_with_complex_parameters(self, memory):
|
def test_format_with_complex_parameters(self, memory):
|
||||||
"""Should format complex parameter schemas."""
|
"""Should format complex parameter schemas."""
|
||||||
from agent.registry import Tool
|
from alfred.agent.registry import Tool
|
||||||
|
|
||||||
tools = {
|
tools = {
|
||||||
"complex_tool": Tool(
|
"complex_tool": Tool(
|
||||||
|
|||||||
@@ -3,9 +3,8 @@
|
|||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from alfred.agent.prompts import PromptBuilder
|
||||||
from agent.prompts import PromptBuilder
|
from alfred.agent.registry import Tool, _create_tool_from_function, make_tools
|
||||||
from agent.registry import Tool, _create_tool_from_function, make_tools
|
|
||||||
|
|
||||||
|
|
||||||
class TestToolSpecFormat:
|
class TestToolSpecFormat:
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
"""Edge case tests for tool registry."""
|
"""Edge case tests for tool registry."""
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from alfred.agent.registry import Tool, make_tools
|
||||||
from agent.registry import Tool, make_tools
|
|
||||||
|
|
||||||
|
|
||||||
class TestToolEdgeCases:
|
class TestToolEdgeCases:
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
"""Tests for JSON repositories."""
|
"""Tests for JSON repositories."""
|
||||||
|
|
||||||
from domain.movies.entities import Movie
|
from alfred.domain.movies.entities import Movie
|
||||||
from domain.movies.value_objects import MovieTitle, Quality, ReleaseYear
|
from alfred.domain.movies.value_objects import MovieTitle, Quality, ReleaseYear
|
||||||
from domain.shared.value_objects import FilePath, FileSize, ImdbId
|
from alfred.domain.shared.value_objects import FilePath, FileSize, ImdbId
|
||||||
from domain.subtitles.entities import Subtitle
|
from alfred.domain.subtitles.entities import Subtitle
|
||||||
from domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset
|
from alfred.domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset
|
||||||
from domain.tv_shows.entities import TVShow
|
from alfred.domain.tv_shows.entities import TVShow
|
||||||
from domain.tv_shows.value_objects import ShowStatus
|
from alfred.domain.tv_shows.value_objects import ShowStatus
|
||||||
from infrastructure.persistence.json import (
|
from alfred.infrastructure.persistence.json import (
|
||||||
JsonMovieRepository,
|
JsonMovieRepository,
|
||||||
JsonSubtitleRepository,
|
JsonSubtitleRepository,
|
||||||
JsonTVShowRepository,
|
JsonTVShowRepository,
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from domain.movies.entities import Movie
|
from alfred.domain.movies.entities import Movie
|
||||||
from domain.movies.value_objects import MovieTitle, Quality
|
from alfred.domain.movies.value_objects import MovieTitle, Quality
|
||||||
from domain.shared.value_objects import FilePath, FileSize, ImdbId
|
from alfred.domain.shared.value_objects import FilePath, FileSize, ImdbId
|
||||||
from domain.subtitles.entities import Subtitle
|
from alfred.domain.subtitles.entities import Subtitle
|
||||||
from domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset
|
from alfred.domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset
|
||||||
from domain.tv_shows.entities import TVShow
|
from alfred.domain.tv_shows.entities import TVShow
|
||||||
from domain.tv_shows.value_objects import ShowStatus
|
from alfred.domain.tv_shows.value_objects import ShowStatus
|
||||||
from infrastructure.persistence.json import (
|
from alfred.infrastructure.persistence.json import (
|
||||||
JsonMovieRepository,
|
JsonMovieRepository,
|
||||||
JsonSubtitleRepository,
|
JsonSubtitleRepository,
|
||||||
JsonTVShowRepository,
|
JsonTVShowRepository,
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
from unittest.mock import Mock, patch
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
from agent.tools import api as api_tools
|
from alfred.agent.tools import api as api_tools
|
||||||
from infrastructure.persistence import get_memory
|
from alfred.infrastructure.persistence import get_memory
|
||||||
|
|
||||||
|
|
||||||
def create_mock_response(status_code, json_data=None, text=None):
|
def create_mock_response(status_code, json_data=None, text=None):
|
||||||
@@ -21,7 +21,7 @@ def create_mock_response(status_code, json_data=None, text=None):
|
|||||||
class TestFindMediaImdbId:
|
class TestFindMediaImdbId:
|
||||||
"""Tests for find_media_imdb_id tool."""
|
"""Tests for find_media_imdb_id tool."""
|
||||||
|
|
||||||
@patch("infrastructure.api.tmdb.client.requests.get")
|
@patch("alfred.infrastructure.api.tmdb.client.requests.get")
|
||||||
def test_success(self, mock_get, memory):
|
def test_success(self, mock_get, memory):
|
||||||
"""Should return movie info on success."""
|
"""Should return movie info on success."""
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ class TestFindMediaImdbId:
|
|||||||
# Verify HTTP calls
|
# Verify HTTP calls
|
||||||
assert mock_get.call_count == 2
|
assert mock_get.call_count == 2
|
||||||
|
|
||||||
@patch("infrastructure.api.tmdb.client.requests.get")
|
@patch("alfred.infrastructure.api.tmdb.client.requests.get")
|
||||||
def test_stores_in_stm(self, mock_get, memory):
|
def test_stores_in_stm(self, mock_get, memory):
|
||||||
"""Should store result in STM on success."""
|
"""Should store result in STM on success."""
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ class TestFindMediaImdbId:
|
|||||||
assert entity["title"] == "Inception"
|
assert entity["title"] == "Inception"
|
||||||
assert mem.stm.current_topic == "searching_media"
|
assert mem.stm.current_topic == "searching_media"
|
||||||
|
|
||||||
@patch("infrastructure.api.tmdb.client.requests.get")
|
@patch("alfred.infrastructure.api.tmdb.client.requests.get")
|
||||||
def test_not_found(self, mock_get, memory):
|
def test_not_found(self, mock_get, memory):
|
||||||
"""Should return error when not found."""
|
"""Should return error when not found."""
|
||||||
mock_get.return_value = create_mock_response(200, json_data={"results": []})
|
mock_get.return_value = create_mock_response(200, json_data={"results": []})
|
||||||
@@ -98,7 +98,7 @@ class TestFindMediaImdbId:
|
|||||||
assert result["status"] == "error"
|
assert result["status"] == "error"
|
||||||
assert result["error"] == "not_found"
|
assert result["error"] == "not_found"
|
||||||
|
|
||||||
@patch("infrastructure.api.tmdb.client.requests.get")
|
@patch("alfred.infrastructure.api.tmdb.client.requests.get")
|
||||||
def test_does_not_store_on_error(self, mock_get, memory):
|
def test_does_not_store_on_error(self, mock_get, memory):
|
||||||
"""Should not store in STM on error."""
|
"""Should not store in STM on error."""
|
||||||
mock_get.return_value = create_mock_response(200, json_data={"results": []})
|
mock_get.return_value = create_mock_response(200, json_data={"results": []})
|
||||||
@@ -112,7 +112,7 @@ class TestFindMediaImdbId:
|
|||||||
class TestFindTorrent:
|
class TestFindTorrent:
|
||||||
"""Tests for find_torrent tool."""
|
"""Tests for find_torrent tool."""
|
||||||
|
|
||||||
@patch("infrastructure.api.knaben.client.requests.post")
|
@patch("alfred.infrastructure.api.knaben.client.requests.post")
|
||||||
def test_success(self, mock_post, memory):
|
def test_success(self, mock_post, memory):
|
||||||
"""Should return torrents on success."""
|
"""Should return torrents on success."""
|
||||||
mock_post.return_value = create_mock_response(
|
mock_post.return_value = create_mock_response(
|
||||||
@@ -146,7 +146,7 @@ class TestFindTorrent:
|
|||||||
payload = mock_post.call_args[1]["json"]
|
payload = mock_post.call_args[1]["json"]
|
||||||
assert payload["query"] == "Inception 1080p"
|
assert payload["query"] == "Inception 1080p"
|
||||||
|
|
||||||
@patch("infrastructure.api.knaben.client.requests.post")
|
@patch("alfred.infrastructure.api.knaben.client.requests.post")
|
||||||
def test_stores_in_episodic(self, mock_post, memory):
|
def test_stores_in_episodic(self, mock_post, memory):
|
||||||
"""Should store results in episodic memory."""
|
"""Should store results in episodic memory."""
|
||||||
mock_post.return_value = create_mock_response(
|
mock_post.return_value = create_mock_response(
|
||||||
@@ -171,7 +171,7 @@ class TestFindTorrent:
|
|||||||
assert mem.episodic.last_search_results["query"] == "Inception"
|
assert mem.episodic.last_search_results["query"] == "Inception"
|
||||||
assert mem.stm.current_topic == "selecting_torrent"
|
assert mem.stm.current_topic == "selecting_torrent"
|
||||||
|
|
||||||
@patch("infrastructure.api.knaben.client.requests.post")
|
@patch("alfred.infrastructure.api.knaben.client.requests.post")
|
||||||
def test_results_have_indexes(self, mock_post, memory):
|
def test_results_have_indexes(self, mock_post, memory):
|
||||||
"""Should add indexes to results."""
|
"""Should add indexes to results."""
|
||||||
mock_post.return_value = create_mock_response(
|
mock_post.return_value = create_mock_response(
|
||||||
@@ -211,7 +211,7 @@ class TestFindTorrent:
|
|||||||
assert results[1]["index"] == 2
|
assert results[1]["index"] == 2
|
||||||
assert results[2]["index"] == 3
|
assert results[2]["index"] == 3
|
||||||
|
|
||||||
@patch("infrastructure.api.knaben.client.requests.post")
|
@patch("alfred.infrastructure.api.knaben.client.requests.post")
|
||||||
def test_not_found(self, mock_post, memory):
|
def test_not_found(self, mock_post, memory):
|
||||||
"""Should return error when no torrents found."""
|
"""Should return error when no torrents found."""
|
||||||
mock_post.return_value = create_mock_response(200, json_data={"hits": []})
|
mock_post.return_value = create_mock_response(200, json_data={"hits": []})
|
||||||
@@ -286,7 +286,7 @@ class TestAddTorrentToQbittorrent:
|
|||||||
This is acceptable mocking because we're testing the TOOL logic, not the client.
|
This is acceptable mocking because we're testing the TOOL logic, not the client.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@patch("agent.tools.api.qbittorrent_client")
|
@patch("alfred.agent.tools.api.qbittorrent_client")
|
||||||
def test_success(self, mock_client, memory):
|
def test_success(self, mock_client, memory):
|
||||||
"""Should add torrent successfully and update memory."""
|
"""Should add torrent successfully and update memory."""
|
||||||
mock_client.add_torrent.return_value = True
|
mock_client.add_torrent.return_value = True
|
||||||
@@ -298,7 +298,7 @@ class TestAddTorrentToQbittorrent:
|
|||||||
# Verify client was called correctly
|
# Verify client was called correctly
|
||||||
mock_client.add_torrent.assert_called_once_with("magnet:?xt=urn:btih:abc123")
|
mock_client.add_torrent.assert_called_once_with("magnet:?xt=urn:btih:abc123")
|
||||||
|
|
||||||
@patch("agent.tools.api.qbittorrent_client")
|
@patch("alfred.agent.tools.api.qbittorrent_client")
|
||||||
def test_adds_to_active_downloads(self, mock_client, memory_with_search_results):
|
def test_adds_to_active_downloads(self, mock_client, memory_with_search_results):
|
||||||
"""Should add to active downloads on success."""
|
"""Should add to active downloads on success."""
|
||||||
mock_client.add_torrent.return_value = True
|
mock_client.add_torrent.return_value = True
|
||||||
@@ -313,7 +313,7 @@ class TestAddTorrentToQbittorrent:
|
|||||||
== "Inception.2010.1080p.BluRay.x264"
|
== "Inception.2010.1080p.BluRay.x264"
|
||||||
)
|
)
|
||||||
|
|
||||||
@patch("agent.tools.api.qbittorrent_client")
|
@patch("alfred.agent.tools.api.qbittorrent_client")
|
||||||
def test_sets_topic_and_ends_workflow(self, mock_client, memory):
|
def test_sets_topic_and_ends_workflow(self, mock_client, memory):
|
||||||
"""Should set topic and end workflow."""
|
"""Should set topic and end workflow."""
|
||||||
mock_client.add_torrent.return_value = True
|
mock_client.add_torrent.return_value = True
|
||||||
@@ -326,10 +326,10 @@ class TestAddTorrentToQbittorrent:
|
|||||||
assert mem.stm.current_topic == "downloading"
|
assert mem.stm.current_topic == "downloading"
|
||||||
assert mem.stm.current_workflow is None
|
assert mem.stm.current_workflow is None
|
||||||
|
|
||||||
@patch("agent.tools.api.qbittorrent_client")
|
@patch("alfred.agent.tools.api.qbittorrent_client")
|
||||||
def test_error_handling(self, mock_client, memory):
|
def test_error_handling(self, mock_client, memory):
|
||||||
"""Should handle client errors correctly."""
|
"""Should handle client errors correctly."""
|
||||||
from infrastructure.api.qbittorrent.exceptions import QBittorrentAPIError
|
from alfred.infrastructure.api.qbittorrent.exceptions import QBittorrentAPIError
|
||||||
|
|
||||||
mock_client.add_torrent.side_effect = QBittorrentAPIError("Connection failed")
|
mock_client.add_torrent.side_effect = QBittorrentAPIError("Connection failed")
|
||||||
|
|
||||||
@@ -349,7 +349,7 @@ class TestAddTorrentByIndex:
|
|||||||
- Error handling for edge cases
|
- Error handling for edge cases
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@patch("agent.tools.api.qbittorrent_client")
|
@patch("alfred.agent.tools.api.qbittorrent_client")
|
||||||
def test_success(self, mock_client, memory_with_search_results):
|
def test_success(self, mock_client, memory_with_search_results):
|
||||||
"""Should get torrent by index and add it."""
|
"""Should get torrent by index and add it."""
|
||||||
mock_client.add_torrent.return_value = True
|
mock_client.add_torrent.return_value = True
|
||||||
@@ -362,7 +362,7 @@ class TestAddTorrentByIndex:
|
|||||||
# Verify correct magnet was extracted and used
|
# Verify correct magnet was extracted and used
|
||||||
mock_client.add_torrent.assert_called_once_with("magnet:?xt=urn:btih:abc123")
|
mock_client.add_torrent.assert_called_once_with("magnet:?xt=urn:btih:abc123")
|
||||||
|
|
||||||
@patch("agent.tools.api.qbittorrent_client")
|
@patch("alfred.agent.tools.api.qbittorrent_client")
|
||||||
def test_uses_correct_magnet(self, mock_client, memory_with_search_results):
|
def test_uses_correct_magnet(self, mock_client, memory_with_search_results):
|
||||||
"""Should extract correct magnet from index."""
|
"""Should extract correct magnet from index."""
|
||||||
mock_client.add_torrent.return_value = True
|
mock_client.add_torrent.return_value = True
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
"""Edge case tests for tools."""
|
"""Edge case tests for tools."""
|
||||||
|
import pytest
|
||||||
from unittest.mock import Mock, patch
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
import pytest
|
from alfred.agent.tools import api as api_tools
|
||||||
|
from alfred.agent.tools import filesystem as fs_tools
|
||||||
from agent.tools import api as api_tools
|
from alfred.infrastructure.persistence import get_memory
|
||||||
from agent.tools import filesystem as fs_tools
|
|
||||||
from infrastructure.persistence import get_memory
|
|
||||||
|
|
||||||
|
|
||||||
class TestFindTorrentEdgeCases:
|
class TestFindTorrentEdgeCases:
|
||||||
"""Edge case tests for find_torrent."""
|
"""Edge case tests for find_torrent."""
|
||||||
|
|
||||||
@patch("agent.tools.api.SearchTorrentsUseCase")
|
@patch("alfred.agent.tools.api.SearchTorrentsUseCase")
|
||||||
def test_empty_query(self, mock_use_case_class, memory):
|
def test_empty_query(self, mock_use_case_class, memory):
|
||||||
"""Should handle empty query."""
|
"""Should handle empty query."""
|
||||||
mock_response = Mock()
|
mock_response = Mock()
|
||||||
@@ -28,7 +26,7 @@ class TestFindTorrentEdgeCases:
|
|||||||
|
|
||||||
assert result["status"] == "error"
|
assert result["status"] == "error"
|
||||||
|
|
||||||
@patch("agent.tools.api.SearchTorrentsUseCase")
|
@patch("alfred.agent.tools.api.SearchTorrentsUseCase")
|
||||||
def test_very_long_query(self, mock_use_case_class, memory):
|
def test_very_long_query(self, mock_use_case_class, memory):
|
||||||
"""Should handle very long query."""
|
"""Should handle very long query."""
|
||||||
mock_response = Mock()
|
mock_response = Mock()
|
||||||
@@ -47,7 +45,7 @@ class TestFindTorrentEdgeCases:
|
|||||||
# Should not crash
|
# Should not crash
|
||||||
assert "status" in result
|
assert "status" in result
|
||||||
|
|
||||||
@patch("agent.tools.api.SearchTorrentsUseCase")
|
@patch("alfred.agent.tools.api.SearchTorrentsUseCase")
|
||||||
def test_special_characters_in_query(self, mock_use_case_class, memory):
|
def test_special_characters_in_query(self, mock_use_case_class, memory):
|
||||||
"""Should handle special characters in query."""
|
"""Should handle special characters in query."""
|
||||||
mock_response = Mock()
|
mock_response = Mock()
|
||||||
@@ -65,7 +63,7 @@ class TestFindTorrentEdgeCases:
|
|||||||
|
|
||||||
assert "status" in result
|
assert "status" in result
|
||||||
|
|
||||||
@patch("agent.tools.api.SearchTorrentsUseCase")
|
@patch("alfred.agent.tools.api.SearchTorrentsUseCase")
|
||||||
def test_unicode_query(self, mock_use_case_class, memory):
|
def test_unicode_query(self, mock_use_case_class, memory):
|
||||||
"""Should handle unicode in query."""
|
"""Should handle unicode in query."""
|
||||||
mock_response = Mock()
|
mock_response = Mock()
|
||||||
@@ -82,7 +80,7 @@ class TestFindTorrentEdgeCases:
|
|||||||
|
|
||||||
assert "status" in result
|
assert "status" in result
|
||||||
|
|
||||||
@patch("agent.tools.api.SearchTorrentsUseCase")
|
@patch("alfred.agent.tools.api.SearchTorrentsUseCase")
|
||||||
def test_results_with_missing_fields(self, mock_use_case_class, memory):
|
def test_results_with_missing_fields(self, mock_use_case_class, memory):
|
||||||
"""Should handle results with missing fields."""
|
"""Should handle results with missing fields."""
|
||||||
mock_response = Mock()
|
mock_response = Mock()
|
||||||
@@ -104,7 +102,7 @@ class TestFindTorrentEdgeCases:
|
|||||||
mem = get_memory()
|
mem = get_memory()
|
||||||
assert len(mem.episodic.last_search_results["results"]) == 2
|
assert len(mem.episodic.last_search_results["results"]) == 2
|
||||||
|
|
||||||
@patch("agent.tools.api.SearchTorrentsUseCase")
|
@patch("alfred.agent.tools.api.SearchTorrentsUseCase")
|
||||||
def test_api_timeout(self, mock_use_case_class, memory):
|
def test_api_timeout(self, mock_use_case_class, memory):
|
||||||
"""Should handle API timeout."""
|
"""Should handle API timeout."""
|
||||||
mock_use_case = Mock()
|
mock_use_case = Mock()
|
||||||
@@ -157,7 +155,7 @@ class TestGetTorrentByIndexEdgeCases:
|
|||||||
class TestAddTorrentEdgeCases:
|
class TestAddTorrentEdgeCases:
|
||||||
"""Edge case tests for add_torrent functions."""
|
"""Edge case tests for add_torrent functions."""
|
||||||
|
|
||||||
@patch("agent.tools.api.AddTorrentUseCase")
|
@patch("alfred.agent.tools.api.AddTorrentUseCase")
|
||||||
def test_invalid_magnet_link(self, mock_use_case_class, memory):
|
def test_invalid_magnet_link(self, mock_use_case_class, memory):
|
||||||
"""Should handle invalid magnet link."""
|
"""Should handle invalid magnet link."""
|
||||||
mock_response = Mock()
|
mock_response = Mock()
|
||||||
@@ -173,7 +171,7 @@ class TestAddTorrentEdgeCases:
|
|||||||
|
|
||||||
assert result["status"] == "error"
|
assert result["status"] == "error"
|
||||||
|
|
||||||
@patch("agent.tools.api.AddTorrentUseCase")
|
@patch("alfred.agent.tools.api.AddTorrentUseCase")
|
||||||
def test_empty_magnet_link(self, mock_use_case_class, memory):
|
def test_empty_magnet_link(self, mock_use_case_class, memory):
|
||||||
"""Should handle empty magnet link."""
|
"""Should handle empty magnet link."""
|
||||||
mock_response = Mock()
|
mock_response = Mock()
|
||||||
@@ -189,7 +187,7 @@ class TestAddTorrentEdgeCases:
|
|||||||
|
|
||||||
assert result["status"] == "error"
|
assert result["status"] == "error"
|
||||||
|
|
||||||
@patch("agent.tools.api.AddTorrentUseCase")
|
@patch("alfred.agent.tools.api.AddTorrentUseCase")
|
||||||
def test_very_long_magnet_link(self, mock_use_case_class, memory):
|
def test_very_long_magnet_link(self, mock_use_case_class, memory):
|
||||||
"""Should handle very long magnet link."""
|
"""Should handle very long magnet link."""
|
||||||
mock_response = Mock()
|
mock_response = Mock()
|
||||||
@@ -203,7 +201,7 @@ class TestAddTorrentEdgeCases:
|
|||||||
|
|
||||||
assert "status" in result
|
assert "status" in result
|
||||||
|
|
||||||
@patch("agent.tools.api.AddTorrentUseCase")
|
@patch("alfred.agent.tools.api.AddTorrentUseCase")
|
||||||
def test_qbittorrent_connection_refused(self, mock_use_case_class, memory):
|
def test_qbittorrent_connection_refused(self, mock_use_case_class, memory):
|
||||||
"""Should handle qBittorrent connection refused."""
|
"""Should handle qBittorrent connection refused."""
|
||||||
mock_use_case = Mock()
|
mock_use_case = Mock()
|
||||||
@@ -391,7 +389,7 @@ class TestFilesystemEdgeCases:
|
|||||||
class TestFindMediaImdbIdEdgeCases:
|
class TestFindMediaImdbIdEdgeCases:
|
||||||
"""Edge case tests for find_media_imdb_id."""
|
"""Edge case tests for find_media_imdb_id."""
|
||||||
|
|
||||||
@patch("agent.tools.api.SearchMovieUseCase")
|
@patch("alfred.agent.tools.api.SearchMovieUseCase")
|
||||||
def test_movie_with_same_name_different_years(self, mock_use_case_class, memory):
|
def test_movie_with_same_name_different_years(self, mock_use_case_class, memory):
|
||||||
"""Should handle movies with same name."""
|
"""Should handle movies with same name."""
|
||||||
mock_response = Mock()
|
mock_response = Mock()
|
||||||
@@ -409,7 +407,7 @@ class TestFindMediaImdbIdEdgeCases:
|
|||||||
|
|
||||||
assert result["status"] == "ok"
|
assert result["status"] == "ok"
|
||||||
|
|
||||||
@patch("agent.tools.api.SearchMovieUseCase")
|
@patch("alfred.agent.tools.api.SearchMovieUseCase")
|
||||||
def test_movie_with_special_title(self, mock_use_case_class, memory):
|
def test_movie_with_special_title(self, mock_use_case_class, memory):
|
||||||
"""Should handle movies with special characters in title."""
|
"""Should handle movies with special characters in title."""
|
||||||
mock_response = Mock()
|
mock_response = Mock()
|
||||||
@@ -426,7 +424,7 @@ class TestFindMediaImdbIdEdgeCases:
|
|||||||
|
|
||||||
assert result["status"] == "ok"
|
assert result["status"] == "ok"
|
||||||
|
|
||||||
@patch("agent.tools.api.SearchMovieUseCase")
|
@patch("alfred.agent.tools.api.SearchMovieUseCase")
|
||||||
def test_tv_show_vs_movie(self, mock_use_case_class, memory):
|
def test_tv_show_vs_movie(self, mock_use_case_class, memory):
|
||||||
"""Should distinguish TV shows from movies."""
|
"""Should distinguish TV shows from movies."""
|
||||||
mock_response = Mock()
|
mock_response = Mock()
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
"""Tests for filesystem tools."""
|
"""Tests for filesystem tools."""
|
||||||
|
import pytest
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
from alfred.agent.tools import filesystem as fs_tools
|
||||||
|
from alfred.infrastructure.persistence import get_memory
|
||||||
from agent.tools import filesystem as fs_tools
|
|
||||||
from infrastructure.persistence import get_memory
|
|
||||||
|
|
||||||
|
|
||||||
class TestSetPathForFolder:
|
class TestSetPathForFolder:
|
||||||
|
|||||||
Reference in New Issue
Block a user