New_Micro_Learning/backend/tests/Unit/AI/OpenAiCompatibleProviderTes...

92 خطوط
3.3 KiB
PHP

<?php
namespace Tests\Unit\AI;
use App\Modules\AI\Infrastructure\AiEndpointPolicy;
use App\Modules\AI\Infrastructure\OpenAiCompatibleProvider;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Support\Facades\Http;
use RuntimeException;
use Tests\TestCase;
class OpenAiCompatibleProviderTest extends TestCase
{
public function test_openai_environment_contract_is_defined_in_config(): void
{
$this->assertNull(config('ai.provider'));
$this->assertNull(config('ai.ollama'));
$this->assertIsString(config('ai.openai.base_url'));
$this->assertIsArray(config('ai.openai.models'));
$this->assertArrayHasKey('fast', config('ai.openai.models'));
$this->assertArrayHasKey('balanced', config('ai.openai.models'));
$this->assertArrayHasKey('advanced', config('ai.openai.models'));
$this->assertIsInt(config('ai.openai.timeout'));
}
public function test_ollama_reachable_and_unavailable_health_states_are_reported(): void
{
Http::fakeSequence()
->push(['data' => [['id' => 'qwen']]])
->push([], 503);
$this->assertTrue($this->ollama()->health()['connected']);
$this->assertFalse($this->ollama()->health()['connected']);
}
public function test_invalid_model_fails_without_silent_fallback(): void
{
Http::fake(['*/chat/completions' => Http::response(['error' => 'model not found'], 404)]);
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('404');
$this->ollama()->chat('hello');
}
public function test_provider_timeout_is_not_silently_swallowed(): void
{
Http::fake(fn () => throw new ConnectionException('timeout'));
$this->expectException(ConnectionException::class);
$this->ollama()->chat('hello');
}
public function test_openai_compatible_assist_and_invalid_credentials_are_handled(): void
{
$provider = $this->online();
Http::fake(['*/chat/completions' => Http::response(['choices' => [['message' => ['content' => '{"result":"ok"}']]]])]);
$this->assertSame('ok', $provider->assist('rewrite', 'content', [])['proposal']['result']);
Http::fake(['*/models' => Http::response(['error' => 'unauthorized'], 401)]);
$this->assertFalse($provider->health()['connected']);
}
private function ollama(): OpenAiCompatibleProvider
{
return new OpenAiCompatibleProvider(new AiEndpointPolicy(customProviderHosts: []), [
'id' => 'ollama',
'provider' => 'ollama',
'mode' => 'local',
'base_url' => 'http://127.0.0.1:11434/v1',
'api_key' => '',
'default_model' => 'qwen',
'timeout_seconds' => 10,
]);
}
private function online(): OpenAiCompatibleProvider
{
return new OpenAiCompatibleProvider(new AiEndpointPolicy(
resolver: fn (string $host): array => ['93.184.216.34'],
customProviderHosts: ['ai.example.test'],
), [
'id' => 'online',
'provider' => 'openai_compatible',
'mode' => 'online',
'base_url' => 'https://ai.example.test/v1',
'api_key' => 'secret',
'default_model' => 'model-a',
'timeout_seconds' => 10,
]);
}
}