mirror of
https://github.com/appwrite/appwrite
synced 2026-04-21 21:47:16 +00:00
858 lines
26 KiB
PHP
858 lines
26 KiB
PHP
<?php
|
|
|
|
namespace Tests\E2E\Services\Project;
|
|
|
|
use Appwrite\Tests\Async;
|
|
use Tests\E2E\Client;
|
|
use Utopia\Database\Document;
|
|
use Utopia\Database\Helpers\ID;
|
|
use Utopia\Database\Query;
|
|
use Utopia\Database\Validator\Datetime as DatetimeValidator;
|
|
|
|
trait KeysBase
|
|
{
|
|
use Async;
|
|
|
|
// =========================================================================
|
|
// Create key tests
|
|
// =========================================================================
|
|
|
|
public function testCreateKey(): void
|
|
{
|
|
$key = $this->createKey(
|
|
ID::unique(),
|
|
'My API Key',
|
|
['users.read', 'users.write'],
|
|
);
|
|
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
$this->assertNotEmpty($key['body']['$id']);
|
|
$this->assertSame('My API Key', $key['body']['name']);
|
|
$this->assertSame(['users.read', 'users.write'], $key['body']['scopes']);
|
|
$this->assertNotEmpty($key['body']['secret']);
|
|
$this->assertSame('', $key['body']['expire']);
|
|
$this->assertSame('', $key['body']['accessedAt']);
|
|
$this->assertSame([], $key['body']['sdks']);
|
|
|
|
$dateValidator = new DatetimeValidator();
|
|
$this->assertSame(true, $dateValidator->isValid($key['body']['$createdAt']));
|
|
$this->assertSame(true, $dateValidator->isValid($key['body']['$updatedAt']));
|
|
|
|
// Verify via GET
|
|
$get = $this->getKey($key['body']['$id']);
|
|
$this->assertSame(200, $get['headers']['status-code']);
|
|
$this->assertSame($key['body']['$id'], $get['body']['$id']);
|
|
$this->assertSame('My API Key', $get['body']['name']);
|
|
$this->assertSame(['users.read', 'users.write'], $get['body']['scopes']);
|
|
|
|
// Verify via LIST
|
|
$list = $this->listKeys(null, true);
|
|
$this->assertSame(200, $list['headers']['status-code']);
|
|
$this->assertGreaterThanOrEqual(1, $list['body']['total']);
|
|
$this->assertGreaterThanOrEqual(1, \count($list['body']['keys']));
|
|
|
|
// Cleanup
|
|
$this->deleteKey($key['body']['$id']);
|
|
}
|
|
|
|
public function testCreateKeyWithExpire(): void
|
|
{
|
|
$expire = '2030-01-01T00:00:00.000+00:00';
|
|
|
|
$key = $this->createKey(
|
|
ID::unique(),
|
|
'Expiring Key',
|
|
['users.read'],
|
|
$expire,
|
|
);
|
|
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
$this->assertSame($expire, $key['body']['expire']);
|
|
|
|
// Verify via GET
|
|
$get = $this->getKey($key['body']['$id']);
|
|
$this->assertSame(200, $get['headers']['status-code']);
|
|
$this->assertSame($expire, $get['body']['expire']);
|
|
|
|
// Cleanup
|
|
$this->deleteKey($key['body']['$id']);
|
|
}
|
|
|
|
public function testCreateKeyWithEmptyScopes(): void
|
|
{
|
|
$key = $this->createKey(
|
|
ID::unique(),
|
|
'Empty Scopes Key',
|
|
[],
|
|
);
|
|
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
$this->assertSame([], $key['body']['scopes']);
|
|
|
|
// Cleanup
|
|
$this->deleteKey($key['body']['$id']);
|
|
}
|
|
|
|
public function testCreateKeyWithNullScopesV22BackwardCompat(): void
|
|
{
|
|
$headers = [
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $this->getProject()['$id'],
|
|
'x-appwrite-response-format' => '1.9.0',
|
|
];
|
|
$headers = array_merge($headers, $this->getHeaders());
|
|
|
|
$key = $this->client->call(Client::METHOD_POST, '/project/keys', $headers, [
|
|
'keyId' => ID::unique(),
|
|
'name' => 'V22 Compat Key',
|
|
'scopes' => null,
|
|
]);
|
|
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
$this->assertSame([], $key['body']['scopes']);
|
|
|
|
// Cleanup
|
|
$this->deleteKey($key['body']['$id']);
|
|
}
|
|
|
|
public function testUpdateKeyWithNullScopesV22BackwardCompat(): void
|
|
{
|
|
$key = $this->createKey(
|
|
ID::unique(),
|
|
'V22 Update Compat Key',
|
|
['users.read'],
|
|
);
|
|
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
$keyId = $key['body']['$id'];
|
|
|
|
$headers = [
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $this->getProject()['$id'],
|
|
'x-appwrite-response-format' => '1.9.0',
|
|
];
|
|
$headers = array_merge($headers, $this->getHeaders());
|
|
|
|
$updated = $this->client->call(Client::METHOD_PUT, '/project/keys/' . $keyId, $headers, [
|
|
'name' => 'V22 Update Compat Key',
|
|
'scopes' => null,
|
|
]);
|
|
|
|
$this->assertSame(200, $updated['headers']['status-code']);
|
|
$this->assertSame([], $updated['body']['scopes']);
|
|
|
|
// Cleanup
|
|
$this->deleteKey($keyId);
|
|
}
|
|
|
|
public function testCreateKeyWithoutAuthentication(): void
|
|
{
|
|
$response = $this->createKey(
|
|
ID::unique(),
|
|
'No Auth Key',
|
|
['users.read'],
|
|
null,
|
|
false
|
|
);
|
|
|
|
$this->assertSame(401, $response['headers']['status-code']);
|
|
}
|
|
|
|
public function testCreateKeyInvalidId(): void
|
|
{
|
|
$key = $this->createKey(
|
|
'!invalid-id!',
|
|
'Invalid ID Key',
|
|
['users.read'],
|
|
);
|
|
|
|
$this->assertSame(400, $key['headers']['status-code']);
|
|
}
|
|
|
|
public function testCreateKeyMissingName(): void
|
|
{
|
|
$response = $this->createKey(
|
|
ID::unique(),
|
|
null,
|
|
['users.read'],
|
|
);
|
|
|
|
$this->assertSame(400, $response['headers']['status-code']);
|
|
}
|
|
|
|
public function testCreateKeyInvalidScope(): void
|
|
{
|
|
$response = $this->createKey(
|
|
ID::unique(),
|
|
'Invalid Scope Key',
|
|
['invalid.scope'],
|
|
);
|
|
|
|
$this->assertSame(400, $response['headers']['status-code']);
|
|
}
|
|
|
|
public function testCreateKeyDuplicateId(): void
|
|
{
|
|
$keyId = ID::unique();
|
|
|
|
$key = $this->createKey(
|
|
$keyId,
|
|
'Key Dup 1',
|
|
['users.read'],
|
|
);
|
|
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
|
|
// Attempt to create with same ID
|
|
$duplicate = $this->createKey(
|
|
$keyId,
|
|
'Key Dup 2',
|
|
['users.write'],
|
|
);
|
|
|
|
$this->assertSame(409, $duplicate['headers']['status-code']);
|
|
$this->assertSame('key_already_exists', $duplicate['body']['type']);
|
|
|
|
// Cleanup
|
|
$this->deleteKey($keyId);
|
|
}
|
|
|
|
public function testCreateKeyCustomId(): void
|
|
{
|
|
$customId = 'my-custom-key-id';
|
|
|
|
$key = $this->createKey(
|
|
$customId,
|
|
'Custom ID Key',
|
|
['users.read'],
|
|
);
|
|
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
$this->assertSame($customId, $key['body']['$id']);
|
|
|
|
// Verify via GET
|
|
$get = $this->getKey($customId);
|
|
$this->assertSame(200, $get['headers']['status-code']);
|
|
$this->assertSame($customId, $get['body']['$id']);
|
|
|
|
// Cleanup
|
|
$this->deleteKey($customId);
|
|
}
|
|
|
|
// =========================================================================
|
|
// Update key tests
|
|
// =========================================================================
|
|
|
|
public function testUpdateKey(): void
|
|
{
|
|
$key = $this->createKey(
|
|
ID::unique(),
|
|
'Original Key',
|
|
['users.read'],
|
|
);
|
|
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
$keyId = $key['body']['$id'];
|
|
|
|
// Update name, scopes, and expire
|
|
$expire = '2031-06-15T12:00:00.000+00:00';
|
|
$updated = $this->updateKey($keyId, 'Updated Key', ['users.write', 'databases.read'], $expire);
|
|
|
|
$this->assertSame(200, $updated['headers']['status-code']);
|
|
$this->assertSame($keyId, $updated['body']['$id']);
|
|
$this->assertSame('Updated Key', $updated['body']['name']);
|
|
$this->assertSame(['users.write', 'databases.read'], $updated['body']['scopes']);
|
|
$this->assertSame($expire, $updated['body']['expire']);
|
|
|
|
// Verify update persisted via GET
|
|
$get = $this->getKey($keyId);
|
|
$this->assertSame(200, $get['headers']['status-code']);
|
|
$this->assertSame('Updated Key', $get['body']['name']);
|
|
$this->assertSame(['users.write', 'databases.read'], $get['body']['scopes']);
|
|
$this->assertSame($expire, $get['body']['expire']);
|
|
|
|
// Cleanup
|
|
$this->deleteKey($keyId);
|
|
}
|
|
|
|
public function testUpdateKeyName(): void
|
|
{
|
|
$key = $this->createKey(
|
|
ID::unique(),
|
|
'Name Before',
|
|
['users.read'],
|
|
);
|
|
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
$keyId = $key['body']['$id'];
|
|
|
|
$updated = $this->updateKey($keyId, 'Name After', ['users.read']);
|
|
|
|
$this->assertSame(200, $updated['headers']['status-code']);
|
|
$this->assertSame('Name After', $updated['body']['name']);
|
|
$this->assertSame(['users.read'], $updated['body']['scopes']);
|
|
|
|
// Cleanup
|
|
$this->deleteKey($keyId);
|
|
}
|
|
|
|
public function testUpdateKeyScopes(): void
|
|
{
|
|
$key = $this->createKey(
|
|
ID::unique(),
|
|
'Scopes Key',
|
|
['users.read'],
|
|
);
|
|
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
$keyId = $key['body']['$id'];
|
|
|
|
$updated = $this->updateKey($keyId, 'Scopes Key', ['databases.read', 'databases.write']);
|
|
|
|
$this->assertSame(200, $updated['headers']['status-code']);
|
|
$this->assertSame(['databases.read', 'databases.write'], $updated['body']['scopes']);
|
|
|
|
// Cleanup
|
|
$this->deleteKey($keyId);
|
|
}
|
|
|
|
public function testUpdateKeySetExpire(): void
|
|
{
|
|
$key = $this->createKey(
|
|
ID::unique(),
|
|
'No Expire Key',
|
|
['users.read'],
|
|
);
|
|
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
$this->assertSame('', $key['body']['expire']);
|
|
$keyId = $key['body']['$id'];
|
|
|
|
$expire = '2032-12-31T23:59:59.000+00:00';
|
|
$updated = $this->updateKey($keyId, 'No Expire Key', ['users.read'], $expire);
|
|
|
|
$this->assertSame(200, $updated['headers']['status-code']);
|
|
$this->assertSame($expire, $updated['body']['expire']);
|
|
|
|
// Cleanup
|
|
$this->deleteKey($keyId);
|
|
}
|
|
|
|
public function testUpdateKeyRemoveExpire(): void
|
|
{
|
|
$key = $this->createKey(
|
|
ID::unique(),
|
|
'Expire Key',
|
|
['users.read'],
|
|
'2030-01-01T00:00:00.000+00:00',
|
|
);
|
|
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
$keyId = $key['body']['$id'];
|
|
|
|
// Remove expire by setting to null
|
|
$updated = $this->updateKey($keyId, 'Expire Key', ['users.read'], null);
|
|
|
|
$this->assertSame(200, $updated['headers']['status-code']);
|
|
$this->assertSame('', $updated['body']['expire']);
|
|
|
|
// Cleanup
|
|
$this->deleteKey($keyId);
|
|
}
|
|
|
|
public function testUpdateKeyWithoutAuthentication(): void
|
|
{
|
|
$key = $this->createKey(
|
|
ID::unique(),
|
|
'Auth Update Key',
|
|
['users.read'],
|
|
);
|
|
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
$keyId = $key['body']['$id'];
|
|
|
|
// Attempt update without authentication
|
|
$response = $this->updateKey($keyId, 'Updated Name', ['users.read'], null, false);
|
|
|
|
$this->assertSame(401, $response['headers']['status-code']);
|
|
|
|
// Cleanup
|
|
$this->deleteKey($keyId);
|
|
}
|
|
|
|
public function testUpdateKeyNotFound(): void
|
|
{
|
|
$updated = $this->updateKey('non-existent-id', 'New Name', ['users.read']);
|
|
|
|
$this->assertSame(404, $updated['headers']['status-code']);
|
|
$this->assertSame('key_not_found', $updated['body']['type']);
|
|
}
|
|
|
|
public function testUpdateKeyInvalidScope(): void
|
|
{
|
|
$key = $this->createKey(
|
|
ID::unique(),
|
|
'Invalid Scope Update',
|
|
['users.read'],
|
|
);
|
|
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
$keyId = $key['body']['$id'];
|
|
|
|
$updated = $this->updateKey($keyId, 'Invalid Scope Update', ['invalid.scope']);
|
|
|
|
$this->assertSame(400, $updated['headers']['status-code']);
|
|
|
|
// Cleanup
|
|
$this->deleteKey($keyId);
|
|
}
|
|
|
|
// =========================================================================
|
|
// Get key tests
|
|
// =========================================================================
|
|
|
|
public function testGetKey(): void
|
|
{
|
|
$key = $this->createKey(
|
|
ID::unique(),
|
|
'Get Test Key',
|
|
['users.read', 'databases.read'],
|
|
);
|
|
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
$keyId = $key['body']['$id'];
|
|
|
|
$get = $this->getKey($keyId);
|
|
|
|
$this->assertSame(200, $get['headers']['status-code']);
|
|
$this->assertSame($keyId, $get['body']['$id']);
|
|
$this->assertSame('Get Test Key', $get['body']['name']);
|
|
$this->assertSame(['users.read', 'databases.read'], $get['body']['scopes']);
|
|
$this->assertNotEmpty($get['body']['secret']);
|
|
$this->assertSame('', $get['body']['expire']);
|
|
$this->assertSame('', $get['body']['accessedAt']);
|
|
$this->assertSame([], $get['body']['sdks']);
|
|
|
|
$dateValidator = new DatetimeValidator();
|
|
$this->assertSame(true, $dateValidator->isValid($get['body']['$createdAt']));
|
|
$this->assertSame(true, $dateValidator->isValid($get['body']['$updatedAt']));
|
|
|
|
// Cleanup
|
|
$this->deleteKey($keyId);
|
|
}
|
|
|
|
public function testGetKeyNotFound(): void
|
|
{
|
|
$get = $this->getKey('non-existent-id');
|
|
|
|
$this->assertSame(404, $get['headers']['status-code']);
|
|
$this->assertSame('key_not_found', $get['body']['type']);
|
|
}
|
|
|
|
public function testGetKeyWithoutAuthentication(): void
|
|
{
|
|
$key = $this->createKey(
|
|
ID::unique(),
|
|
'Auth Get Key',
|
|
['users.read'],
|
|
);
|
|
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
$keyId = $key['body']['$id'];
|
|
|
|
// Attempt GET without authentication
|
|
$response = $this->getKey($keyId, false);
|
|
|
|
$this->assertSame(401, $response['headers']['status-code']);
|
|
|
|
// Cleanup
|
|
$this->deleteKey($keyId);
|
|
}
|
|
|
|
// =========================================================================
|
|
// List keys tests
|
|
// =========================================================================
|
|
|
|
public function testListKeys(): void
|
|
{
|
|
// Create multiple keys
|
|
$key1 = $this->createKey(
|
|
ID::unique(),
|
|
'List Key Alpha',
|
|
['users.read'],
|
|
);
|
|
$this->assertSame(201, $key1['headers']['status-code']);
|
|
|
|
$key2 = $this->createKey(
|
|
ID::unique(),
|
|
'List Key Beta',
|
|
['databases.read'],
|
|
);
|
|
$this->assertSame(201, $key2['headers']['status-code']);
|
|
|
|
$key3 = $this->createKey(
|
|
ID::unique(),
|
|
'List Key Gamma',
|
|
['users.write'],
|
|
);
|
|
$this->assertSame(201, $key3['headers']['status-code']);
|
|
|
|
// List all
|
|
$list = $this->listKeys(null, true);
|
|
|
|
$this->assertSame(200, $list['headers']['status-code']);
|
|
$this->assertGreaterThanOrEqual(3, $list['body']['total']);
|
|
$this->assertGreaterThanOrEqual(3, \count($list['body']['keys']));
|
|
$this->assertIsArray($list['body']['keys']);
|
|
|
|
// Verify structure of returned keys
|
|
foreach ($list['body']['keys'] as $key) {
|
|
$this->assertArrayHasKey('$id', $key);
|
|
$this->assertArrayHasKey('$createdAt', $key);
|
|
$this->assertArrayHasKey('$updatedAt', $key);
|
|
$this->assertArrayHasKey('name', $key);
|
|
$this->assertArrayHasKey('scopes', $key);
|
|
$this->assertArrayHasKey('secret', $key);
|
|
$this->assertArrayHasKey('expire', $key);
|
|
$this->assertArrayHasKey('accessedAt', $key);
|
|
$this->assertArrayHasKey('sdks', $key);
|
|
}
|
|
|
|
// Cleanup
|
|
$this->deleteKey($key1['body']['$id']);
|
|
$this->deleteKey($key2['body']['$id']);
|
|
$this->deleteKey($key3['body']['$id']);
|
|
}
|
|
|
|
public function testListKeysWithLimit(): void
|
|
{
|
|
$key1 = $this->createKey(
|
|
ID::unique(),
|
|
'Limit Key 1',
|
|
['users.read'],
|
|
);
|
|
$this->assertSame(201, $key1['headers']['status-code']);
|
|
|
|
$key2 = $this->createKey(
|
|
ID::unique(),
|
|
'Limit Key 2',
|
|
['users.write'],
|
|
);
|
|
$this->assertSame(201, $key2['headers']['status-code']);
|
|
|
|
// List with limit 1
|
|
$list = $this->listKeys([
|
|
Query::limit(1)->toString(),
|
|
], true);
|
|
|
|
$this->assertSame(200, $list['headers']['status-code']);
|
|
$this->assertCount(1, $list['body']['keys']);
|
|
$this->assertGreaterThanOrEqual(2, $list['body']['total']);
|
|
|
|
// Cleanup
|
|
$this->deleteKey($key1['body']['$id']);
|
|
$this->deleteKey($key2['body']['$id']);
|
|
}
|
|
|
|
public function testListKeysWithoutTotal(): void
|
|
{
|
|
$key = $this->createKey(
|
|
ID::unique(),
|
|
'No Total Key',
|
|
['users.read'],
|
|
);
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
|
|
// List with total=false
|
|
$list = $this->listKeys(null, false);
|
|
|
|
$this->assertSame(200, $list['headers']['status-code']);
|
|
$this->assertSame(0, $list['body']['total']);
|
|
$this->assertGreaterThanOrEqual(1, \count($list['body']['keys']));
|
|
|
|
// Cleanup
|
|
$this->deleteKey($key['body']['$id']);
|
|
}
|
|
|
|
public function testListKeysCursorPagination(): void
|
|
{
|
|
$key1 = $this->createKey(
|
|
ID::unique(),
|
|
'Cursor Key 1',
|
|
['users.read'],
|
|
);
|
|
$this->assertSame(201, $key1['headers']['status-code']);
|
|
|
|
$key2 = $this->createKey(
|
|
ID::unique(),
|
|
'Cursor Key 2',
|
|
['users.write'],
|
|
);
|
|
$this->assertSame(201, $key2['headers']['status-code']);
|
|
|
|
// Get first page with limit 1
|
|
$page1 = $this->listKeys([
|
|
Query::limit(1)->toString(),
|
|
], true);
|
|
|
|
$this->assertSame(200, $page1['headers']['status-code']);
|
|
$this->assertCount(1, $page1['body']['keys']);
|
|
$cursorId = $page1['body']['keys'][0]['$id'];
|
|
|
|
// Get next page using cursor
|
|
$page2 = $this->listKeys([
|
|
Query::limit(1)->toString(),
|
|
Query::cursorAfter(new Document(['$id' => $cursorId]))->toString(),
|
|
], true);
|
|
|
|
$this->assertSame(200, $page2['headers']['status-code']);
|
|
$this->assertCount(1, $page2['body']['keys']);
|
|
$this->assertNotEquals($cursorId, $page2['body']['keys'][0]['$id']);
|
|
|
|
// Cleanup
|
|
$this->deleteKey($key1['body']['$id']);
|
|
$this->deleteKey($key2['body']['$id']);
|
|
}
|
|
|
|
public function testListKeysWithoutAuthentication(): void
|
|
{
|
|
$response = $this->listKeys(null, null, false);
|
|
|
|
$this->assertSame(401, $response['headers']['status-code']);
|
|
}
|
|
|
|
public function testListKeysInvalidCursor(): void
|
|
{
|
|
$list = $this->listKeys([
|
|
Query::cursorAfter(new Document(['$id' => 'non-existent-id']))->toString(),
|
|
], true);
|
|
|
|
$this->assertSame(400, $list['headers']['status-code']);
|
|
}
|
|
|
|
// =========================================================================
|
|
// Delete key tests
|
|
// =========================================================================
|
|
|
|
public function testDeleteKey(): void
|
|
{
|
|
$key = $this->createKey(
|
|
ID::unique(),
|
|
'Delete Key',
|
|
['users.read'],
|
|
);
|
|
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
$keyId = $key['body']['$id'];
|
|
|
|
// Verify it exists
|
|
$get = $this->getKey($keyId);
|
|
$this->assertSame(200, $get['headers']['status-code']);
|
|
|
|
// Delete
|
|
$delete = $this->deleteKey($keyId);
|
|
$this->assertSame(204, $delete['headers']['status-code']);
|
|
$this->assertEmpty($delete['body']);
|
|
|
|
// Verify it no longer exists
|
|
$get = $this->getKey($keyId);
|
|
$this->assertSame(404, $get['headers']['status-code']);
|
|
$this->assertSame('key_not_found', $get['body']['type']);
|
|
}
|
|
|
|
public function testDeleteKeyNotFound(): void
|
|
{
|
|
$delete = $this->deleteKey('non-existent-id');
|
|
|
|
$this->assertSame(404, $delete['headers']['status-code']);
|
|
$this->assertSame('key_not_found', $delete['body']['type']);
|
|
}
|
|
|
|
public function testDeleteKeyWithoutAuthentication(): void
|
|
{
|
|
$key = $this->createKey(
|
|
ID::unique(),
|
|
'Delete Auth Key',
|
|
['users.read'],
|
|
);
|
|
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
$keyId = $key['body']['$id'];
|
|
|
|
// Attempt DELETE without authentication
|
|
$response = $this->deleteKey($keyId, false);
|
|
|
|
$this->assertSame(401, $response['headers']['status-code']);
|
|
|
|
// Verify it still exists
|
|
$get = $this->getKey($keyId);
|
|
$this->assertSame(200, $get['headers']['status-code']);
|
|
|
|
// Cleanup
|
|
$this->deleteKey($keyId);
|
|
}
|
|
|
|
public function testDeleteKeyRemovedFromList(): void
|
|
{
|
|
$key = $this->createKey(
|
|
ID::unique(),
|
|
'Delete List Key',
|
|
['users.read'],
|
|
);
|
|
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
$keyId = $key['body']['$id'];
|
|
|
|
// Get list count before delete
|
|
$listBefore = $this->listKeys(null, true);
|
|
$this->assertSame(200, $listBefore['headers']['status-code']);
|
|
$countBefore = $listBefore['body']['total'];
|
|
|
|
// Delete
|
|
$delete = $this->deleteKey($keyId);
|
|
$this->assertSame(204, $delete['headers']['status-code']);
|
|
|
|
// Get list count after delete
|
|
$listAfter = $this->listKeys(null, true);
|
|
$this->assertSame(200, $listAfter['headers']['status-code']);
|
|
$this->assertSame($countBefore - 1, $listAfter['body']['total']);
|
|
|
|
// Verify the deleted key is not in the list
|
|
$ids = \array_column($listAfter['body']['keys'], '$id');
|
|
$this->assertNotContains($keyId, $ids);
|
|
}
|
|
|
|
public function testDeleteKeyDoubleDelete(): void
|
|
{
|
|
$key = $this->createKey(
|
|
ID::unique(),
|
|
'Double Delete Key',
|
|
['users.read'],
|
|
);
|
|
|
|
$this->assertSame(201, $key['headers']['status-code']);
|
|
$keyId = $key['body']['$id'];
|
|
|
|
// First delete succeeds
|
|
$delete = $this->deleteKey($keyId);
|
|
$this->assertSame(204, $delete['headers']['status-code']);
|
|
|
|
// Second delete returns 404
|
|
$delete = $this->deleteKey($keyId);
|
|
$this->assertSame(404, $delete['headers']['status-code']);
|
|
$this->assertSame('key_not_found', $delete['body']['type']);
|
|
}
|
|
|
|
// =========================================================================
|
|
// Helpers
|
|
// =========================================================================
|
|
|
|
/**
|
|
* @param array<string>|null $scopes
|
|
*/
|
|
protected function createKey(string $keyId, ?string $name, ?array $scopes = null, ?string $expire = null, bool $authenticated = true): mixed
|
|
{
|
|
$params = [
|
|
'keyId' => $keyId,
|
|
'scopes' => $scopes,
|
|
];
|
|
|
|
if ($name !== null) {
|
|
$params['name'] = $name;
|
|
}
|
|
|
|
if ($expire !== null) {
|
|
$params['expire'] = $expire;
|
|
}
|
|
|
|
$headers = [
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $this->getProject()['$id'],
|
|
];
|
|
|
|
if ($authenticated) {
|
|
$headers = array_merge($headers, $this->getHeaders());
|
|
}
|
|
|
|
return $this->client->call(Client::METHOD_POST, '/project/keys', $headers, $params);
|
|
}
|
|
|
|
/**
|
|
* @param array<string>|null $scopes
|
|
*/
|
|
protected function updateKey(string $keyId, ?string $name = null, ?array $scopes = null, ?string $expire = null, bool $authenticated = true): mixed
|
|
{
|
|
$params = [];
|
|
|
|
if ($name !== null) {
|
|
$params['name'] = $name;
|
|
}
|
|
|
|
if ($scopes !== null) {
|
|
$params['scopes'] = $scopes;
|
|
}
|
|
|
|
if ($expire !== null) {
|
|
$params['expire'] = $expire;
|
|
}
|
|
|
|
$headers = [
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $this->getProject()['$id'],
|
|
];
|
|
|
|
if ($authenticated) {
|
|
$headers = array_merge($headers, $this->getHeaders());
|
|
}
|
|
|
|
return $this->client->call(Client::METHOD_PUT, '/project/keys/' . $keyId, $headers, $params);
|
|
}
|
|
|
|
protected function getKey(string $keyId, bool $authenticated = true): mixed
|
|
{
|
|
$headers = [
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $this->getProject()['$id'],
|
|
];
|
|
|
|
if ($authenticated) {
|
|
$headers = array_merge($headers, $this->getHeaders());
|
|
}
|
|
|
|
return $this->client->call(Client::METHOD_GET, '/project/keys/' . $keyId, $headers);
|
|
}
|
|
|
|
/**
|
|
* @param array<string>|null $queries
|
|
*/
|
|
protected function listKeys(?array $queries, ?bool $total, bool $authenticated = true): mixed
|
|
{
|
|
$headers = [
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $this->getProject()['$id'],
|
|
];
|
|
|
|
if ($authenticated) {
|
|
$headers = array_merge($headers, $this->getHeaders());
|
|
}
|
|
|
|
return $this->client->call(Client::METHOD_GET, '/project/keys', $headers, [
|
|
'queries' => $queries,
|
|
'total' => $total,
|
|
]);
|
|
}
|
|
|
|
protected function deleteKey(string $keyId, bool $authenticated = true): mixed
|
|
{
|
|
$headers = [
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $this->getProject()['$id'],
|
|
];
|
|
|
|
if ($authenticated) {
|
|
$headers = array_merge($headers, $this->getHeaders());
|
|
}
|
|
|
|
return $this->client->call(Client::METHOD_DELETE, '/project/keys/' . $keyId, $headers);
|
|
}
|
|
}
|