File size: 7,011 Bytes
1b447de
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
"""
Testes para módulo de LLM providers
"""
import pytest
from src.llms.base import BaseLLM
from src.llms.factory import create_llm, get_available_providers, _get_fallback_order


class TestBaseLLM:
    """Testes para classe base BaseLLM"""

    def test_validate_parameters_valid(self):
        """Testa validação de parâmetros válidos"""
        # Cria mock de BaseLLM
        class MockLLM(BaseLLM):
            def generate(self, prompt, temperature=0.3, max_tokens=512, **kwargs):
                return "mock response"

            def is_available(self):
                return True

            def get_model_info(self):
                return {"provider": "mock"}

        llm = MockLLM("test-model")

        # Testa parâmetros válidos
        valid, msg = llm.validate_parameters(0.5, 256)
        assert valid is True
        assert msg == ""

    def test_validate_parameters_invalid_temperature(self):
        """Testa validação com temperature inválida"""
        class MockLLM(BaseLLM):
            def generate(self, prompt, temperature=0.3, max_tokens=512, **kwargs):
                return "mock response"

            def is_available(self):
                return True

            def get_model_info(self):
                return {"provider": "mock"}

        llm = MockLLM("test-model")

        # Temperature muito alta
        valid, msg = llm.validate_parameters(3.0, 256)
        assert valid is False
        assert "Temperature" in msg

        # Temperature negativa
        valid, msg = llm.validate_parameters(-0.5, 256)
        assert valid is False
        assert "Temperature" in msg

    def test_validate_parameters_invalid_max_tokens(self):
        """Testa validação com max_tokens inválido"""
        class MockLLM(BaseLLM):
            def generate(self, prompt, temperature=0.3, max_tokens=512, **kwargs):
                return "mock response"

            def is_available(self):
                return True

            def get_model_info(self):
                return {"provider": "mock"}

        llm = MockLLM("test-model")

        # Max tokens zero
        valid, msg = llm.validate_parameters(0.5, 0)
        assert valid is False
        assert "tokens" in msg

        # Max tokens muito alto
        valid, msg = llm.validate_parameters(0.5, 10000)
        assert valid is False
        assert "tokens" in msg


class TestFactory:
    """Testes para factory de LLM providers"""

    def test_get_fallback_order(self):
        """Testa ordem de fallback"""
        # Provider primário deve ser primeiro
        order = _get_fallback_order("openai")
        assert order[0] == "openai"
        assert len(order) == 4

        # Todos providers devem estar presentes
        assert "huggingface" in order
        assert "anthropic" in order
        assert "ollama" in order

    def test_create_llm_without_credentials(self):
        """Testa criação de LLM sem credenciais"""
        # Sem credenciais, deve tentar criar mas não estar disponível
        llm = create_llm(provider="huggingface", fallback=False)

        # LLM criado mas não disponível sem token
        if llm:
            assert llm.is_available() is False

    def test_get_available_providers(self):
        """Testa listagem de providers disponíveis"""
        providers = get_available_providers()

        # Deve retornar dicionário com todos os providers
        assert isinstance(providers, dict)
        assert "huggingface" in providers
        assert "openai" in providers
        assert "anthropic" in providers
        assert "ollama" in providers

        # Cada provider deve ter estrutura esperada
        for provider_name, info in providers.items():
            assert "available" in info
            assert "info" in info
            assert "error" in info
            assert isinstance(info["available"], bool)


class TestHuggingFaceLLM:
    """Testes para HuggingFace provider"""

    def test_initialization_without_token(self):
        """Testa inicialização sem token"""
        from src.llms.huggingface import HuggingFaceLLM

        llm = HuggingFaceLLM("test-model", "")
        assert llm.is_available() is False
        assert llm.model_id == "test-model"

    def test_get_model_info(self):
        """Testa obtenção de informações do modelo"""
        from src.llms.huggingface import HuggingFaceLLM

        llm = HuggingFaceLLM("test-model", "fake-token")
        info = llm.get_model_info()

        assert info["provider"] == "HuggingFace"
        assert info["model_id"] == "test-model"
        assert "available" in info
        assert info["api_type"] == "Inference API"


class TestOpenAILLM:
    """Testes para OpenAI provider"""

    def test_initialization_without_key(self):
        """Testa inicialização sem API key"""
        from src.llms.openai import OpenAILLM

        llm = OpenAILLM("gpt-3.5-turbo", "")
        # Pode ou não estar disponível dependendo se biblioteca instalada
        assert llm.model_id == "gpt-3.5-turbo"

    def test_get_model_info(self):
        """Testa obtenção de informações do modelo"""
        from src.llms.openai import OpenAILLM

        llm = OpenAILLM("gpt-4", "fake-key")
        info = llm.get_model_info()

        assert info["provider"] == "OpenAI"
        assert info["model_id"] == "gpt-4"
        assert "available" in info
        assert info["api_type"] == "Chat Completions"


class TestAnthropicLLM:
    """Testes para Anthropic provider"""

    def test_initialization_without_key(self):
        """Testa inicialização sem API key"""
        from src.llms.anthropic import AnthropicLLM

        llm = AnthropicLLM("claude-3-haiku-20240307", "")
        assert llm.model_id == "claude-3-haiku-20240307"

    def test_get_model_info(self):
        """Testa obtenção de informações do modelo"""
        from src.llms.anthropic import AnthropicLLM

        llm = AnthropicLLM("claude-3-sonnet-20240229", "fake-key")
        info = llm.get_model_info()

        assert info["provider"] == "Anthropic"
        assert info["model_id"] == "claude-3-sonnet-20240229"
        assert "available" in info
        assert info["api_type"] == "Messages API"


class TestOllamaLLM:
    """Testes para Ollama provider"""

    def test_initialization(self):
        """Testa inicialização"""
        from src.llms.ollama import OllamaLLM

        llm = OllamaLLM("llama2", "http://localhost:11434")
        assert llm.model_id == "llama2"
        assert llm.base_url == "http://localhost:11434"

    def test_get_model_info(self):
        """Testa obtenção de informações do modelo"""
        from src.llms.ollama import OllamaLLM

        llm = OllamaLLM("mistral", "http://localhost:11434")
        info = llm.get_model_info()

        assert info["provider"] == "Ollama"
        assert info["model_id"] == "mistral"
        assert "available" in info
        assert info["api_type"] == "Local API"
        assert info["base_url"] == "http://localhost:11434"