appwrite/tests/e2e/Services/Realtime/RealtimeBase.php

135 lines
4.8 KiB
PHP
Raw Normal View History

<?php
namespace Tests\E2E\Services\Realtime;
2021-12-06 12:03:12 +00:00
use WebSocket\Client as WebSocketClient;
2024-03-06 17:34:21 +00:00
use WebSocket\ConnectionException;
2021-03-02 18:01:34 +00:00
trait RealtimeBase
{
2024-09-30 15:08:17 +00:00
private function getWebsocket(
array $channels = [],
array $headers = [],
string $projectId = null,
?array $queries = null
2024-09-30 15:08:17 +00:00
): WebSocketClient {
2021-12-06 12:03:12 +00:00
if (is_null($projectId)) {
$projectId = $this->getProject()['$id'];
}
2021-03-02 18:01:34 +00:00
$query = [
2024-09-30 15:08:17 +00:00
"project" => $projectId,
"channels" => $channels
2021-03-02 18:01:34 +00:00
];
2021-12-06 12:03:12 +00:00
/**
* Query param encoding rules:
* - $queries === null -> only send channels (no per-channel query params) for backward compatibility.
* - $queries === [] -> explicit "select all" subscription: send Query::select(['*']) as a single group.
* - non-empty $queries -> treat as a single subscription group for the first channel:
* AND logic within the group; OR logic across multiple groups (if we ever add them).
*
* For now all E2E tests subscribe to a single channel, so we map queries to $channels[0].
2026-02-03 06:13:23 +00:00
*
* Slot-based format: channel[slot][]=query1&channel[slot][]=query2
* We need to manually build the query string to ensure the [] format is used.
*/
// Build base query string
$queryParams = [
"project" => $projectId,
"channels" => $channels
];
$queryString = http_build_query($queryParams);
if ($queries !== null && !empty($channels)) {
$channel = $channels[0];
$slot = 0; // All tests use slot 0 for now
if ($queries === []) {
// Explicit select("*") group - single query in slot 0
$queryValue = \Utopia\Database\Query::select(['*'])->toString();
$queryString .= "&" . urlencode($channel) . "[" . $slot . "][]=" . urlencode($queryValue);
} else {
// Single subscription group for this channel - multiple queries in slot 0
// Each query should be appended with [] format
foreach ($queries as $queryValue) {
$queryString .= "&" . urlencode($channel) . "[" . $slot . "][]=" . urlencode($queryValue);
}
}
}
2024-09-30 15:08:17 +00:00
return new WebSocketClient(
"ws://appwrite.test/v1/realtime?" . $queryString,
2024-09-30 15:08:17 +00:00
[
"headers" => $headers,
"timeout" => 30,
]
);
2021-03-02 18:01:34 +00:00
}
/**
* Build WebSocket client with custom query parameters.
* Useful for testing edge cases like project in header only, or project as Query array.
*
* @param array $queryParams Custom query parameters (e.g., ['channels' => ['project'], 'project' => [...]])
* @param array $headers HTTP headers
* @return WebSocketClient
*/
private function getWebsocketWithCustomQuery(array $queryParams, array $headers = []): WebSocketClient
{
$queryString = http_build_query($queryParams);
return new WebSocketClient(
"ws://appwrite.test/v1/realtime?" . $queryString,
[
"headers" => $headers,
"timeout" => 30,
]
);
}
2022-01-03 14:01:35 +00:00
public function testConnection(): void
2021-03-02 18:01:34 +00:00
{
/**
* Test for SUCCESS
*/
2025-04-27 05:06:21 +00:00
$client = $this->getWebsocket(["rows"]);
2021-08-27 09:20:49 +00:00
$this->assertNotEmpty($client->receive());
2021-03-02 18:01:34 +00:00
$client->close();
2022-01-03 14:01:35 +00:00
}
2021-03-02 18:01:34 +00:00
2022-01-03 14:01:35 +00:00
public function testConnectionFailureMissingChannels(): void
{
2025-04-14 13:34:22 +00:00
$client = $this->getWebsocket([]);
2021-03-11 09:50:19 +00:00
$payload = json_decode($client->receive(), true);
2021-08-27 08:20:44 +00:00
2024-09-30 15:08:17 +00:00
$this->assertArrayHasKey("type", $payload);
$this->assertArrayHasKey("data", $payload);
$this->assertEquals("error", $payload["type"]);
$this->assertEquals(1008, $payload["data"]["code"]);
$this->assertEquals("Missing channels", $payload["data"]["message"]);
2022-02-22 17:01:03 +00:00
\usleep(250000); // 250ms
2025-04-27 05:06:21 +00:00
$this->expectException(ConnectionException::class); // Check if server disconnected client
2021-03-02 18:01:34 +00:00
$client->close();
2022-01-03 14:01:35 +00:00
}
2021-03-02 18:01:34 +00:00
2022-01-03 14:01:35 +00:00
public function testConnectionFailureUnknownProject(): void
{
2025-04-14 13:34:22 +00:00
$client = $this->getWebsocket(projectId: '123');
2021-03-11 09:50:19 +00:00
$payload = json_decode($client->receive(), true);
2021-08-27 08:20:44 +00:00
2024-09-30 15:08:17 +00:00
$this->assertArrayHasKey("type", $payload);
$this->assertArrayHasKey("data", $payload);
$this->assertEquals("error", $payload["type"]);
$this->assertEquals(1008, $payload["data"]["code"]);
$this->assertEquals(
"Missing or unknown project ID",
$payload["data"]["message"]
);
\usleep(250000); // 250ms
2025-04-27 05:06:21 +00:00
$this->expectException(ConnectionException::class); // Check if server disconnected client
2021-03-02 18:01:34 +00:00
$client->close();
}
2021-03-02 13:06:54 +00:00
}