mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Refactor presence API methods for clarity and consistency. Updated method names to include 'Presence' suffix for better identification. Enhanced presence state logic to support unique index-based upserts and improved test coverage for presence functionalities, including custom permissions and expiry handling.
This commit is contained in:
@@ -66,6 +66,9 @@ class PresenceState
|
||||
|
||||
try {
|
||||
if ($this->getSupportForUniqueIndexBasedUpsert()) {
|
||||
$presenceCreated = $dbForProject->findOne('presenceLogs', [Query::equal('userId', [$userId])])->isEmpty();
|
||||
$presence = $dbForProject->upsertDocument('presenceLogs', $presenceDocument);
|
||||
} else {
|
||||
$presence = $this->transactionalUpsertForUser(
|
||||
$dbForProject,
|
||||
$presenceDocument,
|
||||
@@ -73,9 +76,6 @@ class PresenceState
|
||||
$userId,
|
||||
$presenceCreated
|
||||
);
|
||||
} else {
|
||||
$presenceCreated = $dbForProject->findOne('presenceLogs', [Query::equal('userId', [$userId])])->isEmpty();
|
||||
$presence = $dbForProject->upsertDocument('presenceLogs', $presenceDocument);
|
||||
}
|
||||
|
||||
if ($presenceCreated && $onPresenceCreated !== null) {
|
||||
@@ -129,7 +129,7 @@ class PresenceState
|
||||
private function getSupportForUniqueIndexBasedUpsert(): bool
|
||||
{
|
||||
$adapter = \strtolower(System::getEnv('_APP_DB_ADAPTER', 'mariadb'));
|
||||
return \in_array($adapter, ['mongodb', 'postgres', 'postgresql'], true);
|
||||
return !\in_array($adapter, ['mongodb', 'postgres', 'postgresql'], true);
|
||||
}
|
||||
|
||||
private function assertPermissionsAgainstAuthorization(array $permissions, Authorization $authorization): void
|
||||
|
||||
@@ -41,7 +41,7 @@ class Delete extends Base
|
||||
->label('sdk', new Method(
|
||||
namespace: 'presences',
|
||||
group: 'presences',
|
||||
name: 'delete',
|
||||
name: 'deletePresence',
|
||||
description: 'Delete a presence log by its unique ID.',
|
||||
auth: [AuthType::ADMIN, AuthType::KEY, AuthType::SESSION, AuthType::JWT],
|
||||
responses: [
|
||||
|
||||
@@ -33,7 +33,7 @@ class Get extends Base
|
||||
->label('sdk', new Method(
|
||||
namespace: 'presences',
|
||||
group: 'presences',
|
||||
name: 'get',
|
||||
name: 'getPresence',
|
||||
description: 'Get a presence log by its unique ID.',
|
||||
auth: [AuthType::ADMIN, AuthType::KEY, AuthType::SESSION, AuthType::JWT],
|
||||
responses: [
|
||||
|
||||
@@ -45,7 +45,7 @@ class Update extends PresenceAction
|
||||
->label('sdk', new Method(
|
||||
namespace: 'presences',
|
||||
group: 'presences',
|
||||
name: 'update',
|
||||
name: 'updatePresence',
|
||||
description: 'Update a presence log by its unique ID.',
|
||||
auth: [AuthType::ADMIN, AuthType::KEY, AuthType::SESSION, AuthType::JWT],
|
||||
responses: [
|
||||
|
||||
@@ -49,7 +49,7 @@ class Upsert extends PresenceAction
|
||||
->label('sdk', new Method(
|
||||
namespace: 'presences',
|
||||
group: 'presences',
|
||||
name: 'upsert',
|
||||
name: 'upsertPresence',
|
||||
description: 'Create or update a presence log by its unique ID.',
|
||||
auth: [AuthType::ADMIN, AuthType::KEY, AuthType::SESSION, AuthType::JWT],
|
||||
responses: [
|
||||
|
||||
@@ -43,7 +43,7 @@ class XList extends Base
|
||||
->label('sdk', new Method(
|
||||
namespace: 'presences',
|
||||
group: 'presences',
|
||||
name: 'list',
|
||||
name: 'listPresences',
|
||||
description: 'List presence logs.',
|
||||
auth: [AuthType::ADMIN, AuthType::KEY, AuthType::SESSION, AuthType::JWT],
|
||||
responses: [
|
||||
|
||||
@@ -4,6 +4,8 @@ namespace Tests\E2E\Services\Presence;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
trait PresenceBase
|
||||
@@ -27,6 +29,19 @@ trait PresenceBase
|
||||
return self::$presenceApiKeyCache[$projectId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Server-side helper: ensure presences requests use a presence-scoped API key.
|
||||
*/
|
||||
protected function getPresenceServerHeaders(): array
|
||||
{
|
||||
$headers = $this->getHeaders(false);
|
||||
|
||||
// Override the project API key added by `SideServer` with a presence-scoped key.
|
||||
$headers['x-appwrite-key'] = $this->getPresenceApiKey();
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
protected function setupPresence(array $overrides = []): array
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
@@ -93,6 +108,8 @@ trait PresenceBase
|
||||
public function testUpsertAndGetPresence(): void
|
||||
{
|
||||
if ($this->getSide() === 'client') {
|
||||
$userId = $this->getUser()['$id'];
|
||||
|
||||
$upsert = $this->client->call(
|
||||
Client::METHOD_PUT,
|
||||
'/presences/' . ID::unique(),
|
||||
@@ -106,7 +123,24 @@ trait PresenceBase
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(401, $upsert['headers']['status-code']);
|
||||
$this->assertEquals(200, $upsert['headers']['status-code']);
|
||||
$this->assertNotEmpty($upsert['body']['$id']);
|
||||
$this->assertEquals($userId, $upsert['body']['userId']);
|
||||
|
||||
$get = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/presences/' . $upsert['body']['$id'],
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders(false))
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $get['headers']['status-code']);
|
||||
$this->assertEquals($upsert['body']['$id'], $get['body']['$id']);
|
||||
$this->assertEquals($userId, $get['body']['userId']);
|
||||
$this->assertArrayHasKey('expiry', $get['body']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -118,7 +152,7 @@ trait PresenceBase
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders(false))
|
||||
], $this->getPresenceServerHeaders())
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $get['headers']['status-code']);
|
||||
@@ -130,16 +164,78 @@ trait PresenceBase
|
||||
public function testListPresences(): void
|
||||
{
|
||||
if ($this->getSide() === 'client') {
|
||||
$upsert = $this->client->call(
|
||||
Client::METHOD_PUT,
|
||||
'/presences/' . ID::unique(),
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders(false)),
|
||||
[
|
||||
'status' => 'online',
|
||||
'metadata' => ['device' => 'web'],
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $upsert['headers']['status-code']);
|
||||
$this->assertNotEmpty($upsert['body']['$id']);
|
||||
$this->assertArrayHasKey('userId', $upsert['body']);
|
||||
|
||||
$list = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/presences',
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders(false))
|
||||
], $this->getHeaders(false)),
|
||||
[
|
||||
'queries' => [
|
||||
Query::equal('userId', [$upsert['body']['userId']])->toString(),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(401, $list['headers']['status-code']);
|
||||
$this->assertEquals(200, $list['headers']['status-code']);
|
||||
$this->assertArrayHasKey('total', $list['body']);
|
||||
$this->assertArrayHasKey('presences', $list['body']);
|
||||
$this->assertIsArray($list['body']['presences']);
|
||||
$this->assertGreaterThanOrEqual(1, $list['body']['total']);
|
||||
|
||||
// Client sessions must not be able to list presences belonging to a different user.
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$originalUser = $this->getUser();
|
||||
$otherUserId = $this->getUser(true)['$id'];
|
||||
|
||||
// Important: don't let `getUser(true)` overwrite the cached user/session for the rest
|
||||
// of this test run. We only need the other user's ID.
|
||||
self::$user[$projectId] = $originalUser;
|
||||
|
||||
// Seed another presence for the other user (setup via API key, not the client session).
|
||||
$this->setupPresence([
|
||||
'userId' => $otherUserId,
|
||||
'status' => 'online',
|
||||
'metadata' => ['device' => 'other-user'],
|
||||
]);
|
||||
|
||||
$otherList = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/presences',
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders(false)),
|
||||
[
|
||||
'queries' => [
|
||||
Query::equal('userId', [$otherUserId])->toString(),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $otherList['headers']['status-code']);
|
||||
$this->assertArrayHasKey('total', $otherList['body']);
|
||||
$this->assertArrayHasKey('presences', $otherList['body']);
|
||||
$this->assertSame([], $otherList['body']['presences']);
|
||||
$this->assertEquals(0, $otherList['body']['total']);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -151,7 +247,7 @@ trait PresenceBase
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders(false)),
|
||||
], $this->getPresenceServerHeaders()),
|
||||
[
|
||||
'queries' => [
|
||||
Query::equal('userId', [$presence['userId']])->toString(),
|
||||
@@ -166,12 +262,179 @@ trait PresenceBase
|
||||
$this->assertGreaterThanOrEqual(1, $list['body']['total']);
|
||||
}
|
||||
|
||||
public function testClientPresenceCustomPermissionsForOtherUser(): void
|
||||
{
|
||||
if ($this->getSide() !== 'client') {
|
||||
$this->expectNotToPerformAssertions();
|
||||
return;
|
||||
}
|
||||
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$user1 = $this->getUser();
|
||||
$headersUser1 = $this->getHeaders(false);
|
||||
|
||||
$user2 = $this->getUser(true);
|
||||
|
||||
// Avoid overwriting the cached user for the rest of the test run.
|
||||
self::$user[$projectId] = $user1;
|
||||
|
||||
$headersUser2 = $this->getHeaders(false);
|
||||
$headersUser2['cookie'] = 'a_session_' . $projectId . '=' . $user2['session'];
|
||||
|
||||
$permissionsForUser2 = [
|
||||
Permission::read(Role::user($user2['$id'])),
|
||||
Permission::update(Role::user($user2['$id'])),
|
||||
Permission::delete(Role::user($user2['$id'])),
|
||||
Permission::write(Role::user($user2['$id'])),
|
||||
];
|
||||
|
||||
$permissionsForUser1 = [
|
||||
Permission::read(Role::user($user1['$id'])),
|
||||
Permission::update(Role::user($user1['$id'])),
|
||||
Permission::delete(Role::user($user1['$id'])),
|
||||
Permission::write(Role::user($user1['$id'])),
|
||||
];
|
||||
|
||||
// Create a presence for user1 using a presence-scoped API key so we can set ACLs.
|
||||
$presenceAllow = $this->client->call(
|
||||
Client::METHOD_PUT,
|
||||
'/presences/' . ID::unique(),
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-key' => $this->getPresenceApiKey(),
|
||||
]),
|
||||
[
|
||||
'userId' => $user1['$id'],
|
||||
'status' => 'online',
|
||||
'metadata' => ['case' => 'allow'],
|
||||
// Owner always retains full permissions; user2 additionally gets access.
|
||||
'permissions' => \array_merge($permissionsForUser1, $permissionsForUser2),
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $presenceAllow['headers']['status-code']);
|
||||
$presenceIdAllow = $presenceAllow['body']['$id'];
|
||||
|
||||
// user2 can read
|
||||
$get = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/presences/' . $presenceIdAllow,
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $headersUser2)
|
||||
);
|
||||
$this->assertEquals(200, $get['headers']['status-code']);
|
||||
|
||||
// user2 can update
|
||||
$patch = $this->client->call(
|
||||
Client::METHOD_PATCH,
|
||||
'/presences/' . $presenceIdAllow,
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $headersUser2),
|
||||
[
|
||||
'status' => 'busy',
|
||||
'metadata' => ['case' => 'allow-update'],
|
||||
]
|
||||
);
|
||||
$this->assertEquals(200, $patch['headers']['status-code']);
|
||||
$this->assertEquals('busy', $patch['body']['status']);
|
||||
|
||||
// user2 can delete
|
||||
$delete = $this->client->call(
|
||||
Client::METHOD_DELETE,
|
||||
'/presences/' . $presenceIdAllow,
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $headersUser2)
|
||||
);
|
||||
$this->assertEquals(204, $delete['headers']['status-code']);
|
||||
|
||||
// Create another presence for user1 without granting any special permissions to user2.
|
||||
$presenceDeny = $this->client->call(
|
||||
Client::METHOD_PUT,
|
||||
'/presences/' . ID::unique(),
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-key' => $this->getPresenceApiKey(),
|
||||
]),
|
||||
[
|
||||
'userId' => $user1['$id'],
|
||||
'status' => 'online',
|
||||
'metadata' => ['case' => 'deny'],
|
||||
// Only the owner has permissions; user2 should not be able to access this document.
|
||||
'permissions' => $permissionsForUser1,
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $presenceDeny['headers']['status-code']);
|
||||
$presenceIdDeny = $presenceDeny['body']['$id'];
|
||||
|
||||
// user2 cannot read
|
||||
$getDeny = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/presences/' . $presenceIdDeny,
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $headersUser2)
|
||||
);
|
||||
// When read permission is missing, the document should be treated as not found.
|
||||
$this->assertEquals(404, $getDeny['headers']['status-code']);
|
||||
|
||||
// user2 cannot update
|
||||
$patchDeny = $this->client->call(
|
||||
Client::METHOD_PATCH,
|
||||
'/presences/' . $presenceIdDeny,
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $headersUser2),
|
||||
[
|
||||
'status' => 'busy',
|
||||
]
|
||||
);
|
||||
$this->assertEquals(404, $patchDeny['headers']['status-code']);
|
||||
|
||||
// user2 cannot delete
|
||||
$deleteDeny = $this->client->call(
|
||||
Client::METHOD_DELETE,
|
||||
'/presences/' . $presenceIdDeny,
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $headersUser2)
|
||||
);
|
||||
$this->assertEquals(404, $deleteDeny['headers']['status-code']);
|
||||
}
|
||||
|
||||
public function testUpdatePresenceSparseFields(): void
|
||||
{
|
||||
if ($this->getSide() === 'client') {
|
||||
$upsert = $this->client->call(
|
||||
Client::METHOD_PUT,
|
||||
'/presences/' . ID::unique(),
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders(false)),
|
||||
[
|
||||
'status' => 'away',
|
||||
'metadata' => ['source' => 'setup'],
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $upsert['headers']['status-code']);
|
||||
$presenceId = $upsert['body']['$id'];
|
||||
|
||||
$update = $this->client->call(
|
||||
Client::METHOD_PATCH,
|
||||
'/presences/' . ID::unique(),
|
||||
'/presences/' . $presenceId,
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
@@ -182,7 +445,10 @@ trait PresenceBase
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(401, $update['headers']['status-code']);
|
||||
$this->assertEquals(200, $update['headers']['status-code']);
|
||||
$this->assertEquals('busy', $update['body']['status']);
|
||||
$this->assertEquals(['source' => 'update'], $update['body']['metadata']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -206,7 +472,7 @@ trait PresenceBase
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders(false)),
|
||||
], $this->getPresenceServerHeaders()),
|
||||
$payload
|
||||
);
|
||||
|
||||
@@ -218,16 +484,33 @@ trait PresenceBase
|
||||
public function testDeletePresence(): void
|
||||
{
|
||||
if ($this->getSide() === 'client') {
|
||||
$upsert = $this->client->call(
|
||||
Client::METHOD_PUT,
|
||||
'/presences/' . ID::unique(),
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders(false)),
|
||||
[
|
||||
'status' => 'temp-delete',
|
||||
'metadata' => ['cleanup' => true],
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $upsert['headers']['status-code']);
|
||||
$presenceId = $upsert['body']['$id'];
|
||||
|
||||
$delete = $this->client->call(
|
||||
Client::METHOD_DELETE,
|
||||
'/presences/' . ID::unique(),
|
||||
'/presences/' . $presenceId,
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders(false))
|
||||
);
|
||||
|
||||
$this->assertEquals(401, $delete['headers']['status-code']);
|
||||
$this->assertEquals(204, $delete['headers']['status-code']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -242,7 +525,7 @@ trait PresenceBase
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders(false))
|
||||
], $this->getPresenceServerHeaders())
|
||||
);
|
||||
|
||||
$this->assertEquals(204, $delete['headers']['status-code']);
|
||||
@@ -263,7 +546,7 @@ trait PresenceBase
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -281,7 +564,7 @@ trait PresenceBase
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders(false)),
|
||||
], $this->getPresenceServerHeaders()),
|
||||
$payload
|
||||
);
|
||||
|
||||
@@ -324,7 +607,7 @@ trait PresenceBase
|
||||
\array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders(false)),
|
||||
], $this->getPresenceServerHeaders()),
|
||||
[
|
||||
'status' => 'online',
|
||||
]
|
||||
@@ -345,7 +628,7 @@ trait PresenceBase
|
||||
$headers = \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $this->getHeaders(false));
|
||||
], $this->getPresenceServerHeaders());
|
||||
|
||||
$firstUpsert = $this->client->call(
|
||||
Client::METHOD_PUT,
|
||||
|
||||
@@ -7,6 +7,7 @@ use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideServer;
|
||||
use Utopia\Console;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
|
||||
class PresenceExpiryTest extends Scope
|
||||
@@ -25,8 +26,8 @@ class PresenceExpiryTest extends Scope
|
||||
}
|
||||
|
||||
self::$presenceApiKeyCache[$projectId] = $this->getNewKey([
|
||||
'users.read',
|
||||
'users.write',
|
||||
'presence.read',
|
||||
'presence.write',
|
||||
]);
|
||||
|
||||
return self::$presenceApiKeyCache[$projectId];
|
||||
@@ -36,7 +37,8 @@ class PresenceExpiryTest extends Scope
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$userId = $this->getUser()['$id'];
|
||||
$expiredAt = \gmdate('Y-m-d\TH:i:s.v\Z', \time() - 120);
|
||||
// Must match the format used by the maintenance worker query.
|
||||
$expiredAt = DateTime::format((new \DateTime())->modify('-120 seconds'));
|
||||
|
||||
$createServer = $this->client->call(
|
||||
Client::METHOD_PUT,
|
||||
@@ -81,6 +83,7 @@ class PresenceExpiryTest extends Scope
|
||||
$code = Console::execute('docker exec appwrite maintenance --type=trigger', '', $stdout, $stderr);
|
||||
$this->assertSame(0, $code, "Maintenance command failed with code $code: $stderr ($stdout)");
|
||||
|
||||
// Maintenance + delete workers are asynchronous; give extra time to observe cleanup.
|
||||
$this->assertEventually(function () use ($presenceIdServer, $projectId) {
|
||||
$getServer = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
@@ -93,6 +96,6 @@ class PresenceExpiryTest extends Scope
|
||||
);
|
||||
|
||||
$this->assertEquals(404, $getServer['headers']['status-code']);
|
||||
});
|
||||
}, 30000, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ class PresenceRealtimeClientTest extends Scope
|
||||
use ProjectCustom;
|
||||
use SideClient;
|
||||
|
||||
private static array $presenceApiKeyCache = [];
|
||||
|
||||
private function bootstrapIsolatedProject(): array
|
||||
{
|
||||
$project = $this->getProject(true);
|
||||
@@ -37,10 +39,27 @@ class PresenceRealtimeClientTest extends Scope
|
||||
return [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $project['$id'],
|
||||
'x-appwrite-key' => $project['apiKey'],
|
||||
'x-appwrite-key' => $this->getPresenceApiKey($project),
|
||||
];
|
||||
}
|
||||
|
||||
private function getPresenceApiKey(array $project): string
|
||||
{
|
||||
$projectId = $project['$id'];
|
||||
|
||||
if (!empty(self::$presenceApiKeyCache[$projectId])) {
|
||||
return self::$presenceApiKeyCache[$projectId];
|
||||
}
|
||||
|
||||
// Realtime tests validate HTTP reads of presences; those endpoints require `presence.read`.
|
||||
self::$presenceApiKeyCache[$projectId] = $this->getNewKey([
|
||||
'presence.read',
|
||||
'presence.write',
|
||||
]);
|
||||
|
||||
return self::$presenceApiKeyCache[$projectId];
|
||||
}
|
||||
|
||||
private function connectRealtimeAndSubscribe(
|
||||
array $project,
|
||||
array $headers,
|
||||
|
||||
Reference in New Issue
Block a user