|
10 | 10 | use Carbon\CarbonImmutable; |
11 | 11 | use Illuminate\Support\Facades\Cache; |
12 | 12 | use Illuminate\Support\Facades\Http; |
| 13 | +use Spatie\ResponseCache\Facades\ResponseCache; |
13 | 14 |
|
14 | 15 | use function Pest\Laravel\assertDatabaseHas; |
15 | 16 |
|
@@ -76,3 +77,33 @@ function spendLogsPayload(int $promptTokens): array |
76 | 77 |
|
77 | 78 | expect(Cache::get(LlmUsageStatsAction::VERSION_CACHE_KEY))->toBeGreaterThan($versionBefore); |
78 | 79 | })->group('llm-analytics'); |
| 80 | + |
| 81 | +it('does not clear the response cache when a single day is stored', function () { |
| 82 | + $responseCache = ResponseCache::spy(); |
| 83 | + |
| 84 | + (new StoreLlmUsageAction)->store(collect([[ |
| 85 | + 'date' => '2026-07-20', |
| 86 | + 'model' => 'qwen3.6:35b', |
| 87 | + 'prompt_tokens' => 100, |
| 88 | + 'completion_tokens' => 50, |
| 89 | + 'total_tokens' => 150, |
| 90 | + 'requests' => 1, |
| 91 | + 'spend' => 0.5, |
| 92 | + ]])); |
| 93 | + |
| 94 | + // Clearing the whole site's rendered HTML is the sync's decision, not one day's — |
| 95 | + // otherwise an hourly run wipes the response cache once per day in its window. |
| 96 | + $responseCache->shouldNotHaveReceived('clear'); |
| 97 | +})->group('llm-analytics'); |
| 98 | + |
| 99 | +it('clears the response cache once after the whole sync batch finishes', function () { |
| 100 | + Http::fake(['llm.codebar.net/spend/logs*' => Http::response(spendLogsPayload(promptTokens: 100))]); |
| 101 | + |
| 102 | + $responseCache = ResponseCache::spy(); |
| 103 | + |
| 104 | + runArtisan('llm:fetch-analytics', ['--from' => '2026-07-20', '--to' => '2026-07-23']) |
| 105 | + ->assertSuccessful(); |
| 106 | + |
| 107 | + // Four days were synced; the rendered pages are dropped exactly once. |
| 108 | + $responseCache->shouldHaveReceived('clear')->once(); |
| 109 | +})->group('llm-analytics'); |
0 commit comments