agent/php/tests/Feature/Mcp/Middleware/CheckMcpQuotaTest.php
Snider 8091bad2c0 feat(mcp): implement §4 Middleware (5 middleware classes) (#852)
Additive-only — no existing files modified.

- McpApiKeyAuth: validates Bearer or X-MCP-API-Key header, attaches
  workspace context
- CheckMcpQuota: consumes via McpQuotaService, exposes MCP quota headers
- ValidateWorkspaceContext: normalises + enforces authenticated workspace scope
- ValidateToolDependencies: JSON-RPC + flat tool-call payload validation
  via ToolDependencyService
- McpAuthenticate: combined auth gate chaining the full stack

Pest Feature tests _Good/_Bad/_Ugly per AX-10 for each middleware.
pest skipped (vendor binaries missing in sandbox).

Co-authored-by: Codex <noreply@openai.com>
Closes tasks.lthn.sh/view.php?id=852
2026-04-25 05:25:09 +01:00

62 lines
2.3 KiB
PHP

<?php
// SPDX-License-Identifier: EUPL-1.2
declare(strict_types=1);
use Core\Mod\Agentic\Mcp\Services\McpQuotaService;
use Core\Mod\Agentic\Website\Mcp\Middleware\CheckMcpQuota;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
beforeEach(function (): void {
Cache::flush();
config()->set('mcp.quota_limit', 3);
config()->set('mcp.quota_period', 'minute');
});
test('CheckMcpQuota_handle_Good_consumes_workspace_quota_and_sets_response_headers', function (): void {
$workspace = createWorkspace();
$service = new McpQuotaService;
$service->setQuota($workspace->id, 3);
$middleware = new CheckMcpQuota($service);
$request = Request::create('/api/v1/mcp/tools/call', 'POST');
$request->attributes->set('workspace_id', $workspace->id);
$response = $middleware->handle($request, fn () => response()->json(['success' => true]));
expect($response->getStatusCode())->toBe(200)
->and($service->currentUsage($workspace->id))->toBe(1)
->and($response->headers->get('X-MCP-Quota-Limit'))->toBe('3')
->and($response->headers->get('X-MCP-Quota-Used'))->toBe('1')
->and($response->headers->get('X-MCP-Quota-Remaining'))->toBe('2');
});
test('CheckMcpQuota_handle_Bad_rejects_workspaces_that_have_exhausted_their_quota', function (): void {
$workspace = createWorkspace();
$service = new McpQuotaService;
$service->setQuota($workspace->id, 1);
$service->consume($workspace->id);
$middleware = new CheckMcpQuota($service);
$request = Request::create('/api/v1/mcp/tools/call', 'POST');
$request->attributes->set('workspace_id', $workspace->id);
$response = $middleware->handle($request, fn () => response()->json(['success' => true]));
$data = json_decode((string) $response->getContent(), true);
expect($response->getStatusCode())->toBe(429)
->and($data['error'])->toBe('quota_exceeded');
});
test('CheckMcpQuota_handle_Ugly_skips_quota_checks_when_workspace_context_is_absent', function (): void {
$service = new McpQuotaService;
$middleware = new CheckMcpQuota($service);
$request = Request::create('/api/v1/mcp/tools/call', 'POST');
$response = $middleware->handle($request, fn () => response()->json(['success' => true]));
expect($response->getStatusCode())->toBe(200)
->and($request->attributes->has('mcp_quota'))->toBeFalse();
});