From ffeb27e5a371c6e092892a6663daa88410badd17 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Fri, 8 May 2026 14:36:59 +0530 Subject: [PATCH] updated presence test --- tests/e2e/Services/Presence/PresenceBase.php | 91 ++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/tests/e2e/Services/Presence/PresenceBase.php b/tests/e2e/Services/Presence/PresenceBase.php index c70379e1fb..f04afbbec1 100644 --- a/tests/e2e/Services/Presence/PresenceBase.php +++ b/tests/e2e/Services/Presence/PresenceBase.php @@ -908,4 +908,95 @@ trait PresenceBase $this->assertEquals($userId, $list['body']['presences'][0]['userId']); $this->assertEquals('away', $list['body']['presences'][0]['status']); } + + public function testUpsertSameUserDifferentIdsReplacesRow(): void + { + if ($this->getSide() !== 'server') { + $this->expectNotToPerformAssertions(); + return; + } + + $projectId = $this->getProject()['$id']; + $originalUser = $this->getUser(); + // Fresh user so this test isn't entangled with rows seeded by other tests in the suite. + $targetUserId = $this->getUser(true)['$id']; + // Restore the suite's cached user/session so subsequent tests aren't affected. + self::$user[$projectId] = $originalUser; + + $headers = \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + ], $this->getPresenceServerHeaders()); + + $firstId = ID::unique(); + $first = $this->client->call( + Client::METHOD_PUT, + '/presences/' . $firstId, + $headers, + [ + 'userId' => $targetUserId, + 'status' => 'online', + 'metadata' => ['source' => 'first'], + ] + ); + $this->assertEquals(200, $first['headers']['status-code']); + $this->assertEquals($firstId, $first['body']['$id']); + $this->assertEquals($targetUserId, $first['body']['userId']); + + $secondId = ID::unique(); + $this->assertNotEquals($firstId, $secondId); + + $second = $this->client->call( + Client::METHOD_PUT, + '/presences/' . $secondId, + $headers, + [ + 'userId' => $targetUserId, + 'status' => 'away', + 'metadata' => ['source' => 'second'], + ] + ); + $this->assertEquals(200, $second['headers']['status-code']); + // Returned $id must be the one we asked for — not silently aliased to the prior row. + $this->assertEquals($secondId, $second['body']['$id']); + $this->assertEquals($targetUserId, $second['body']['userId']); + $this->assertEquals('away', $second['body']['status']); + $this->assertEquals(['source' => 'second'], $second['body']['metadata']); + + // Old presenceId is gone (the unique-key-on-userInternalId guarantees one row per user; + // an ID change must replace the prior row, not coexist with it). + $oldGet = $this->client->call( + Client::METHOD_GET, + '/presences/' . $firstId, + $headers + ); + $this->assertEquals(404, $oldGet['headers']['status-code']); + + // New presenceId is reachable and matches the upsert response. + $newGet = $this->client->call( + Client::METHOD_GET, + '/presences/' . $secondId, + $headers + ); + $this->assertEquals(200, $newGet['headers']['status-code']); + $this->assertEquals($secondId, $newGet['body']['$id']); + $this->assertEquals($targetUserId, $newGet['body']['userId']); + $this->assertEquals('away', $newGet['body']['status']); + + // Listing the user surfaces exactly one row, carrying the new $id. + $list = $this->client->call( + Client::METHOD_GET, + '/presences', + $headers, + [ + 'queries' => [ + Query::equal('userId', [$targetUserId])->toString(), + ], + ] + ); + $this->assertEquals(200, $list['headers']['status-code']); + $this->assertEquals(1, $list['body']['total']); + $this->assertCount(1, $list['body']['presences']); + $this->assertEquals($secondId, $list['body']['presences'][0]['$id']); + } }