diff --git a/.dockerignore b/.dockerignore index 3338a74..667224e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -41,10 +41,6 @@ docs/ *.md !README.md -# Tests -tests/ -pytest.ini - # Data (will be mounted as volumes) memory_data/ logs/ diff --git a/Dockerfile b/Dockerfile index 17bc69d..15ab5f9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -59,12 +59,8 @@ RUN --mount=type=cache,target=/root/.cache/pip \ uv pip install --system -e .[dev]; \ fi -COPY alfred/agent/ ./agent/ -COPY alfred/application/ ./application/ -COPY alfred/domain/ ./domain/ -COPY alfred/infrastructure/ ./infrastructure/ -COPY alfred/app.py . -COPY tests/ ./tests/ +COPY alfred/ ./alfred +COPY tests/ ./tests # =========================================== # Stage 3: Runtime @@ -96,18 +92,14 @@ RUN mkdir -p /data/memory /data/logs \ USER appuser # Set working directory (owned by appuser) -WORKDIR /home/appuser/app +WORKDIR /home/appuser # 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/bin /usr/local/bin # Copy application code (already owned by appuser) -COPY --chown=appuser:appuser alfred/agent/ ./agent/ -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 . +COPY --chown=appuser:appuser alfred/ ./alfred # Create volumes for persistent data VOLUME ["/data/memory", "/data/logs"] diff --git a/alfred/agent/agent.py b/alfred/agent/agent.py index 27e9cf0..770fbcf 100644 --- a/alfred/agent/agent.py +++ b/alfred/agent/agent.py @@ -5,7 +5,7 @@ import logging from collections.abc import AsyncGenerator from typing import Any -from infrastructure.persistence import get_memory +from alfred.infrastructure.persistence import get_memory from .config import settings from .prompts import PromptBuilder diff --git a/alfred/agent/prompts.py b/alfred/agent/prompts.py index 734e627..f43bc85 100644 --- a/alfred/agent/prompts.py +++ b/alfred/agent/prompts.py @@ -3,7 +3,7 @@ import json from typing import Any -from infrastructure.persistence import get_memory +from alfred.infrastructure.persistence import get_memory from .registry import Tool diff --git a/alfred/agent/tools/api.py b/alfred/agent/tools/api.py index 0898c60..ecca8e5 100644 --- a/alfred/agent/tools/api.py +++ b/alfred/agent/tools/api.py @@ -3,12 +3,12 @@ import logging from typing import Any -from application.movies import SearchMovieUseCase -from application.torrents import AddTorrentUseCase, SearchTorrentsUseCase -from infrastructure.api.knaben import knaben_client -from infrastructure.api.qbittorrent import qbittorrent_client -from infrastructure.api.tmdb import tmdb_client -from infrastructure.persistence import get_memory +from alfred.application.movies import SearchMovieUseCase +from alfred.application.torrents import AddTorrentUseCase, SearchTorrentsUseCase +from alfred.infrastructure.api.knaben import knaben_client +from alfred.infrastructure.api.qbittorrent import qbittorrent_client +from alfred.infrastructure.api.tmdb import tmdb_client +from alfred.infrastructure.persistence import get_memory logger = logging.getLogger(__name__) diff --git a/alfred/agent/tools/filesystem.py b/alfred/agent/tools/filesystem.py index cc7d547..017c339 100644 --- a/alfred/agent/tools/filesystem.py +++ b/alfred/agent/tools/filesystem.py @@ -2,8 +2,8 @@ from typing import Any -from application.filesystem import ListFolderUseCase, SetFolderPathUseCase -from infrastructure.filesystem import FileManager +from alfred.application.filesystem import ListFolderUseCase, SetFolderPathUseCase +from alfred.infrastructure.filesystem import FileManager def set_path_for_folder(folder_name: str, path_value: str) -> dict[str, Any]: diff --git a/alfred/agent/tools/language.py b/alfred/agent/tools/language.py index e7ea471..22b0098 100644 --- a/alfred/agent/tools/language.py +++ b/alfred/agent/tools/language.py @@ -3,7 +3,7 @@ import logging from typing import Any -from infrastructure.persistence import get_memory +from alfred.infrastructure.persistence import get_memory logger = logging.getLogger(__name__) diff --git a/alfred/app.py b/alfred/app.py index 2788a9f..8280b89 100644 --- a/alfred/app.py +++ b/alfred/app.py @@ -5,19 +5,18 @@ import logging import os import time import uuid -from typing import Any - from fastapi import FastAPI, HTTPException from fastapi.responses import JSONResponse, StreamingResponse from fastapi.staticfiles import StaticFiles from pydantic import BaseModel, Field, validator +from typing import Any -from agent.agent import Agent -from agent.config import settings -from agent.llm.deepseek import DeepSeekClient -from agent.llm.exceptions import LLMAPIError, LLMConfigurationError -from agent.llm.ollama import OllamaClient -from infrastructure.persistence import get_memory, init_memory +from alfred.agent.agent import Agent +from alfred.agent.config import settings +from alfred.agent.llm.deepseek import DeepSeekClient +from alfred.agent.llm.exceptions import LLMAPIError, LLMConfigurationError +from alfred.agent.llm.ollama import OllamaClient +from alfred.infrastructure.persistence import get_memory, init_memory logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" diff --git a/alfred/application/filesystem/list_folder.py b/alfred/application/filesystem/list_folder.py index fdae123..02abfb0 100644 --- a/alfred/application/filesystem/list_folder.py +++ b/alfred/application/filesystem/list_folder.py @@ -2,7 +2,7 @@ import logging -from infrastructure.filesystem import FileManager +from alfred.infrastructure.filesystem import FileManager from .dto import ListFolderResponse diff --git a/alfred/application/filesystem/set_folder_path.py b/alfred/application/filesystem/set_folder_path.py index 2f3d0ea..277a35f 100644 --- a/alfred/application/filesystem/set_folder_path.py +++ b/alfred/application/filesystem/set_folder_path.py @@ -2,7 +2,7 @@ import logging -from infrastructure.filesystem import FileManager +from alfred.infrastructure.filesystem import FileManager from .dto import SetFolderPathResponse diff --git a/alfred/application/movies/search_movie.py b/alfred/application/movies/search_movie.py index 940fd0d..652d418 100644 --- a/alfred/application/movies/search_movie.py +++ b/alfred/application/movies/search_movie.py @@ -2,7 +2,7 @@ import logging -from infrastructure.api.tmdb import ( +from alfred.infrastructure.api.tmdb import ( TMDBAPIError, TMDBClient, TMDBConfigurationError, diff --git a/alfred/application/torrents/add_torrent.py b/alfred/application/torrents/add_torrent.py index d6fce1b..2d2214d 100644 --- a/alfred/application/torrents/add_torrent.py +++ b/alfred/application/torrents/add_torrent.py @@ -2,7 +2,7 @@ import logging -from infrastructure.api.qbittorrent import ( +from alfred.infrastructure.api.qbittorrent import ( QBittorrentAPIError, QBittorrentAuthError, QBittorrentClient, diff --git a/alfred/application/torrents/search_torrents.py b/alfred/application/torrents/search_torrents.py index 1dd9745..daad45e 100644 --- a/alfred/application/torrents/search_torrents.py +++ b/alfred/application/torrents/search_torrents.py @@ -2,7 +2,7 @@ import logging -from infrastructure.api.knaben import KnabenAPIError, KnabenClient, KnabenNotFoundError +from alfred.infrastructure.api.knaben import KnabenAPIError, KnabenClient, KnabenNotFoundError from .dto import SearchTorrentsResponse diff --git a/alfred/infrastructure/api/knaben/client.py b/alfred/infrastructure/api/knaben/client.py index b5300ff..359de66 100644 --- a/alfred/infrastructure/api/knaben/client.py +++ b/alfred/infrastructure/api/knaben/client.py @@ -1,13 +1,12 @@ """Knaben torrent search API client.""" -import logging -from typing import Any +import logging import requests 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 .exceptions import KnabenAPIError, KnabenNotFoundError diff --git a/alfred/infrastructure/api/qbittorrent/client.py b/alfred/infrastructure/api/qbittorrent/client.py index 61dc25b..02d3124 100644 --- a/alfred/infrastructure/api/qbittorrent/client.py +++ b/alfred/infrastructure/api/qbittorrent/client.py @@ -1,13 +1,11 @@ """qBittorrent Web API client.""" import logging -from typing import Any - import requests 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 .exceptions import QBittorrentAPIError, QBittorrentAuthError diff --git a/alfred/infrastructure/api/tmdb/client.py b/alfred/infrastructure/api/tmdb/client.py index 5cd9ce1..208edbc 100644 --- a/alfred/infrastructure/api/tmdb/client.py +++ b/alfred/infrastructure/api/tmdb/client.py @@ -1,13 +1,12 @@ """TMDB (The Movie Database) API client.""" import logging -from typing import Any - import requests 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 .exceptions import ( TMDBAPIError, diff --git a/alfred/infrastructure/filesystem/file_manager.py b/alfred/infrastructure/filesystem/file_manager.py index c36303b..854bf07 100644 --- a/alfred/infrastructure/filesystem/file_manager.py +++ b/alfred/infrastructure/filesystem/file_manager.py @@ -7,7 +7,7 @@ from enum import Enum from pathlib import Path from typing import Any -from infrastructure.persistence import get_memory +from alfred.infrastructure.persistence import get_memory from .exceptions import PathTraversalError diff --git a/alfred/infrastructure/filesystem/organizer.py b/alfred/infrastructure/filesystem/organizer.py index 60864ac..050b529 100644 --- a/alfred/infrastructure/filesystem/organizer.py +++ b/alfred/infrastructure/filesystem/organizer.py @@ -3,9 +3,9 @@ import logging from pathlib import Path -from domain.movies.entities import Movie -from domain.tv_shows.entities import Episode, Season, TVShow -from domain.tv_shows.value_objects import SeasonNumber +from alfred.domain.movies.entities import Movie +from alfred.domain.tv_shows.entities import Episode, Season, TVShow +from alfred.domain.tv_shows.value_objects import SeasonNumber logger = logging.getLogger(__name__) diff --git a/alfred/infrastructure/persistence/context.py b/alfred/infrastructure/persistence/context.py index 80bf142..8cddbd3 100644 --- a/alfred/infrastructure/persistence/context.py +++ b/alfred/infrastructure/persistence/context.py @@ -6,7 +6,7 @@ without passing it explicitly through all function calls. Usage: # At application startup - from infrastructure.persistence import init_memory, get_memory + from alfred.infrastructure.persistence import init_memory, get_memory init_memory("memory_data") diff --git a/alfred/infrastructure/persistence/json/movie_repository.py b/alfred/infrastructure/persistence/json/movie_repository.py index 243d425..46ace79 100644 --- a/alfred/infrastructure/persistence/json/movie_repository.py +++ b/alfred/infrastructure/persistence/json/movie_repository.py @@ -4,11 +4,11 @@ import logging from datetime import datetime from typing import Any -from domain.movies.entities import Movie -from domain.movies.repositories import MovieRepository -from domain.movies.value_objects import MovieTitle, Quality, ReleaseYear -from domain.shared.value_objects import FilePath, FileSize, ImdbId -from infrastructure.persistence import get_memory +from alfred.domain.movies.entities import Movie +from alfred.domain.movies.repositories import MovieRepository +from alfred.domain.movies.value_objects import MovieTitle, Quality, ReleaseYear +from alfred.domain.shared.value_objects import FilePath, FileSize, ImdbId +from alfred.infrastructure.persistence import get_memory logger = logging.getLogger(__name__) diff --git a/alfred/infrastructure/persistence/json/subtitle_repository.py b/alfred/infrastructure/persistence/json/subtitle_repository.py index f5c92f2..c0ce6c5 100644 --- a/alfred/infrastructure/persistence/json/subtitle_repository.py +++ b/alfred/infrastructure/persistence/json/subtitle_repository.py @@ -3,11 +3,11 @@ import logging from typing import Any -from domain.shared.value_objects import FilePath, ImdbId -from domain.subtitles.entities import Subtitle -from domain.subtitles.repositories import SubtitleRepository -from domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset -from infrastructure.persistence import get_memory +from alfred.domain.shared.value_objects import FilePath, ImdbId +from alfred.domain.subtitles.entities import Subtitle +from alfred.domain.subtitles.repositories import SubtitleRepository +from alfred.domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset +from alfred.infrastructure.persistence import get_memory logger = logging.getLogger(__name__) diff --git a/alfred/infrastructure/persistence/json/tvshow_repository.py b/alfred/infrastructure/persistence/json/tvshow_repository.py index 2cb9643..2e79836 100644 --- a/alfred/infrastructure/persistence/json/tvshow_repository.py +++ b/alfred/infrastructure/persistence/json/tvshow_repository.py @@ -4,11 +4,11 @@ import logging from datetime import datetime from typing import Any -from domain.shared.value_objects import ImdbId -from domain.tv_shows.entities import TVShow -from domain.tv_shows.repositories import TVShowRepository -from domain.tv_shows.value_objects import ShowStatus -from infrastructure.persistence import get_memory +from alfred.domain.shared.value_objects import ImdbId +from alfred.domain.tv_shows.entities import TVShow +from alfred.domain.tv_shows.repositories import TVShowRepository +from alfred.domain.tv_shows.value_objects import ShowStatus +from alfred.infrastructure.persistence import get_memory logger = logging.getLogger(__name__) diff --git a/pyproject.toml b/pyproject.toml index 32de1a1..967da51 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,6 +31,8 @@ build-backend = "poetry.core.masonry.api" [tool.pytest.ini_options] # Chemins où pytest cherche les tests testpaths = ["tests"] +# Ajouter le répertoire racine au PYTHONPATH pour les imports +pythonpath = ["."] # Patterns de fichiers/classes/fonctions à considérer comme tests python_files = ["test_*.py"] # Fichiers commençant par "test_" diff --git a/tests/conftest.py b/tests/conftest.py index 67c6932..ff87c6f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,20 +1,16 @@ """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 # sys.path.insert(0, str(Path(__file__).parent.parent)) - +import pytest import shutil +import sys import tempfile from pathlib import Path from unittest.mock import MagicMock, Mock -import pytest - -from infrastructure.persistence import Memory, set_memory +from alfred.infrastructure.persistence import Memory, set_memory @pytest.fixture @@ -255,7 +251,6 @@ def mock_deepseek(): def test_something(mock_deepseek): # Your test code here """ - import sys from unittest.mock import Mock # Save the original module if it exists diff --git a/tests/test_agent.py b/tests/test_agent.py index cf3c426..eb846c5 100644 --- a/tests/test_agent.py +++ b/tests/test_agent.py @@ -2,8 +2,8 @@ from unittest.mock import Mock -from agent.agent import Agent -from infrastructure.persistence import get_memory +from alfred.agent.agent import Agent +from alfred.infrastructure.persistence import get_memory class TestAgentInit: diff --git a/tests/test_agent_edge_cases.py b/tests/test_agent_edge_cases.py index df92abe..83d94ce 100644 --- a/tests/test_agent_edge_cases.py +++ b/tests/test_agent_edge_cases.py @@ -1,11 +1,9 @@ """Edge case tests for the Agent.""" - +import pytest from unittest.mock import Mock -import pytest - -from agent.agent import Agent -from infrastructure.persistence import get_memory +from alfred.agent.agent import Agent +from alfred.infrastructure.persistence import get_memory class TestExecuteToolCallEdgeCases: @@ -16,7 +14,7 @@ class TestExecuteToolCallEdgeCases: agent = Agent(llm=mock_llm) # Mock a tool that returns None - from agent.registry import Tool + from alfred.agent.registry import Tool agent.tools["test_tool"] = Tool( name="test_tool", description="Test", func=lambda: None, parameters={} @@ -34,7 +32,7 @@ class TestExecuteToolCallEdgeCases: """Should propagate KeyboardInterrupt.""" agent = Agent(llm=mock_llm) - from agent.registry import Tool + from alfred.agent.registry import Tool def raise_interrupt(): raise KeyboardInterrupt() diff --git a/tests/test_api.py b/tests/test_api.py index 85ea1c1..5f72b9a 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -10,7 +10,7 @@ class TestHealthEndpoint: def test_health_check(self, memory): """Should return healthy status.""" - from app import app + from alfred.app import app client = TestClient(app) @@ -25,7 +25,7 @@ class TestModelsEndpoint: def test_list_models(self, memory): """Should return model list.""" - from app import app + from alfred.app import app client = TestClient(app) @@ -43,7 +43,7 @@ class TestMemoryEndpoints: def test_get_memory_state(self, memory): """Should return full memory state.""" - from app import app + from alfred.app import app client = TestClient(app) @@ -57,7 +57,7 @@ class TestMemoryEndpoints: def test_get_search_results_empty(self, memory): """Should return empty when no search results.""" - from app import app + from alfred.app import app client = TestClient(app) @@ -69,7 +69,7 @@ class TestMemoryEndpoints: def test_get_search_results_with_data(self, memory_with_search_results): """Should return search results when available.""" - from app import app + from alfred.app import app client = TestClient(app) @@ -83,7 +83,7 @@ class TestMemoryEndpoints: def test_clear_session(self, memory_with_search_results): """Should clear session memories.""" - from app import app + from alfred.app import app client = TestClient(app) @@ -102,10 +102,10 @@ class TestChatCompletionsEndpoint: def test_chat_completion_success(self, memory): """Should return chat completion.""" - from app import app + from alfred.app import app # 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) response = client.post( @@ -123,7 +123,7 @@ class TestChatCompletionsEndpoint: def test_chat_completion_no_user_message(self, memory): """Should return error if no user message.""" - from app import app + from alfred.app import app client = TestClient(app) @@ -146,7 +146,7 @@ class TestChatCompletionsEndpoint: def test_chat_completion_empty_messages(self, memory): """Should return error for empty messages.""" - from app import app + from alfred.app import app client = TestClient(app) @@ -162,7 +162,7 @@ class TestChatCompletionsEndpoint: def test_chat_completion_invalid_json(self, memory): """Should return error for invalid JSON.""" - from app import app + from alfred.app import app client = TestClient(app) @@ -176,9 +176,9 @@ class TestChatCompletionsEndpoint: def test_chat_completion_streaming(self, memory): """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) response = client.post( @@ -195,9 +195,9 @@ class TestChatCompletionsEndpoint: def test_chat_completion_extracts_last_user_message(self, memory): """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) response = client.post( @@ -218,9 +218,9 @@ class TestChatCompletionsEndpoint: def test_chat_completion_response_format(self, memory): """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) response = client.post( diff --git a/tests/test_api_edge_cases.py b/tests/test_api_edge_cases.py index 562da55..5ffa798 100644 --- a/tests/test_api_edge_cases.py +++ b/tests/test_api_edge_cases.py @@ -10,7 +10,8 @@ class TestChatCompletionsEdgeCases: def test_very_long_message(self, memory): """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 mock_llm = Mock() @@ -32,7 +33,8 @@ class TestChatCompletionsEdgeCases: def test_unicode_message(self, memory): """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.complete.return_value = { @@ -57,7 +59,8 @@ class TestChatCompletionsEdgeCases: def test_special_characters_in_message(self, memory): """Should handle special characters.""" - from app import agent, app + from alfred.app import app + from alfred.agent import agent mock_llm = Mock() mock_llm.complete.return_value = {"role": "assistant", "content": "Response"} @@ -78,12 +81,12 @@ class TestChatCompletionsEdgeCases: def test_empty_content_in_message(self, memory): """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.complete.return_value = "Response" mock_llm_class.return_value = mock_llm - from app import app + from alfred.app import app client = TestClient(app) @@ -100,11 +103,11 @@ class TestChatCompletionsEdgeCases: def test_null_content_in_message(self, memory): """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_class.return_value = mock_llm - from app import app + from alfred.app import app client = TestClient(app) @@ -120,11 +123,11 @@ class TestChatCompletionsEdgeCases: def test_missing_content_field(self, memory): """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_class.return_value = mock_llm - from app import app + from alfred.app import app client = TestClient(app) @@ -141,11 +144,11 @@ class TestChatCompletionsEdgeCases: def test_missing_role_field(self, memory): """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_class.return_value = mock_llm - from app import app + from alfred.app import app client = TestClient(app) @@ -162,12 +165,12 @@ class TestChatCompletionsEdgeCases: def test_invalid_role(self, memory): """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.complete.return_value = "Response" mock_llm_class.return_value = mock_llm - from app import app + from alfred.app import app client = TestClient(app) @@ -184,7 +187,8 @@ class TestChatCompletionsEdgeCases: def test_many_messages(self, memory): """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.complete.return_value = {"role": "assistant", "content": "Response"} @@ -210,11 +214,11 @@ class TestChatCompletionsEdgeCases: def test_only_system_messages(self, memory): """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_class.return_value = mock_llm - from app import app + from alfred.app import app client = TestClient(app) @@ -233,11 +237,11 @@ class TestChatCompletionsEdgeCases: def test_only_assistant_messages(self, memory): """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_class.return_value = mock_llm - from app import app + from alfred.app import app client = TestClient(app) @@ -255,11 +259,11 @@ class TestChatCompletionsEdgeCases: def test_messages_not_array(self, memory): """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_class.return_value = mock_llm - from app import app + from alfred.app import app client = TestClient(app) @@ -276,11 +280,11 @@ class TestChatCompletionsEdgeCases: def test_message_not_object(self, memory): """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_class.return_value = mock_llm - from app import app + from alfred.app import app client = TestClient(app) @@ -297,7 +301,8 @@ class TestChatCompletionsEdgeCases: def test_extra_fields_in_request(self, memory): """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.complete.return_value = {"role": "assistant", "content": "Response"} @@ -320,8 +325,9 @@ class TestChatCompletionsEdgeCases: def test_streaming_with_tool_call(self, memory, real_folder): """Should handle streaming with tool execution.""" - from app import agent, app - from infrastructure.persistence import get_memory + from alfred.app import app + from alfred.agent import agent + from alfred.infrastructure.persistence import get_memory mem = get_memory() mem.ltm.set_config("download_folder", str(real_folder["downloads"])) @@ -365,7 +371,8 @@ class TestChatCompletionsEdgeCases: def test_concurrent_requests_simulation(self, memory): """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.complete.return_value = {"role": "assistant", "content": "Response"} @@ -385,7 +392,8 @@ class TestChatCompletionsEdgeCases: def test_llm_returns_json_in_response(self, memory): """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.complete.return_value = { @@ -414,9 +422,9 @@ class TestMemoryEndpointsEdgeCases: def test_memory_state_with_large_data(self, memory): """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() - from app import app + from alfred.app import app # Add lots of data to memory for i in range(100): @@ -432,9 +440,9 @@ class TestMemoryEndpointsEdgeCases: def test_memory_state_with_unicode(self, memory): """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() - from app import app + from alfred.app import app memory.ltm.set_config("japanese", "日本語テスト") memory.stm.add_message("user", "🎬 Movie request") @@ -448,9 +456,9 @@ class TestMemoryEndpointsEdgeCases: def test_search_results_with_special_chars(self, memory): """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() - from app import app + from alfred.app import app memory.episodic.store_search_results( "Test ", @@ -467,9 +475,9 @@ class TestMemoryEndpointsEdgeCases: def test_clear_session_idempotent(self, memory): """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() - from app import app + from alfred.app import app client = TestClient(app) @@ -480,9 +488,9 @@ class TestMemoryEndpointsEdgeCases: def test_clear_session_preserves_ltm(self, memory): """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() - from app import app + from alfred.app import app memory.ltm.set_config("important", "data") memory.stm.add_message("user", "Hello") @@ -502,9 +510,9 @@ class TestHealthEndpointEdgeCases: def test_health_returns_version(self, memory): """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() - from app import app + from alfred.app import app client = TestClient(app) @@ -515,9 +523,9 @@ class TestHealthEndpointEdgeCases: def test_health_with_query_params(self, memory): """Should ignore query parameters.""" - with patch("app.DeepSeekClient") as mock_llm: + with patch("alfred.app.DeepSeekClient") as mock_llm: mock_llm.return_value = Mock() - from app import app + from alfred.app import app client = TestClient(app) @@ -531,9 +539,9 @@ class TestModelsEndpointEdgeCases: def test_models_response_format(self, memory): """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() - from app import app + from alfred.app import app client = TestClient(app) diff --git a/tests/test_config_critical.py b/tests/test_config_critical.py index d149f2c..47e8b07 100644 --- a/tests/test_config_critical.py +++ b/tests/test_config_critical.py @@ -1,8 +1,7 @@ """Critical tests for configuration validation.""" - import pytest -from agent.config import ConfigurationError, Settings +from alfred.agent.config import ConfigurationError, Settings class TestConfigValidation: diff --git a/tests/test_config_edge_cases.py b/tests/test_config_edge_cases.py index 3076e85..01dc150 100644 --- a/tests/test_config_edge_cases.py +++ b/tests/test_config_edge_cases.py @@ -1,12 +1,11 @@ """Edge case tests for configuration and parameters.""" import os +import pytest from unittest.mock import patch -import pytest - -from agent.config import ConfigurationError, Settings -from agent.parameters import ( +from alfred.agent.config import ConfigurationError, Settings +from alfred.agent.parameters import ( REQUIRED_PARAMETERS, ParameterSchema, format_parameters_for_prompt, diff --git a/tests/test_domain_edge_cases.py b/tests/test_domain_edge_cases.py index 2e9afee..25a618d 100644 --- a/tests/test_domain_edge_cases.py +++ b/tests/test_domain_edge_cases.py @@ -1,17 +1,15 @@ """Edge case tests for domain entities and value objects.""" - +import pytest from datetime import datetime -import pytest - -from domain.movies.entities import Movie -from domain.movies.value_objects import MovieTitle, Quality, ReleaseYear -from domain.shared.exceptions import ValidationError -from domain.shared.value_objects import FilePath, FileSize, ImdbId -from domain.subtitles.entities import Subtitle -from domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset -from domain.tv_shows.entities import TVShow -from domain.tv_shows.value_objects import ShowStatus +from alfred.domain.movies.entities import Movie +from alfred.domain.movies.value_objects import MovieTitle, Quality, ReleaseYear +from alfred.domain.shared.exceptions import ValidationError +from alfred.domain.shared.value_objects import FilePath, FileSize, ImdbId +from alfred.domain.subtitles.entities import Subtitle +from alfred.domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset +from alfred.domain.tv_shows.entities import TVShow +from alfred.domain.tv_shows.value_objects import ShowStatus class TestImdbIdEdgeCases: diff --git a/tests/test_memory.py b/tests/test_memory.py index ad1ecfe..ce83aa3 100644 --- a/tests/test_memory.py +++ b/tests/test_memory.py @@ -1,10 +1,8 @@ """Tests for the Memory system.""" - +import pytest from datetime import datetime -import pytest - -from infrastructure.persistence import ( +from alfred.infrastructure.persistence import ( EpisodicMemory, LongTermMemory, Memory, @@ -13,7 +11,7 @@ from infrastructure.persistence import ( has_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: diff --git a/tests/test_memory_edge_cases.py b/tests/test_memory_edge_cases.py index d320b00..356c90e 100644 --- a/tests/test_memory_edge_cases.py +++ b/tests/test_memory_edge_cases.py @@ -4,8 +4,7 @@ import json import os import pytest - -from infrastructure.persistence import ( +from alfred.infrastructure.persistence import ( EpisodicMemory, LongTermMemory, Memory, @@ -14,7 +13,7 @@ from infrastructure.persistence import ( init_memory, set_memory, ) -from infrastructure.persistence.context import _memory_ctx +from alfred.infrastructure.persistence.context import _memory_ctx class TestLongTermMemoryEdgeCases: diff --git a/tests/test_prompts.py b/tests/test_prompts.py index 28e77be..6cd7539 100644 --- a/tests/test_prompts.py +++ b/tests/test_prompts.py @@ -1,7 +1,7 @@ """Tests for PromptBuilder.""" -from agent.prompts import PromptBuilder -from agent.registry import make_tools +from alfred.agent.prompts import PromptBuilder +from alfred.agent.registry import make_tools class TestPromptBuilder: diff --git a/tests/test_prompts_critical.py b/tests/test_prompts_critical.py index 3ef683c..499514e 100644 --- a/tests/test_prompts_critical.py +++ b/tests/test_prompts_critical.py @@ -1,7 +1,7 @@ """Critical tests for prompt builder - Tests that would have caught bugs.""" -from agent.prompts import PromptBuilder -from agent.registry import make_tools +from alfred.agent.prompts import PromptBuilder +from alfred.agent.registry import make_tools class TestPromptBuilderToolsInjection: diff --git a/tests/test_prompts_edge_cases.py b/tests/test_prompts_edge_cases.py index 5e4a3e8..738b1d7 100644 --- a/tests/test_prompts_edge_cases.py +++ b/tests/test_prompts_edge_cases.py @@ -1,7 +1,7 @@ """Edge case tests for PromptBuilder.""" -from agent.prompts import PromptBuilder -from agent.registry import make_tools +from alfred.agent.prompts import PromptBuilder +from alfred.agent.registry import make_tools class TestPromptBuilderEdgeCases: @@ -266,7 +266,7 @@ class TestFormatToolsDescriptionEdgeCases: def test_format_with_complex_parameters(self, memory): """Should format complex parameter schemas.""" - from agent.registry import Tool + from alfred.agent.registry import Tool tools = { "complex_tool": Tool( diff --git a/tests/test_registry_critical.py b/tests/test_registry_critical.py index ec275e4..5f8a2c2 100644 --- a/tests/test_registry_critical.py +++ b/tests/test_registry_critical.py @@ -3,9 +3,8 @@ import inspect import pytest - -from agent.prompts import PromptBuilder -from agent.registry import Tool, _create_tool_from_function, make_tools +from alfred.agent.prompts import PromptBuilder +from alfred.agent.registry import Tool, _create_tool_from_function, make_tools class TestToolSpecFormat: diff --git a/tests/test_registry_edge_cases.py b/tests/test_registry_edge_cases.py index 9404bca..16a761b 100644 --- a/tests/test_registry_edge_cases.py +++ b/tests/test_registry_edge_cases.py @@ -1,8 +1,7 @@ """Edge case tests for tool registry.""" import pytest - -from agent.registry import Tool, make_tools +from alfred.agent.registry import Tool, make_tools class TestToolEdgeCases: diff --git a/tests/test_repositories.py b/tests/test_repositories.py index b904f4d..c6e9993 100644 --- a/tests/test_repositories.py +++ b/tests/test_repositories.py @@ -1,13 +1,13 @@ """Tests for JSON repositories.""" -from domain.movies.entities import Movie -from domain.movies.value_objects import MovieTitle, Quality, ReleaseYear -from domain.shared.value_objects import FilePath, FileSize, ImdbId -from domain.subtitles.entities import Subtitle -from domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset -from domain.tv_shows.entities import TVShow -from domain.tv_shows.value_objects import ShowStatus -from infrastructure.persistence.json import ( +from alfred.domain.movies.entities import Movie +from alfred.domain.movies.value_objects import MovieTitle, Quality, ReleaseYear +from alfred.domain.shared.value_objects import FilePath, FileSize, ImdbId +from alfred.domain.subtitles.entities import Subtitle +from alfred.domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset +from alfred.domain.tv_shows.entities import TVShow +from alfred.domain.tv_shows.value_objects import ShowStatus +from alfred.infrastructure.persistence.json import ( JsonMovieRepository, JsonSubtitleRepository, JsonTVShowRepository, diff --git a/tests/test_repositories_edge_cases.py b/tests/test_repositories_edge_cases.py index f77fe48..97700c6 100644 --- a/tests/test_repositories_edge_cases.py +++ b/tests/test_repositories_edge_cases.py @@ -2,14 +2,14 @@ from datetime import datetime -from domain.movies.entities import Movie -from domain.movies.value_objects import MovieTitle, Quality -from domain.shared.value_objects import FilePath, FileSize, ImdbId -from domain.subtitles.entities import Subtitle -from domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset -from domain.tv_shows.entities import TVShow -from domain.tv_shows.value_objects import ShowStatus -from infrastructure.persistence.json import ( +from alfred.domain.movies.entities import Movie +from alfred.domain.movies.value_objects import MovieTitle, Quality +from alfred.domain.shared.value_objects import FilePath, FileSize, ImdbId +from alfred.domain.subtitles.entities import Subtitle +from alfred.domain.subtitles.value_objects import Language, SubtitleFormat, TimingOffset +from alfred.domain.tv_shows.entities import TVShow +from alfred.domain.tv_shows.value_objects import ShowStatus +from alfred.infrastructure.persistence.json import ( JsonMovieRepository, JsonSubtitleRepository, JsonTVShowRepository, diff --git a/tests/test_tools_api.py b/tests/test_tools_api.py index 137d2e1..7a3ebb0 100644 --- a/tests/test_tools_api.py +++ b/tests/test_tools_api.py @@ -2,8 +2,8 @@ from unittest.mock import Mock, patch -from agent.tools import api as api_tools -from infrastructure.persistence import get_memory +from alfred.agent.tools import api as api_tools +from alfred.infrastructure.persistence import get_memory 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: """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): """Should return movie info on success.""" @@ -56,7 +56,7 @@ class TestFindMediaImdbId: # Verify HTTP calls 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): """Should store result in STM on success.""" @@ -88,7 +88,7 @@ class TestFindMediaImdbId: assert entity["title"] == "Inception" 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): """Should return error when not found.""" mock_get.return_value = create_mock_response(200, json_data={"results": []}) @@ -98,7 +98,7 @@ class TestFindMediaImdbId: assert result["status"] == "error" 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): """Should not store in STM on error.""" mock_get.return_value = create_mock_response(200, json_data={"results": []}) @@ -112,7 +112,7 @@ class TestFindMediaImdbId: class TestFindTorrent: """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): """Should return torrents on success.""" mock_post.return_value = create_mock_response( @@ -146,7 +146,7 @@ class TestFindTorrent: payload = mock_post.call_args[1]["json"] 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): """Should store results in episodic memory.""" mock_post.return_value = create_mock_response( @@ -171,7 +171,7 @@ class TestFindTorrent: assert mem.episodic.last_search_results["query"] == "Inception" 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): """Should add indexes to results.""" mock_post.return_value = create_mock_response( @@ -211,7 +211,7 @@ class TestFindTorrent: assert results[1]["index"] == 2 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): """Should return error when no torrents found.""" 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. """ - @patch("agent.tools.api.qbittorrent_client") + @patch("alfred.agent.tools.api.qbittorrent_client") def test_success(self, mock_client, memory): """Should add torrent successfully and update memory.""" mock_client.add_torrent.return_value = True @@ -298,7 +298,7 @@ class TestAddTorrentToQbittorrent: # Verify client was called correctly 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): """Should add to active downloads on success.""" mock_client.add_torrent.return_value = True @@ -313,7 +313,7 @@ class TestAddTorrentToQbittorrent: == "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): """Should set topic and end workflow.""" mock_client.add_torrent.return_value = True @@ -326,10 +326,10 @@ class TestAddTorrentToQbittorrent: assert mem.stm.current_topic == "downloading" 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): """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") @@ -349,7 +349,7 @@ class TestAddTorrentByIndex: - 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): """Should get torrent by index and add it.""" mock_client.add_torrent.return_value = True @@ -362,7 +362,7 @@ class TestAddTorrentByIndex: # Verify correct magnet was extracted and used 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): """Should extract correct magnet from index.""" mock_client.add_torrent.return_value = True diff --git a/tests/test_tools_edge_cases.py b/tests/test_tools_edge_cases.py index 23fb50e..ac24aa2 100644 --- a/tests/test_tools_edge_cases.py +++ b/tests/test_tools_edge_cases.py @@ -1,18 +1,16 @@ """Edge case tests for tools.""" - +import pytest from unittest.mock import Mock, patch -import pytest - -from agent.tools import api as api_tools -from agent.tools import filesystem as fs_tools -from infrastructure.persistence import get_memory +from alfred.agent.tools import api as api_tools +from alfred.agent.tools import filesystem as fs_tools +from alfred.infrastructure.persistence import get_memory class TestFindTorrentEdgeCases: """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): """Should handle empty query.""" mock_response = Mock() @@ -28,7 +26,7 @@ class TestFindTorrentEdgeCases: 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): """Should handle very long query.""" mock_response = Mock() @@ -47,7 +45,7 @@ class TestFindTorrentEdgeCases: # Should not crash 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): """Should handle special characters in query.""" mock_response = Mock() @@ -65,7 +63,7 @@ class TestFindTorrentEdgeCases: 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): """Should handle unicode in query.""" mock_response = Mock() @@ -82,7 +80,7 @@ class TestFindTorrentEdgeCases: 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): """Should handle results with missing fields.""" mock_response = Mock() @@ -104,7 +102,7 @@ class TestFindTorrentEdgeCases: mem = get_memory() 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): """Should handle API timeout.""" mock_use_case = Mock() @@ -157,7 +155,7 @@ class TestGetTorrentByIndexEdgeCases: class TestAddTorrentEdgeCases: """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): """Should handle invalid magnet link.""" mock_response = Mock() @@ -173,7 +171,7 @@ class TestAddTorrentEdgeCases: 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): """Should handle empty magnet link.""" mock_response = Mock() @@ -189,7 +187,7 @@ class TestAddTorrentEdgeCases: 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): """Should handle very long magnet link.""" mock_response = Mock() @@ -203,7 +201,7 @@ class TestAddTorrentEdgeCases: 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): """Should handle qBittorrent connection refused.""" mock_use_case = Mock() @@ -391,7 +389,7 @@ class TestFilesystemEdgeCases: class TestFindMediaImdbIdEdgeCases: """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): """Should handle movies with same name.""" mock_response = Mock() @@ -409,7 +407,7 @@ class TestFindMediaImdbIdEdgeCases: 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): """Should handle movies with special characters in title.""" mock_response = Mock() @@ -426,7 +424,7 @@ class TestFindMediaImdbIdEdgeCases: 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): """Should distinguish TV shows from movies.""" mock_response = Mock() diff --git a/tests/test_tools_filesystem.py b/tests/test_tools_filesystem.py index 706a477..21c8836 100644 --- a/tests/test_tools_filesystem.py +++ b/tests/test_tools_filesystem.py @@ -1,11 +1,9 @@ """Tests for filesystem tools.""" - +import pytest from pathlib import Path -import pytest - -from agent.tools import filesystem as fs_tools -from infrastructure.persistence import get_memory +from alfred.agent.tools import filesystem as fs_tools +from alfred.infrastructure.persistence import get_memory class TestSetPathForFolder: