mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
152 lines
5.3 KiB
PHP
152 lines
5.3 KiB
PHP
<?php
|
|
|
|
namespace Tests\E2E\Services\Realtime;
|
|
|
|
use WebSocket\Client as WebSocketClient;
|
|
use WebSocket\ConnectionException;
|
|
|
|
trait RealtimeBase
|
|
{
|
|
private function getWebsocket(
|
|
array $channels = [],
|
|
array $headers = [],
|
|
?string $projectId = null,
|
|
?array $queries = null,
|
|
int $timeout = 2
|
|
): WebSocketClient {
|
|
if (is_null($projectId)) {
|
|
$projectId = $this->getProject()['$id'];
|
|
}
|
|
|
|
$query = [
|
|
"project" => $projectId,
|
|
"channels" => $channels
|
|
];
|
|
|
|
/**
|
|
* 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].
|
|
*
|
|
* 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);
|
|
}
|
|
}
|
|
}
|
|
|
|
return new WebSocketClient(
|
|
"ws://appwrite.test/v1/realtime?" . $queryString,
|
|
[
|
|
"headers" => $headers,
|
|
"timeout" => $timeout,
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
* @param int $timeout Timeout in seconds (default: 2)
|
|
* @return WebSocketClient
|
|
*/
|
|
private function getWebsocketWithCustomQuery(array $queryParams, array $headers = [], int $timeout = 2): WebSocketClient
|
|
{
|
|
$queryString = http_build_query($queryParams);
|
|
|
|
return new WebSocketClient(
|
|
"ws://appwrite.test/v1/realtime?" . $queryString,
|
|
[
|
|
"headers" => $headers,
|
|
"timeout" => $timeout,
|
|
]
|
|
);
|
|
}
|
|
|
|
public function testConnection(): void
|
|
{
|
|
/**
|
|
* Test for SUCCESS
|
|
*/
|
|
$client = $this->getWebsocket(["rows"]);
|
|
$this->assertNotEmpty($client->receive());
|
|
$client->close();
|
|
}
|
|
|
|
public function testConnectionSuccessMissingChannels(): void
|
|
{
|
|
$client = $this->getWebsocket([]);
|
|
$payload = json_decode($client->receive(), true);
|
|
|
|
$this->assertArrayHasKey("type", $payload);
|
|
$this->assertArrayHasKey("data", $payload);
|
|
$this->assertEquals("connected", $payload["type"]);
|
|
$client->close();
|
|
}
|
|
|
|
public function testConnectionFailureUnknownProject(): void
|
|
{
|
|
$client = $this->getWebsocket(projectId: '123');
|
|
$payload = json_decode($client->receive(), true);
|
|
|
|
$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
|
|
$this->expectException(ConnectionException::class); // Check if server disconnected client
|
|
$client->close();
|
|
}
|
|
|
|
public function testConnectionRegionCheck(): void
|
|
{
|
|
/**
|
|
* Test for SUCCESS
|
|
* A project whose region matches the server region should connect successfully.
|
|
*/
|
|
$client = $this->getWebsocket(['documents']);
|
|
$response = json_decode($client->receive(), true);
|
|
|
|
$this->assertArrayHasKey('type', $response);
|
|
$this->assertArrayHasKey('data', $response);
|
|
$this->assertEquals('connected', $response['type']);
|
|
$this->assertNotEmpty($response['data']);
|
|
$this->assertArrayHasKey('channels', $response['data']);
|
|
$this->assertContains('documents', $response['data']['channels']);
|
|
|
|
$client->close();
|
|
}
|
|
}
|