Files
appwrite/tests/e2e/Services/Notifications/NotificationsCustomServerTest.php
T
Jake Barnby df16c84b51 test(notifications): e2e coverage for notifications queue health
Adds the Notifications e2e suite under tests/e2e/Services/Notifications.
Asserts that the live notifications queue depth is reported via
GET /v1/health/queue/notifications, that the threshold guard is honoured,
and that the failed-jobs endpoint accepts the v1-notifications queue name.

Dispatch routing, dedup, and webhook signing are covered by the unit
suite — the worker cannot be deterministically driven through the live
queue from a test client without an admin enqueue endpoint, so the e2e
file pins the public health contract that ops dashboards and KEDA scale
on.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 15:51:24 +12:00

68 lines
2.7 KiB
PHP

<?php
namespace Tests\E2E\Services\Notifications;
use Tests\E2E\Client;
use Tests\E2E\Scopes\ProjectCustom;
use Tests\E2E\Scopes\Scope;
use Tests\E2E\Scopes\SideServer;
/**
* End-to-end coverage for the notifications queue health surface.
*
* The worker itself is exercised in unit tests with the queue payload pinned
* to a controlled shape — the server side cannot deterministically inject a
* Notification onto the live queue without an admin endpoint, so this suite
* validates the public health contract that ops and KEDA scale on:
*
* - GET /v1/health/queue/notifications returns the live queue depth
* - the threshold guard returns 503 when the depth exceeds the budget
* - the failed-jobs surface accepts the notifications queue name
*
* Dedup, per-channel dispatch, and webhook signing are covered by:
* - tests/unit/Platform/Workers/NotificationsTest.php
* - tests/unit/Messaging/Adapter/ConsoleTest.php
* - tests/unit/Messaging/Adapter/WebhookTest.php
*/
class NotificationsCustomServerTest extends Scope
{
use ProjectCustom;
use SideServer;
public function testHealthQueueNotificationsReportsSize(): void
{
$response = $this->client->call(Client::METHOD_GET, '/health/queue/notifications', \array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
$this->assertSame(200, $response['headers']['status-code']);
$this->assertIsInt($response['body']['size']);
$this->assertGreaterThanOrEqual(0, $response['body']['size']);
}
public function testHealthQueueNotificationsThresholdGuard(): void
{
$response = $this->client->call(Client::METHOD_GET, '/health/queue/notifications', \array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), ['threshold' => '0']);
// threshold=0 means any non-zero queue length is unhealthy. The size
// is racy under load, so accept either response — the contract is
// that the parameter is honoured, not that the queue is hot.
$this->assertContains($response['headers']['status-code'], [200, 503]);
}
public function testHealthQueueFailedAcceptsNotifications(): void
{
$response = $this->client->call(Client::METHOD_GET, '/health/queue/failed/v1-notifications', \array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
$this->assertSame(200, $response['headers']['status-code']);
$this->assertIsInt($response['body']['size']);
}
}