Files
laravel-llm-gateway/laravel-app/tests/Unit/Services/CostCalculatorTest.php
wtrinkl 6573e15ba4 Add complete Laravel LLM Gateway implementation
Core Features:
- Multi-provider support (OpenAI, Anthropic, DeepSeek, Gemini, Mistral)
- Provider service architecture with abstract base class
- Dynamic model discovery from provider APIs
- Encrypted per-user provider credentials storage

Admin Interface:
- Complete admin panel with Livewire components
- User management with CRUD operations
- API key management with testing capabilities
- Budget system with limits and reset schedules
- Usage logs with filtering and CSV export
- Model pricing management with cost calculator
- Dashboard with Chart.js visualizations

Database Schema:
- MariaDB migrations for all tables
- User provider credentials (encrypted)
- LLM request logging
- Budget tracking and rate limiting
- Model pricing configuration

API Implementation:
- OpenAI-compatible endpoints
- Budget checking middleware
- Rate limit enforcement
- Request logging jobs
- Cost calculation service

Testing:
- Unit tests for all provider services
- Provider factory tests
- Cost calculator tests

Documentation:
- Admin user seeder
- Model pricing seeder
- Configuration files
2025-11-18 22:18:36 +01:00

106 lines
3.1 KiB
PHP

<?php
namespace Tests\Unit\Services;
use Tests\TestCase;
use App\Services\LLM\CostCalculator;
use App\Models\ModelPricing;
use Illuminate\Support\Facades\Cache;
use Illuminate\Foundation\Testing\RefreshDatabase;
class CostCalculatorTest extends TestCase
{
use RefreshDatabase;
private CostCalculator $calculator;
protected function setUp(): void
{
parent::setUp();
$this->calculator = new CostCalculator();
}
public function test_calculates_cost_correctly(): void
{
ModelPricing::create([
'provider' => 'openai',
'model' => 'gpt-4o-mini',
'input_price_per_million' => 0.15,
'output_price_per_million' => 0.60,
'is_active' => true,
'effective_from' => now(),
]);
Cache::flush();
$costs = $this->calculator->calculate('openai', 'gpt-4o-mini', 1000, 500);
// (1000/1M * 0.15) + (500/1M * 0.60) = 0.00015 + 0.0003 = 0.00045
$this->assertEquals(0.00015, $costs['prompt_cost']);
$this->assertEquals(0.0003, $costs['completion_cost']);
$this->assertEquals(0.00045, $costs['total_cost']);
}
public function test_returns_zero_cost_for_unknown_model(): void
{
Cache::flush();
$costs = $this->calculator->calculate('unknown', 'unknown-model', 1000, 500);
$this->assertEquals(0.0, $costs['prompt_cost']);
$this->assertEquals(0.0, $costs['completion_cost']);
$this->assertEquals(0.0, $costs['total_cost']);
}
public function test_uses_cache_for_pricing(): void
{
ModelPricing::create([
'provider' => 'anthropic',
'model' => 'claude-sonnet-4',
'input_price_per_million' => 3.00,
'output_price_per_million' => 15.00,
'is_active' => true,
'effective_from' => now(),
]);
Cache::flush();
// First call - should query database
$costs1 = $this->calculator->calculate('anthropic', 'claude-sonnet-4', 1000, 500);
// Second call - should use cache
$costs2 = $this->calculator->calculate('anthropic', 'claude-sonnet-4', 1000, 500);
$this->assertEquals($costs1, $costs2);
$this->assertTrue(Cache::has('pricing:anthropic:claude-sonnet-4'));
}
public function test_estimate_cost(): void
{
ModelPricing::create([
'provider' => 'openai',
'model' => 'gpt-4o',
'input_price_per_million' => 2.50,
'output_price_per_million' => 10.00,
'is_active' => true,
'effective_from' => now(),
]);
Cache::flush();
$estimatedCost = $this->calculator->estimateCost('openai', 'gpt-4o', 2000, 1000);
// (2000/1M * 2.50) + (1000/1M * 10.00) = 0.005 + 0.01 = 0.015
$this->assertEquals(0.015, $estimatedCost);
}
public function test_clear_cache(): void
{
Cache::put('pricing:test:model', 'test_data', 3600);
$this->calculator->clearCache('test', 'model');
$this->assertFalse(Cache::has('pricing:test:model'));
}
}