diff --git a/app/config/variables.php b/app/config/variables.php index 793fa5c74c..1c016b84de 100644 --- a/app/config/variables.php +++ b/app/config/variables.php @@ -335,6 +335,54 @@ return [ ], ], ], + [ + 'category' => 'InfluxDB', + 'description' => 'Deprecated since 1.4.8.', + 'variables' => [ + [ + 'name' => '_APP_INFLUXDB_HOST', + 'description' => 'InfluxDB server host name address. Default value is: \'influxdb\'.', + 'introduction' => '', + 'default' => 'influxdb', + 'required' => false, + 'question' => '', + 'filter' => '' + ], + [ + 'name' => '_APP_INFLUXDB_PORT', + 'description' => 'InfluxDB server TCP port. Default value is: \'8086\'.', + 'introduction' => '', + 'default' => '8086', + 'required' => false, + 'question' => '', + 'filter' => '' + ], + ], + ], + [ + 'category' => 'StatsD', + 'description' => 'Deprecated since 1.4.8.', + 'variables' => [ + [ + 'name' => '_APP_STATSD_HOST', + 'description' => 'StatsD server host name address. Default value is: \'telegraf\'.', + 'introduction' => '', + 'default' => 'telegraf', + 'required' => false, + 'question' => '', + 'filter' => '' + ], + [ + 'name' => '_APP_STATSD_PORT', + 'description' => 'StatsD server TCP port. Default value is: \'8125\'.', + 'introduction' => '', + 'default' => '8125', + 'required' => false, + 'question' => '', + 'filter' => '' + ], + ], + ], [ 'category' => 'SMTP', 'description' => "Appwrite is using an SMTP server for emailing your projects users and server admins. The SMTP env vars are used to allow Appwrite server to connect to the SMTP container.\n\nIf running in production, it might be easier to use a 3rd party SMTP server as it might be a little more difficult to set up a production SMTP server that will not send all your emails into your user\'s SPAM folder.", diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index ad51622418..fdd5de47df 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -58,7 +58,6 @@ App::post('/v1/account') ->label('audits.event', 'user.create') ->label('audits.resource', 'user/{response.$id}') ->label('audits.userId', '{response.$id}') - ->label('usage.metric', 'users.{scope}.requests.create') ->label('sdk.auth', []) ->label('sdk.namespace', 'account') ->label('sdk.method', 'create') @@ -1642,7 +1641,6 @@ App::get('/v1/account') ->desc('Get account') ->groups(['api', 'account']) ->label('scope', 'account') - ->label('usage.metric', 'users.{scope}.requests.read') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'get') @@ -1685,7 +1683,6 @@ App::get('/v1/account/sessions') ->desc('List sessions') ->groups(['api', 'account']) ->label('scope', 'account') - ->label('usage.metric', 'users.{scope}.requests.read') ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'account') ->label('sdk.method', 'listSessions') diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index c152250ecb..88b0a2fed1 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -1835,8 +1835,6 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/email ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update') ->label('audits.event', 'attribute.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('usage.metric', 'collections.{scope}.requests.update') - ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateEmailAttribute') @@ -1876,8 +1874,6 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/enum/ ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update') ->label('audits.event', 'attribute.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('usage.metric', 'collections.{scope}.requests.update') - ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateEnumAttribute') @@ -1919,8 +1915,6 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/ip/:k ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update') ->label('audits.event', 'attribute.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('usage.metric', 'collections.{scope}.requests.update') - ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateIpAttribute') @@ -1960,8 +1954,6 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/url/: ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update') ->label('audits.event', 'attribute.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('usage.metric', 'collections.{scope}.requests.update') - ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateUrlAttribute') @@ -2001,8 +1993,6 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/integ ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update') ->label('audits.event', 'attribute.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('usage.metric', 'collections.{scope}.requests.update') - ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateIntegerAttribute') @@ -2052,8 +2042,6 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/float ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update') ->label('audits.event', 'attribute.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('usage.metric', 'collections.{scope}.requests.update') - ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateFloatAttribute') @@ -2103,8 +2091,6 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/boole ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update') ->label('audits.event', 'attribute.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('usage.metric', 'collections.{scope}.requests.update') - ->label('usage.params', ['databaseId:{request.databaseId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateBooleanAttribute') @@ -2143,8 +2129,6 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/datet ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update') ->label('audits.event', 'attribute.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('usage.metric', 'documents.{scope}.requests.update') - ->label('usage.params', ['databaseId:{request.databaseId}', 'collectionId:{request.collectionId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateDatetimeAttribute') @@ -2183,8 +2167,6 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/ ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update') ->label('audits.event', 'attribute.update') ->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}') - ->label('usage.metric', 'documents.{scope}.requests.update') - ->label('usage.params', ['databaseId:{request.databaseId}', 'collectionId:{request.collectionId}']) ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'databases') ->label('sdk.method', 'updateRelationshipAttribute') @@ -3594,8 +3576,8 @@ App::get('/v1/databases/usage') $limit = $days['limit']; $period = $days['period']; $results = $dbForProject->find('stats', [ - Query::equal('period', [$period]), Query::equal('metric', [$metric]), + Query::equal('period', [$period]), Query::limit($limit), Query::orderDesc('time'), ]); @@ -3668,8 +3650,8 @@ App::get('/v1/databases/:databaseId/usage') $limit = $days['limit']; $period = $days['period']; $results = $dbForProject->find('stats', [ - Query::equal('period', [$period]), Query::equal('metric', [$metric]), + Query::equal('period', [$period]), Query::limit($limit), Query::orderDesc('time'), ]); @@ -3745,8 +3727,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/usage') $limit = $days['limit']; $period = $days['period']; $results = $dbForProject->find('stats', [ - Query::equal('period', [$period]), Query::equal('metric', [$metric]), + Query::equal('period', [$period]), Query::limit($limit), Query::orderDesc('time'), ]); diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 828c7e115b..e899d61da6 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -476,8 +476,8 @@ App::get('/v1/functions/:functionId/usage') $limit = $days['limit']; $period = $days['period']; $results = $dbForProject->find('stats', [ - Query::equal('period', [$period]), Query::equal('metric', [$metric]), + Query::equal('period', [$period]), Query::limit($limit), Query::orderDesc('time'), ]); @@ -554,8 +554,8 @@ App::get('/v1/functions/usage') $limit = $days['limit']; $period = $days['period']; $results = $dbForProject->find('stats', [ - Query::equal('period', [$period]), Query::equal('metric', [$metric]), + Query::equal('period', [$period]), Query::limit($limit), Query::orderDesc('time'), ]); diff --git a/app/controllers/api/project.php b/app/controllers/api/project.php index bb4457eeed..7ff82ad3ea 100644 --- a/app/controllers/api/project.php +++ b/app/controllers/api/project.php @@ -52,8 +52,8 @@ App::get('/v1/project/usage') $limit = $days['limit']; $period = $days['period']; $results = $dbForProject->find('stats', [ - Query::equal('period', [$period]), Query::equal('metric', [$metric]), + Query::equal('period', [$period]), Query::limit($limit), Query::orderDesc('time'), ]); diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 0c7f10a0e0..3b1a234b8e 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -1495,8 +1495,8 @@ App::get('/v1/storage/usage') $limit = $days['limit']; $period = $days['period']; $results = $dbForProject->find('stats', [ - Query::equal('period', [$period]), Query::equal('metric', [$metric]), + Query::equal('period', [$period]), Query::limit($limit), Query::orderDesc('time'), ]); @@ -1570,8 +1570,8 @@ App::get('/v1/storage/:bucketId/usage') $limit = $days['limit']; $period = $days['period']; $results = $dbForProject->find('stats', [ - Query::equal('period', [$period]), Query::equal('metric', [$metric]), + Query::equal('period', [$period]), Query::limit($limit), Query::orderDesc('time'), ]); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index a992d51965..e8a80a1a25 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -1241,8 +1241,8 @@ App::get('/v1/users/usage') $limit = $days['limit']; $period = $days['period']; $results = $dbForProject->find('stats', [ - Query::equal('period', [$period]), Query::equal('metric', [$metric]), + Query::equal('period', [$period]), Query::limit($limit), Query::orderDesc('time'), ]); diff --git a/app/views/install/compose.phtml b/app/views/install/compose.phtml index 898b46b3a5..1544b38e6f 100644 --- a/app/views/install/compose.phtml +++ b/app/views/install/compose.phtml @@ -71,7 +71,6 @@ services: - mariadb - redis # - clamav - - influxdb environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -106,8 +105,6 @@ services: - _APP_SMTP_USERNAME - _APP_SMTP_PASSWORD - _APP_USAGE_STATS - - _APP_INFLUXDB_HOST - - _APP_INFLUXDB_PORT - _APP_STORAGE_LIMIT - _APP_STORAGE_PREVIEW_LIMIT - _APP_STORAGE_ANTIVIRUS @@ -144,8 +141,6 @@ services: - _APP_EXECUTOR_HOST - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG - - _APP_STATSD_HOST - - _APP_STATSD_PORT - _APP_MAINTENANCE_INTERVAL - _APP_MAINTENANCE_RETENTION_EXECUTION - _APP_MAINTENANCE_RETENTION_CACHE @@ -595,16 +590,15 @@ services: - _APP_MAINTENANCE_RETENTION_USAGE_HOURLY - _APP_MAINTENANCE_RETENTION_SCHEDULES - appwrite-usage: + appwrite-worker-usage: image: /: entrypoint: usage - container_name: appwrite-usage + container_name: appwrite-worker-usage <<: *x-logging restart: unless-stopped networks: - appwrite depends_on: - - influxdb - mariadb environment: - _APP_ENV @@ -615,9 +609,6 @@ services: - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS - - _APP_INFLUXDB_HOST - - _APP_INFLUXDB_PORT - - _APP_USAGE_AGGREGATION_INTERVAL - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -751,27 +742,6 @@ services: # volumes: # - appwrite-uploads:/storage/uploads - influxdb: - image: appwrite/influxdb:1.5.0 - container_name: appwrite-influxdb - <<: *x-logging - restart: unless-stopped - networks: - - appwrite - volumes: - - appwrite-influxdb:/var/lib/influxdb:rw - - telegraf: - image: appwrite/telegraf:1.4.0 - container_name: appwrite-telegraf - <<: *x-logging - restart: unless-stopped - networks: - - appwrite - environment: - - _APP_INFLUXDB_HOST - - _APP_INFLUXDB_PORT - networks: gateway: name: gateway @@ -788,5 +758,4 @@ volumes: appwrite-certificates: appwrite-functions: appwrite-builds: - appwrite-influxdb: appwrite-config: diff --git a/docker-compose.yml b/docker-compose.yml index 6b1cc2d354..4820df5b51 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -654,9 +654,6 @@ services: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src - - ./vendor/utopia-php/platform:/usr/src/code/vendor/utopia-php/platform - - ./vendor/utopia-php/framework:/usr/src/code/vendor/utopia-php/framework - - ./vendor/utopia-php/queue:/usr/src/code/vendor/utopia-php/queue depends_on: - redis - mariadb diff --git a/src/Appwrite/Platform/Tasks/CalcTierStats.php b/src/Appwrite/Platform/Tasks/CalcTierStats.php index 2a2bc20af9..dae46dd56c 100644 --- a/src/Appwrite/Platform/Tasks/CalcTierStats.php +++ b/src/Appwrite/Platform/Tasks/CalcTierStats.php @@ -171,8 +171,8 @@ class CalcTierStats extends Action $period = $periods[$range]['period']; $requestDocs = $dbForProject->find('stats', [ - Query::equal('period', [$period]), Query::equal('metric', [$metric]), + Query::equal('period', [$period]), Query::limit($limit), Query::orderDesc('time'), ]); diff --git a/src/Appwrite/Platform/Tasks/Hamster.php b/src/Appwrite/Platform/Tasks/Hamster.php index 1d5d3b0b26..42824ebe38 100644 --- a/src/Appwrite/Platform/Tasks/Hamster.php +++ b/src/Appwrite/Platform/Tasks/Hamster.php @@ -237,8 +237,8 @@ class Hamster extends Action $period = $periodValue['period']; $requestDocs = $dbForProject->find('stats', [ - Query::equal('period', [$period]), Query::equal('metric', [$metric]), + Query::equal('period', [$period]), Query::limit($limit), Query::orderDesc('time'), ]); diff --git a/tests/e2e/General/UsageTest.php b/tests/e2e/General/UsageTest.php index fdea53d68b..cd5ddb07b8 100644 --- a/tests/e2e/General/UsageTest.php +++ b/tests/e2e/General/UsageTest.php @@ -10,789 +10,788 @@ use Tests\E2E\Scopes\SideServer; use CURLFile; use Tests\E2E\Services\Functions\FunctionsBase; use Utopia\Database\DateTime; -use Utopia\Database\Permission; -use Utopia\Database\Role; - -// TODO @christyjacob4 : enable test once usage stats are fixed -// class UsageTest extends Scope -// { -// use ProjectCustom; -// use SideServer; -// use FunctionsBase; - -// protected string $projectId; - -// protected function setUp(): void -// { -// parent::setUp(); -// } - -// protected static string $formatTz = 'Y-m-d\TH:i:s.vP'; - -// protected function validateDates(array $metrics): void -// { -// foreach ($metrics as $metric) { -// $this->assertIsObject(\DateTime::createFromFormat("Y-m-d\TH:i:s.vP", $metric['date'])); -// } -// } - -// public function testPrepareUsersStats(): array -// { -// $project = $this->getProject(true); -// $projectId = $project['$id']; -// $headers['x-appwrite-project'] = $project['$id']; -// $headers['x-appwrite-key'] = $project['apiKey']; -// $headers['content-type'] = 'application/json'; - -// $usersCount = 0; -// $requestsCount = 0; -// for ($i = 0; $i < 10; $i++) { -// $email = uniqid() . 'user@usage.test'; -// $password = 'password'; -// $name = uniqid() . 'User'; -// $res = $this->client->call(Client::METHOD_POST, '/users', $headers, [ -// 'userId' => 'unique()', -// 'email' => $email, -// 'password' => $password, -// 'name' => $name, -// ]); -// $this->assertEquals($email, $res['body']['email']); -// $this->assertNotEmpty($res['body']['$id']); -// $usersCount++; -// $requestsCount++; - -// if ($i < 5) { -// $userId = $res['body']['$id']; -// $res = $this->client->call(Client::METHOD_GET, '/users/' . $userId, $headers); -// $this->assertEquals($userId, $res['body']['$id']); -// $res = $this->client->call(Client::METHOD_DELETE, '/users/' . $userId, $headers); -// $this->assertEmpty($res['body']); -// $requestsCount += 2; -// $usersCount--; -// } -// } - -// return [ -// 'projectId' => $projectId, -// 'headers' => $headers, -// 'usersCount' => $usersCount, -// 'requestsCount' => $requestsCount -// ]; -// } - -// /** -// * @depends testPrepareUsersStats -// */ -// #[Retry(count: 1)] -// public function testUsersStats(array $data): array -// { -// sleep(20); - -// $projectId = $data['projectId']; -// $headers = $data['headers']; -// $usersCount = $data['usersCount']; -// $requestsCount = $data['requestsCount']; - -// // console request -// $headers = [ -// 'origin' => 'http://localhost', -// 'x-appwrite-project' => 'console', -// 'cookie' => 'a_session_console=' . $this->getRoot()['session'], -// 'x-appwrite-project' => $projectId, -// 'x-appwrite-mode' => 'admin', -// ]; - -// $res = $this->client->call(Client::METHOD_GET, '/project/usage?range=30d', $headers); -// $res = $res['body']; - -// $this->assertEquals(9, count($res)); -// $this->assertEquals(30, count($res['requests'])); -// $this->assertEquals(30, count($res['users'])); -// $this->assertEquals($usersCount, $res['users'][array_key_last($res['users'])]['value']); -// $this->validateDates($res['users']); -// $this->assertEquals($requestsCount, $res['requests'][array_key_last($res['requests'])]['value']); -// $this->validateDates($res['requests']); - -// $res = $this->client->call(Client::METHOD_GET, '/users/usage?range=30d', array_merge($headers, [ -// 'x-appwrite-project' => $projectId, -// 'x-appwrite-mode' => 'admin' -// ])); -// $requestsCount++; -// $res = $res['body']; -// $this->assertEquals(10, $res['usersCreate'][array_key_last($res['usersCreate'])]['value']); -// $this->validateDates($res['usersCreate']); -// $this->assertEquals(5, $res['usersRead'][array_key_last($res['usersRead'])]['value']); -// $this->validateDates($res['usersRead']); -// $this->assertEquals(5, $res['usersDelete'][array_key_last($res['usersDelete'])]['value']); -// $this->validateDates($res['usersDelete']); - -// return ['projectId' => $projectId, 'headers' => $headers, 'requestsCount' => $requestsCount]; -// } - -// /** @depends testUsersStats */ -// public function testPrepareStorageStats(array $data): array -// { -// $projectId = $data['projectId']; -// $headers = $data['headers']; - -// $bucketId = ''; -// $bucketsCount = 0; -// $requestsCount = $data['requestsCount']; -// $storageTotal = 0; -// $bucketsCreate = 0; -// $bucketsDelete = 0; -// $bucketsRead = 0; -// $filesCount = 0; -// $filesRead = 0; -// $filesCreate = 0; -// $filesDelete = 0; - -// for ($i = 0; $i < 10; $i++) { -// $name = uniqid() . ' bucket'; -// $res = $this->client->call(Client::METHOD_POST, '/storage/buckets', \array_merge($headers, [ -// 'content-type' => 'application/json' -// ]), [ -// 'bucketId' => 'unique()', -// 'name' => $name, -// 'fileSecurity' => false, -// 'permissions' => [ -// Permission::read(Role::any()), -// Permission::create(Role::any()), -// Permission::update(Role::any()), -// Permission::delete(Role::any()), -// ], -// ]); -// $this->assertEquals($name, $res['body']['name']); -// $this->assertNotEmpty($res['body']['$id']); -// $bucketId = $res['body']['$id']; - -// $bucketsCreate++; -// $bucketsCount++; -// $requestsCount++; - -// if ($i < 5) { -// $res = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId, $headers); -// $this->assertEquals($bucketId, $res['body']['$id']); -// $bucketsRead++; - -// $res = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId, $headers); -// $this->assertEmpty($res['body']); -// $bucketsDelete++; - -// $requestsCount += 2; -// $bucketsCount--; -// } -// } - -// // upload some files -// $files = [ -// [ -// 'path' => realpath(__DIR__ . '/../../resources/logo.png'), -// 'name' => 'logo.png', -// ], -// [ -// 'path' => realpath(__DIR__ . '/../../resources/file.png'), -// 'name' => 'file.png', -// ], -// [ -// 'path' => realpath(__DIR__ . '/../../resources/disk-a/kitten-3.gif'), -// 'name' => 'kitten-3.gif', -// ], -// [ -// 'path' => realpath(__DIR__ . '/../../resources/disk-a/kitten-1.jpg'), -// 'name' => 'kitten-1.jpg', -// ], -// ]; - -// for ($i = 0; $i < 10; $i++) { -// $file = $files[$i % count($files)]; -// $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge($headers, ['content-type' => 'multipart/form-data']), [ -// 'fileId' => 'unique()', -// 'file' => new CURLFile($file['path'], '', $file['name']), -// ]); -// $this->assertNotEmpty($res['body']['$id']); - -// $fileSize = $res['body']['sizeOriginal']; -// $storageTotal += $fileSize; -// $filesCount++; -// $filesCreate++; -// $requestsCount++; - -// $fileId = $res['body']['$id']; -// if ($i < 5) { -// $res = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, $headers); -// $this->assertEquals($fileId, $res['body']['$id']); -// $filesRead++; - -// $res = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, $headers); -// $this->assertEmpty($res['body']); -// $filesDelete++; -// $requestsCount += 2; -// $filesCount--; -// $storageTotal -= $fileSize; -// } -// } - -// return array_merge($data, [ -// 'bucketId' => $bucketId, -// 'bucketsCount' => $bucketsCount, -// 'requestsCount' => $requestsCount, -// 'storageTotal' => $storageTotal, -// 'bucketsCreate' => $bucketsCreate, -// 'bucketsDelete' => $bucketsDelete, -// 'bucketsRead' => $bucketsRead, -// 'filesCount' => $filesCount, -// 'filesRead' => $filesRead, -// 'filesCreate' => $filesCreate, -// 'filesDelete' => $filesDelete, -// ]); -// } - -// /** -// * @depends testPrepareStorageStats -// */ -// #[Retry(count: 1)] -// public function testStorageStats(array $data): array -// { -// $projectId = $data['projectId']; -// $bucketId = $data['bucketId']; -// $bucketsCount = $data['bucketsCount']; -// $requestsCount = $data['requestsCount']; -// $storageTotal = $data['storageTotal']; -// $bucketsCreate = $data['bucketsCreate']; -// $bucketsDelete = $data['bucketsDelete']; -// $bucketsRead = $data['bucketsRead']; -// $filesCount = $data['filesCount']; -// $filesRead = $data['filesRead']; -// $filesCreate = $data['filesCreate']; -// $filesDelete = $data['filesDelete']; - -// sleep(20); - -// // console request -// $headers = [ -// 'origin' => 'http://localhost', -// 'x-appwrite-project' => 'console', -// 'cookie' => 'a_session_console=' . $this->getRoot()['session'], -// 'x-appwrite-project' => $projectId, -// 'x-appwrite-mode' => 'admin', -// ]; - -// $res = $this->client->call(Client::METHOD_GET, '/project/usage?range=30d', $headers); -// $res = $res['body']; - -// $this->assertEquals(9, count($res)); -// $this->assertEquals(30, count($res['requests'])); -// $this->assertEquals(30, count($res['storage'])); -// $this->assertEquals($requestsCount, $res['requests'][array_key_last($res['requests'])]['value']); -// $this->validateDates($res['requests']); -// $this->assertEquals($storageTotal, $res['storage'][array_key_last($res['storage'])]['value']); -// $this->validateDates($res['storage']); - -// $res = $this->client->call(Client::METHOD_GET, '/storage/usage?range=30d', array_merge($headers, [ -// 'x-appwrite-project' => $projectId, -// 'x-appwrite-mode' => 'admin' -// ])); -// $requestsCount++; -// $res = $res['body']; -// $this->assertEquals($storageTotal, $res['storage'][array_key_last($res['storage'])]['value']); -// $this->validateDates($res['storage']); -// $this->assertEquals($bucketsCount, $res['bucketsCount'][array_key_last($res['bucketsCount'])]['value']); -// $this->validateDates($res['bucketsCount']); -// $this->assertEquals($bucketsRead, $res['bucketsRead'][array_key_last($res['bucketsRead'])]['value']); -// $this->validateDates($res['bucketsRead']); -// $this->assertEquals($bucketsCreate, $res['bucketsCreate'][array_key_last($res['bucketsCreate'])]['value']); -// $this->validateDates($res['bucketsCreate']); -// $this->assertEquals($bucketsDelete, $res['bucketsDelete'][array_key_last($res['bucketsDelete'])]['value']); -// $this->validateDates($res['bucketsDelete']); -// $this->assertEquals($filesCount, $res['filesCount'][array_key_last($res['filesCount'])]['value']); -// $this->validateDates($res['filesCount']); -// $this->assertEquals($filesRead, $res['filesRead'][array_key_last($res['filesRead'])]['value']); -// $this->validateDates($res['filesRead']); -// $this->assertEquals($filesCreate, $res['filesCreate'][array_key_last($res['filesCreate'])]['value']); -// $this->validateDates($res['filesCreate']); -// $this->assertEquals($filesDelete, $res['filesDelete'][array_key_last($res['filesDelete'])]['value']); -// $this->validateDates($res['filesDelete']); - -// $res = $this->client->call(Client::METHOD_GET, '/storage/' . $bucketId . '/usage?range=30d', array_merge($headers, [ -// 'x-appwrite-project' => $projectId, -// 'x-appwrite-mode' => 'admin' -// ])); -// $requestsCount++; -// $res = $res['body']; -// $this->assertEquals($storageTotal, $res['filesStorage'][array_key_last($res['filesStorage'])]['value']); -// $this->assertEquals($filesCount, $res['filesCount'][array_key_last($res['filesCount'])]['value']); -// $this->assertEquals($filesRead, $res['filesRead'][array_key_last($res['filesRead'])]['value']); -// $this->assertEquals($filesCreate, $res['filesCreate'][array_key_last($res['filesCreate'])]['value']); -// $this->assertEquals($filesDelete, $res['filesDelete'][array_key_last($res['filesDelete'])]['value']); - -// $data['requestsCount'] = $requestsCount; -// return $data; -// } - -// /** @depends testStorageStats */ -// public function testPrepareDatabaseStats(array $data): array -// { -// $headers = $data['headers']; -// $projectId = $data['projectId']; - -// $databaseId = ''; -// $collectionId = ''; - -// $requestsCount = $data['requestsCount']; -// $databasesCount = 0; -// $databasesCreate = 0; -// $databasesRead = 0; -// $databasesDelete = 0; - -// $collectionsCount = 0; -// $collectionsCreate = 0; -// $collectionsRead = 0; -// $collectionsUpdate = 0; -// $collectionsDelete = 0; - -// $documentsCount = 0; -// $documentsCreate = 0; -// $documentsRead = 0; -// $documentsDelete = 0; - -// for ($i = 0; $i < 10; $i++) { -// $name = uniqid() . ' database'; -// $res = $this->client->call(Client::METHOD_POST, '/databases', $headers, [ -// 'databaseId' => 'unique()', -// 'name' => $name, -// ]); -// $this->assertEquals($name, $res['body']['name']); -// $this->assertNotEmpty($res['body']['$id']); -// $databaseId = $res['body']['$id']; - -// $requestsCount++; -// $databasesCount++; -// $databasesCreate++; - -// if ($i < 5) { -// $res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId, $headers); -// $this->assertEquals($databaseId, $res['body']['$id']); -// $databasesRead++; - -// $res = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, $headers); -// $this->assertEmpty($res['body']); -// $databasesDelete++; - -// $databasesCount--; -// $requestsCount += 2; -// } -// } - -// for ($i = 0; $i < 10; $i++) { -// $name = uniqid() . ' collection'; -// $res = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', $headers, [ -// 'collectionId' => 'unique()', -// 'name' => $name, -// 'documentSecurity' => false, -// 'permissions' => [ -// Permission::read(Role::any()), -// Permission::create(Role::any()), -// Permission::update(Role::any()), -// Permission::delete(Role::any()), -// ], -// ]); -// $this->assertEquals($name, $res['body']['name']); -// $this->assertNotEmpty($res['body']['$id']); -// $collectionId = $res['body']['$id']; - -// $requestsCount++; -// $collectionsCount++; -// $collectionsCreate++; - -// if ($i < 5) { -// $res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, $headers); -// $this->assertEquals($collectionId, $res['body']['$id']); -// $collectionsRead++; - -// $res = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId, $headers); -// $this->assertEmpty($res['body']); -// $collectionsDelete++; - -// $collectionsCount--; -// $requestsCount += 2; -// } -// } - -// $res = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes' . '/string', $headers, [ -// 'key' => 'name', -// 'size' => 255, -// 'required' => true, -// ]); -// $this->assertEquals('name', $res['body']['key']); -// $collectionsUpdate++; -// $requestsCount++; -// sleep(20); - -// for ($i = 0; $i < 10; $i++) { -// $name = uniqid() . ' collection'; -// $res = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', $headers, [ -// 'documentId' => 'unique()', -// 'data' => ['name' => $name] -// ]); -// $this->assertEquals($name, $res['body']['name']); -// $this->assertNotEmpty($res['body']['$id']); -// $documentId = $res['body']['$id']; - -// $requestsCount++; -// $documentsCount++; -// $documentsCreate++; - -// if ($i < 5) { -// $res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, $headers); -// $this->assertEquals($documentId, $res['body']['$id']); -// $documentsRead++; - -// $res = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, $headers); -// $this->assertEmpty($res['body']); -// $documentsDelete++; - -// $documentsCount--; -// $requestsCount += 2; -// } -// } - -// $data = array_merge($data, [ -// 'databaseId' => $databaseId, -// 'collectionId' => $collectionId, - -// 'requestsCount' => $requestsCount, -// 'databasesCount' => $databasesCount, -// 'databasesCreate' => $databasesCreate, -// 'databasesRead' => $databasesRead, -// 'databasesDelete' => $databasesDelete, - -// 'collectionsCount' => $collectionsCount, -// 'collectionsCreate' => $collectionsCreate, -// 'collectionsRead' => $collectionsRead, -// 'collectionsUpdate' => $collectionsUpdate, -// 'collectionsDelete' => $collectionsDelete, - -// 'documentsCount' => $documentsCount, -// 'documentsCreate' => $documentsCreate, -// 'documentsRead' => $documentsRead, -// 'documentsDelete' => $documentsDelete, -// ]); - -// return $data; -// } - -// /** @depends testPrepareDatabaseStats */ -// #[Retry(count: 1)] -// public function testDatabaseStats(array $data): array -// { -// $headers = $data['headers']; -// $projectId = $data['projectId']; - -// $databaseId = $data['databaseId']; -// $collectionId = $data['collectionId']; - -// $requestsCount = $data['requestsCount']; -// $databasesCount = $data['databasesCount']; -// $databasesCreate = $data['databasesCreate']; -// $databasesRead = $data['databasesRead']; -// $databasesDelete = $data['databasesDelete']; - -// $collectionsCount = $data['collectionsCount']; -// $collectionsCreate = $data['collectionsCreate']; -// $collectionsRead = $data['collectionsRead']; -// $collectionsUpdate = $data['collectionsUpdate']; -// $collectionsDelete = $data['collectionsDelete']; - -// $documentsCount = $data['documentsCount']; -// $documentsCreate = $data['documentsCreate']; -// $documentsRead = $data['documentsRead']; -// $documentsDelete = $data['documentsDelete']; - -// sleep(20); - -// // check datbase stats -// $headers = [ -// 'origin' => 'http://localhost', -// 'x-appwrite-project' => 'console', -// 'cookie' => 'a_session_console=' . $this->getRoot()['session'], -// 'x-appwrite-project' => $projectId, -// 'x-appwrite-mode' => 'admin', -// ]; - -// $res = $this->client->call(Client::METHOD_GET, '/project/usage?range=30d', $headers); -// $res = $res['body']; - -// $this->assertEquals(9, count($res)); -// $this->assertEquals(30, count($res['requests'])); -// $this->assertEquals(30, count($res['storage'])); -// $this->assertEquals($requestsCount, $res['requests'][array_key_last($res['requests'])]['value']); -// $this->validateDates($res['requests']); -// $this->assertEquals($databasesCount, $res['databases'][array_key_last($res['databases'])]['value']); -// $this->validateDates($res['databases']); -// $this->assertEquals($documentsCount, $res['documents'][array_key_last($res['documents'])]['value']); -// $this->validateDates($res['documents']); - -// $res = $this->client->call(Client::METHOD_GET, '/databases/usage?range=30d', array_merge($headers, [ -// 'x-appwrite-project' => $projectId, -// 'x-appwrite-mode' => 'admin' -// ])); -// $res = $res['body']; -// $this->assertEquals($databasesCount, $res['databasesCount'][array_key_last($res['databasesCount'])]['value']); -// $this->validateDates($res['databasesCount']); -// $this->assertEquals($collectionsCount, $res['collectionsCount'][array_key_last($res['collectionsCount'])]['value']); -// $this->validateDates($res['collectionsCount']); -// $this->assertEquals($documentsCount, $res['documentsCount'][array_key_last($res['documentsCount'])]['value']); -// $this->validateDates($res['documentsCount']); - -// $this->assertEquals($databasesCreate, $res['databasesCreate'][array_key_last($res['databasesCreate'])]['value']); -// $this->validateDates($res['databasesCreate']); -// $this->assertEquals($databasesRead, $res['databasesRead'][array_key_last($res['databasesRead'])]['value']); -// $this->validateDates($res['databasesRead']); -// $this->assertEquals($databasesDelete, $res['databasesDelete'][array_key_last($res['databasesDelete'])]['value']); -// $this->validateDates($res['databasesDelete']); - -// $this->assertEquals($collectionsCreate, $res['collectionsCreate'][array_key_last($res['collectionsCreate'])]['value']); -// $this->validateDates($res['collectionsCreate']); -// $this->assertEquals($collectionsRead, $res['collectionsRead'][array_key_last($res['collectionsRead'])]['value']); -// $this->validateDates($res['collectionsRead']); -// $this->assertEquals($collectionsUpdate, $res['collectionsUpdate'][array_key_last($res['collectionsUpdate'])]['value']); -// $this->validateDates($res['collectionsUpdate']); -// $this->assertEquals($collectionsDelete, $res['collectionsDelete'][array_key_last($res['collectionsDelete'])]['value']); -// $this->validateDates($res['collectionsDelete']); - -// $this->assertEquals($documentsCreate, $res['documentsCreate'][array_key_last($res['documentsCreate'])]['value']); -// $this->validateDates($res['documentsCreate']); -// $this->assertEquals($documentsRead, $res['documentsRead'][array_key_last($res['documentsRead'])]['value']); -// $this->validateDates($res['documentsRead']); -// $this->assertEquals($documentsDelete, $res['documentsDelete'][array_key_last($res['documentsDelete'])]['value']); -// $this->validateDates($res['documentsDelete']); - -// $res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/usage?range=30d', array_merge($headers, [ -// 'x-appwrite-project' => $projectId, -// 'x-appwrite-mode' => 'admin' -// ])); -// $res = $res['body']; -// $this->assertEquals($collectionsCount, $res['collectionsCount'][array_key_last($res['collectionsCount'])]['value']); -// $this->validateDates($res['collectionsCount']); -// $this->assertEquals($documentsCount, $res['documentsCount'][array_key_last($res['documentsCount'])]['value']); -// $this->validateDates($res['documentsCount']); - -// $this->assertEquals($collectionsCreate, $res['collectionsCreate'][array_key_last($res['collectionsCreate'])]['value']); -// $this->validateDates($res['collectionsCreate']); -// $this->assertEquals($collectionsRead, $res['collectionsRead'][array_key_last($res['collectionsRead'])]['value']); -// $this->validateDates($res['collectionsRead']); -// $this->assertEquals($collectionsUpdate, $res['collectionsUpdate'][array_key_last($res['collectionsUpdate'])]['value']); -// $this->validateDates($res['collectionsUpdate']); -// $this->assertEquals($collectionsDelete, $res['collectionsDelete'][array_key_last($res['collectionsDelete'])]['value']); -// $this->validateDates($res['collectionsDelete']); - -// $this->assertEquals($documentsCreate, $res['documentsCreate'][array_key_last($res['documentsCreate'])]['value']); -// $this->validateDates($res['documentsCreate']); -// $this->assertEquals($documentsRead, $res['documentsRead'][array_key_last($res['documentsRead'])]['value']); -// $this->validateDates($res['documentsRead']); -// $this->assertEquals($documentsDelete, $res['documentsDelete'][array_key_last($res['documentsDelete'])]['value']); -// $this->validateDates($res['documentsDelete']); - -// $res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/usage?range=30d', array_merge($headers, [ -// 'x-appwrite-project' => $projectId, -// 'x-appwrite-mode' => 'admin' -// ])); -// $res = $res['body']; -// $this->assertEquals($documentsCount, $res['documentsCount'][array_key_last($res['documentsCount'])]['value']); -// $this->validateDates($res['documentsCount']); - -// $this->assertEquals($documentsCreate, $res['documentsCreate'][array_key_last($res['documentsCreate'])]['value']); -// $this->validateDates($res['documentsCreate']); -// $this->assertEquals($documentsRead, $res['documentsRead'][array_key_last($res['documentsRead'])]['value']); -// $this->validateDates($res['documentsRead']); -// $this->assertEquals($documentsDelete, $res['documentsDelete'][array_key_last($res['documentsDelete'])]['value']); -// $this->validateDates($res['documentsDelete']); - -// $data['requestsCount'] = $requestsCount; -// return $data; -// } - - -// /** @depends testDatabaseStats */ -// public function testPrepareFunctionsStats(array $data): array -// { -// $headers = $data['headers']; -// $functionId = ''; -// $executionTime = 0; -// $executions = 0; -// $failures = 0; - -// $response1 = $this->client->call(Client::METHOD_POST, '/functions', $headers, [ -// 'functionId' => 'unique()', -// 'name' => 'Test', -// 'runtime' => 'php-8.0', -// 'vars' => [ -// 'funcKey1' => 'funcValue1', -// 'funcKey2' => 'funcValue2', -// 'funcKey3' => 'funcValue3', -// ], -// 'events' => [ -// 'users.*.create', -// 'users.*.delete', -// ], -// 'schedule' => '0 0 1 1 *', -// 'timeout' => 10, -// ]); - -// $functionId = $response1['body']['$id'] ?? ''; - -// $this->assertEquals(201, $response1['headers']['status-code']); -// $this->assertNotEmpty($response1['body']['$id']); - -// $code = realpath(__DIR__ . '/../../resources/functions') . "/php/code.tar.gz"; -// $this->packageCode('php'); - -// $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge($headers, ['content-type' => 'multipart/form-data',]), [ -// 'entrypoint' => 'index.php', -// 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), -// 'activate' => true -// ]); - -// $deploymentId = $deployment['body']['$id'] ?? ''; - -// $this->assertEquals(202, $deployment['headers']['status-code']); -// $this->assertNotEmpty($deployment['body']['$id']); -// $this->assertEquals(true, DateTime::isValid($deployment['body']['$createdAt'])); -// $this->assertEquals('index.php', $deployment['body']['entrypoint']); - -// // Wait for deployment to build. -// sleep(30); - -// $response = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, $headers, []); - -// $this->assertEquals(200, $response['headers']['status-code']); -// $this->assertNotEmpty($response['body']['$id']); -// $this->assertEquals(true, DateTime::isValid($response['body']['$createdAt'])); -// $this->assertEquals(true, DateTime::isValid($response['body']['$updatedAt'])); -// $this->assertEquals($deploymentId, $response['body']['deployment']); - -// $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', $headers, [ -// 'async' => false, -// ]); - -// $this->assertEquals(201, $execution['headers']['status-code']); -// $this->assertNotEmpty($execution['body']['$id']); -// $this->assertEquals($functionId, $execution['body']['functionId']); -// $executionTime += (int) ($execution['body']['duration'] * 1000); -// if ($execution['body']['status'] == 'failed') { -// $failures++; -// } elseif ($execution['body']['status'] == 'completed') { -// $executions++; -// } - -// $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', $headers, [ -// 'async' => false, -// ]); - -// $this->assertEquals(201, $execution['headers']['status-code']); -// $this->assertNotEmpty($execution['body']['$id']); -// $this->assertEquals($functionId, $execution['body']['functionId']); -// if ($execution['body']['status'] == 'failed') { -// $failures++; -// } elseif ($execution['body']['status'] == 'completed') { -// $executions++; -// } -// $executionTime += (int) ($execution['body']['duration'] * 1000); - -// $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', $headers, [ -// 'async' => true, -// ]); - -// sleep(10); - -// $execution = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $execution['body']['$id'], $headers); - -// if ($execution['body']['status'] == 'failed') { -// $failures++; -// } elseif ($execution['body']['status'] == 'completed') { -// $executions++; -// } -// $executionTime += (int) ($execution['body']['duration'] * 1000); - -// $data = array_merge($data, [ -// 'functionId' => $functionId, -// 'executionTime' => $executionTime, -// 'executions' => $executions, -// 'failures' => $failures, -// ]); - -// return $data; -// } - -// /** @depends testPrepareFunctionsStats */ -// #[Retry(count: 1)] -// public function testFunctionsStats(array $data): void -// { -// $headers = $data['headers']; -// $functionId = $data['functionId']; -// $executionTime = $data['executionTime']; -// $executions = $data['executions']; -// $failures = $data['failures']; - -// sleep(20); - -// $response = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/usage', $headers, [ -// 'range' => '30d' -// ]); - -// $this->assertEquals(200, $response['headers']['status-code']); -// $this->assertEquals(9, count($response['body'])); -// $this->assertEquals('30d', $response['body']['range']); -// $this->assertIsArray($response['body']['executionsTotal']); -// $this->assertIsArray($response['body']['executionsFailure']); -// $this->assertIsArray($response['body']['executionsSuccess']); -// $this->assertIsArray($response['body']['executionsTime']); -// $this->assertIsArray($response['body']['buildsTotal']); -// $this->assertIsArray($response['body']['buildsFailure']); -// $this->assertIsArray($response['body']['buildsSuccess']); -// $this->assertIsArray($response['body']['buildsTime']); -// $response = $response['body']; - -// $this->assertEquals($executions, $response['executionsTotal'][array_key_last($response['executionsTotal'])]['value']); -// $this->validateDates($response['executionsTotal']); -// $this->assertEquals($executionTime, $response['executionsTime'][array_key_last($response['executionsTime'])]['value']); -// $this->validateDates($response['executionsTime']); -// $this->assertEquals($failures, $response['executionsFailure'][array_key_last($response['executionsFailure'])]['value']); -// $this->validateDates($response['executionsFailure']); - -// $response = $this->client->call(Client::METHOD_GET, '/functions/usage', $headers, [ -// 'range' => '30d' -// ]); - -// $this->assertEquals(200, $response['headers']['status-code']); -// $this->assertEquals(9, count($response['body'])); -// $this->assertEquals($response['body']['range'], '30d'); -// $this->assertIsArray($response['body']['executionsTotal']); -// $this->assertIsArray($response['body']['executionsFailure']); -// $this->assertIsArray($response['body']['executionsSuccess']); -// $this->assertIsArray($response['body']['executionsTime']); -// $this->assertIsArray($response['body']['buildsTotal']); -// $this->assertIsArray($response['body']['buildsFailure']); -// $this->assertIsArray($response['body']['buildsSuccess']); -// $this->assertIsArray($response['body']['buildsTime']); -// $response = $response['body']; - -// $this->assertEquals($executions, $response['executionsTotal'][array_key_last($response['executionsTotal'])]['value']); -// $this->validateDates($response['executionsTotal']); -// $this->assertEquals($executionTime, $response['executionsTime'][array_key_last($response['executionsTime'])]['value']); -// $this->validateDates($response['executionsTime']); -// $this->assertGreaterThan(0, $response['buildsTime'][array_key_last($response['buildsTime'])]['value']); -// $this->validateDates($response['buildsTime']); -// $this->assertEquals($failures, $response['executionsFailure'][array_key_last($response['executionsFailure'])]['value']); -// $this->validateDates($response['executionsFailure']); -// } - -// protected function tearDown(): void -// { -// $this->usersCount = 0; -// $this->requestsCount = 0; -// $projectId = ''; -// $headers = []; -// } -// } +use Utopia\Database\Helpers\Permission; +use Utopia\Database\Helpers\Role; + +class UsageTest extends Scope +{ + use ProjectCustom; + use SideServer; + use FunctionsBase; + + protected string $projectId; + private int $requestsCount; + private int $usersCount; + + protected function setUp(): void + { + parent::setUp(); + } + + protected static string $formatTz = 'Y-m-d\TH:i:s.vP'; + + protected function validateDates(array $metrics): void + { + foreach ($metrics as $metric) { + $this->assertIsObject(\DateTime::createFromFormat("Y-m-d\TH:i:s.vP", $metric['date'])); + } + } + + public function testPrepareUsersStats(): array + { + $project = $this->getProject(true); + $projectId = $project['$id']; + $headers['x-appwrite-project'] = $project['$id']; + $headers['x-appwrite-key'] = $project['apiKey']; + $headers['content-type'] = 'application/json'; + + $usersCount = 0; + $requestsCount = 0; + for ($i = 0; $i < 10; $i++) { + $email = uniqid() . 'user@usage.test'; + $password = 'password'; + $name = uniqid() . 'User'; + $res = $this->client->call(Client::METHOD_POST, '/users', $headers, [ + 'userId' => 'unique()', + 'email' => $email, + 'password' => $password, + 'name' => $name, + ]); + $this->assertEquals($email, $res['body']['email']); + $this->assertNotEmpty($res['body']['$id']); + $usersCount++; + $requestsCount++; + + if ($i < 5) { + $userId = $res['body']['$id']; + $res = $this->client->call(Client::METHOD_GET, '/users/' . $userId, $headers); + $this->assertEquals($userId, $res['body']['$id']); + $res = $this->client->call(Client::METHOD_DELETE, '/users/' . $userId, $headers); + $this->assertEmpty($res['body']); + $requestsCount += 2; + $usersCount--; + } + } + + return [ + 'projectId' => $projectId, + 'headers' => $headers, + 'usersCount' => $usersCount, + 'requestsCount' => $requestsCount + ]; + } + + /** + * @depends testPrepareUsersStats + */ + #[Retry(count: 1)] + public function testUsersStats(array $data): array + { + sleep(20); + + $projectId = $data['projectId']; + $headers = $data['headers']; + $usersCount = $data['usersCount']; + $requestsCount = $data['requestsCount']; + + //console request + $headers = [ + 'origin' => 'http:localhost', + 'x-appwrite-project' => 'console', + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'x-appwrite-project' => $projectId, + 'x-appwrite-mode' => 'admin', + ]; + + $res = $this->client->call(Client::METHOD_GET, '/project/usage?range=30d', $headers); + $res = $res['body']; + + $this->assertEquals(9, count($res)); + $this->assertEquals(30, count($res['requests'])); + $this->assertEquals(30, count($res['users'])); + $this->assertEquals($usersCount, $res['users'][array_key_last($res['users'])]['value']); + $this->validateDates($res['users']); + $this->assertEquals($requestsCount, $res['requests'][array_key_last($res['requests'])]['value']); + $this->validateDates($res['requests']); + + $res = $this->client->call(Client::METHOD_GET, '/users/usage?range=30d', array_merge($headers, [ + 'x-appwrite-project' => $projectId, + 'x-appwrite-mode' => 'admin' + ])); + $requestsCount++; + $res = $res['body']; + $this->assertEquals(10, $res['usersCreate'][array_key_last($res['usersCreate'])]['value']); + $this->validateDates($res['usersCreate']); + $this->assertEquals(5, $res['usersRead'][array_key_last($res['usersRead'])]['value']); + $this->validateDates($res['usersRead']); + $this->assertEquals(5, $res['usersDelete'][array_key_last($res['usersDelete'])]['value']); + $this->validateDates($res['usersDelete']); + + return ['projectId' => $projectId, 'headers' => $headers, 'requestsCount' => $requestsCount]; + } + + /** @depends testUsersStats */ + public function testPrepareStorageStats(array $data): array + { + $projectId = $data['projectId']; + $headers = $data['headers']; + + $bucketId = ''; + $bucketsCount = 0; + $requestsCount = $data['requestsCount']; + $storageTotal = 0; + $bucketsCreate = 0; + $bucketsDelete = 0; + $bucketsRead = 0; + $filesCount = 0; + $filesRead = 0; + $filesCreate = 0; + $filesDelete = 0; + + for ($i = 0; $i < 10; $i++) { + $name = uniqid() . ' bucket'; + $res = $this->client->call(Client::METHOD_POST, '/storage/buckets', \array_merge($headers, [ + 'content-type' => 'application/json' + ]), [ + 'bucketId' => 'unique()', + 'name' => $name, + 'fileSecurity' => false, + 'permissions' => [ + Permission::read(Role::any()), + Permission::create(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + ]); + $this->assertEquals($name, $res['body']['name']); + $this->assertNotEmpty($res['body']['$id']); + $bucketId = $res['body']['$id']; + + $bucketsCreate++; + $bucketsCount++; + $requestsCount++; + + if ($i < 5) { + $res = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId, $headers); + $this->assertEquals($bucketId, $res['body']['$id']); + $bucketsRead++; + + $res = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId, $headers); + $this->assertEmpty($res['body']); + $bucketsDelete++; + + $requestsCount += 2; + $bucketsCount--; + } + } + + //upload some files + $files = [ + [ + 'path' => realpath(__DIR__ . '/../../resources/logo.png'), + 'name' => 'logo.png', + ], + [ + 'path' => realpath(__DIR__ . '/../../resources/file.png'), + 'name' => 'file.png', + ], + [ + 'path' => realpath(__DIR__ . '/../../resources/disk-a/kitten-3.gif'), + 'name' => 'kitten-3.gif', + ], + [ + 'path' => realpath(__DIR__ . '/../../resources/disk-a/kitten-1.jpg'), + 'name' => 'kitten-1.jpg', + ], + ]; + + for ($i = 0; $i < 10; $i++) { + $file = $files[$i % count($files)]; + $res = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge($headers, ['content-type' => 'multipart/form-data']), [ + 'fileId' => 'unique()', + 'file' => new CURLFile($file['path'], '', $file['name']), + ]); + $this->assertNotEmpty($res['body']['$id']); + + $fileSize = $res['body']['sizeOriginal']; + $storageTotal += $fileSize; + $filesCount++; + $filesCreate++; + $requestsCount++; + + $fileId = $res['body']['$id']; + if ($i < 5) { + $res = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, $headers); + $this->assertEquals($fileId, $res['body']['$id']); + $filesRead++; + + $res = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, $headers); + $this->assertEmpty($res['body']); + $filesDelete++; + $requestsCount += 2; + $filesCount--; + $storageTotal -= $fileSize; + } + } + + return array_merge($data, [ + 'bucketId' => $bucketId, + 'bucketsCount' => $bucketsCount, + 'requestsCount' => $requestsCount, + 'storageTotal' => $storageTotal, + 'bucketsCreate' => $bucketsCreate, + 'bucketsDelete' => $bucketsDelete, + 'bucketsRead' => $bucketsRead, + 'filesCount' => $filesCount, + 'filesRead' => $filesRead, + 'filesCreate' => $filesCreate, + 'filesDelete' => $filesDelete, + ]); + } + + /** + * @depends testPrepareStorageStats + */ + #[Retry(count: 1)] + public function testStorageStats(array $data): array + { + $projectId = $data['projectId']; + $bucketId = $data['bucketId']; + $bucketsCount = $data['bucketsCount']; + $requestsCount = $data['requestsCount']; + $storageTotal = $data['storageTotal']; + $bucketsCreate = $data['bucketsCreate']; + $bucketsDelete = $data['bucketsDelete']; + $bucketsRead = $data['bucketsRead']; + $filesCount = $data['filesCount']; + $filesRead = $data['filesRead']; + $filesCreate = $data['filesCreate']; + $filesDelete = $data['filesDelete']; + + sleep(20); + + //console request + $headers = [ + 'origin' => 'http:localhost', + 'x-appwrite-project' => 'console', + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'x-appwrite-project' => $projectId, + 'x-appwrite-mode' => 'admin', + ]; + + $res = $this->client->call(Client::METHOD_GET, '/project/usage?range=30d', $headers); + $res = $res['body']; + + $this->assertEquals(9, count($res)); + $this->assertEquals(30, count($res['requests'])); + $this->assertEquals(30, count($res['storage'])); + $this->assertEquals($requestsCount, $res['requests'][array_key_last($res['requests'])]['value']); + $this->validateDates($res['requests']); + $this->assertEquals($storageTotal, $res['storage'][array_key_last($res['storage'])]['value']); + $this->validateDates($res['storage']); + + $res = $this->client->call(Client::METHOD_GET, '/storage/usage?range=30d', array_merge($headers, [ + 'x-appwrite-project' => $projectId, + 'x-appwrite-mode' => 'admin' + ])); + $requestsCount++; + $res = $res['body']; + $this->assertEquals($storageTotal, $res['storage'][array_key_last($res['storage'])]['value']); + $this->validateDates($res['storage']); + $this->assertEquals($bucketsCount, $res['bucketsCount'][array_key_last($res['bucketsCount'])]['value']); + $this->validateDates($res['bucketsCount']); + $this->assertEquals($bucketsRead, $res['bucketsRead'][array_key_last($res['bucketsRead'])]['value']); + $this->validateDates($res['bucketsRead']); + $this->assertEquals($bucketsCreate, $res['bucketsCreate'][array_key_last($res['bucketsCreate'])]['value']); + $this->validateDates($res['bucketsCreate']); + $this->assertEquals($bucketsDelete, $res['bucketsDelete'][array_key_last($res['bucketsDelete'])]['value']); + $this->validateDates($res['bucketsDelete']); + $this->assertEquals($filesCount, $res['filesCount'][array_key_last($res['filesCount'])]['value']); + $this->validateDates($res['filesCount']); + $this->assertEquals($filesRead, $res['filesRead'][array_key_last($res['filesRead'])]['value']); + $this->validateDates($res['filesRead']); + $this->assertEquals($filesCreate, $res['filesCreate'][array_key_last($res['filesCreate'])]['value']); + $this->validateDates($res['filesCreate']); + $this->assertEquals($filesDelete, $res['filesDelete'][array_key_last($res['filesDelete'])]['value']); + $this->validateDates($res['filesDelete']); + + $res = $this->client->call(Client::METHOD_GET, '/storage/' . $bucketId . '/usage?range=30d', array_merge($headers, [ + 'x-appwrite-project' => $projectId, + 'x-appwrite-mode' => 'admin' + ])); + $requestsCount++; + $res = $res['body']; + $this->assertEquals($storageTotal, $res['filesStorage'][array_key_last($res['filesStorage'])]['value']); + $this->assertEquals($filesCount, $res['filesCount'][array_key_last($res['filesCount'])]['value']); + $this->assertEquals($filesRead, $res['filesRead'][array_key_last($res['filesRead'])]['value']); + $this->assertEquals($filesCreate, $res['filesCreate'][array_key_last($res['filesCreate'])]['value']); + $this->assertEquals($filesDelete, $res['filesDelete'][array_key_last($res['filesDelete'])]['value']); + + $data['requestsCount'] = $requestsCount; + return $data; + } + + /** @depends testStorageStats */ + public function testPrepareDatabaseStats(array $data): array + { + $headers = $data['headers']; + $projectId = $data['projectId']; + + $databaseId = ''; + $collectionId = ''; + + $requestsCount = $data['requestsCount']; + $databasesCount = 0; + $databasesCreate = 0; + $databasesRead = 0; + $databasesDelete = 0; + + $collectionsCount = 0; + $collectionsCreate = 0; + $collectionsRead = 0; + $collectionsUpdate = 0; + $collectionsDelete = 0; + + $documentsCount = 0; + $documentsCreate = 0; + $documentsRead = 0; + $documentsDelete = 0; + + for ($i = 0; $i < 10; $i++) { + $name = uniqid() . ' database'; + $res = $this->client->call(Client::METHOD_POST, '/databases', $headers, [ + 'databaseId' => 'unique()', + 'name' => $name, + ]); + $this->assertEquals($name, $res['body']['name']); + $this->assertNotEmpty($res['body']['$id']); + $databaseId = $res['body']['$id']; + + $requestsCount++; + $databasesCount++; + $databasesCreate++; + + if ($i < 5) { + $res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId, $headers); + $this->assertEquals($databaseId, $res['body']['$id']); + $databasesRead++; + + $res = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, $headers); + $this->assertEmpty($res['body']); + $databasesDelete++; + + $databasesCount--; + $requestsCount += 2; + } + } + + for ($i = 0; $i < 10; $i++) { + $name = uniqid() . ' collection'; + $res = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', $headers, [ + 'collectionId' => 'unique()', + 'name' => $name, + 'documentSecurity' => false, + 'permissions' => [ + Permission::read(Role::any()), + Permission::create(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + ]); + $this->assertEquals($name, $res['body']['name']); + $this->assertNotEmpty($res['body']['$id']); + $collectionId = $res['body']['$id']; + + $requestsCount++; + $collectionsCount++; + $collectionsCreate++; + + if ($i < 5) { + $res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, $headers); + $this->assertEquals($collectionId, $res['body']['$id']); + $collectionsRead++; + + $res = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId, $headers); + $this->assertEmpty($res['body']); + $collectionsDelete++; + + $collectionsCount--; + $requestsCount += 2; + } + } + + $res = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes' . '/string', $headers, [ + 'key' => 'name', + 'size' => 255, + 'required' => true, + ]); + $this->assertEquals('name', $res['body']['key']); + $collectionsUpdate++; + $requestsCount++; + sleep(20); + + for ($i = 0; $i < 10; $i++) { + $name = uniqid() . ' collection'; + $res = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', $headers, [ + 'documentId' => 'unique()', + 'data' => ['name' => $name] + ]); + $this->assertEquals($name, $res['body']['name']); + $this->assertNotEmpty($res['body']['$id']); + $documentId = $res['body']['$id']; + + $requestsCount++; + $documentsCount++; + $documentsCreate++; + + if ($i < 5) { + $res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, $headers); + $this->assertEquals($documentId, $res['body']['$id']); + $documentsRead++; + + $res = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, $headers); + $this->assertEmpty($res['body']); + $documentsDelete++; + + $documentsCount--; + $requestsCount += 2; + } + } + + $data = array_merge($data, [ + 'databaseId' => $databaseId, + 'collectionId' => $collectionId, + + 'requestsCount' => $requestsCount, + 'databasesCount' => $databasesCount, + 'databasesCreate' => $databasesCreate, + 'databasesRead' => $databasesRead, + 'databasesDelete' => $databasesDelete, + + 'collectionsCount' => $collectionsCount, + 'collectionsCreate' => $collectionsCreate, + 'collectionsRead' => $collectionsRead, + 'collectionsUpdate' => $collectionsUpdate, + 'collectionsDelete' => $collectionsDelete, + + 'documentsCount' => $documentsCount, + 'documentsCreate' => $documentsCreate, + 'documentsRead' => $documentsRead, + 'documentsDelete' => $documentsDelete, + ]); + + return $data; + } + + /** @depends testPrepareDatabaseStats */ + #[Retry(count: 1)] + public function testDatabaseStats(array $data): array + { + $headers = $data['headers']; + $projectId = $data['projectId']; + + $databaseId = $data['databaseId']; + $collectionId = $data['collectionId']; + + $requestsCount = $data['requestsCount']; + $databasesCount = $data['databasesCount']; + $databasesCreate = $data['databasesCreate']; + $databasesRead = $data['databasesRead']; + $databasesDelete = $data['databasesDelete']; + + $collectionsCount = $data['collectionsCount']; + $collectionsCreate = $data['collectionsCreate']; + $collectionsRead = $data['collectionsRead']; + $collectionsUpdate = $data['collectionsUpdate']; + $collectionsDelete = $data['collectionsDelete']; + + $documentsCount = $data['documentsCount']; + $documentsCreate = $data['documentsCreate']; + $documentsRead = $data['documentsRead']; + $documentsDelete = $data['documentsDelete']; + + sleep(20); + + //check datbase stats + $headers = [ + 'origin' => 'http:localhost', + 'x-appwrite-project' => 'console', + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'x-appwrite-project' => $projectId, + 'x-appwrite-mode' => 'admin', + ]; + + $res = $this->client->call(Client::METHOD_GET, '/project/usage?range=30d', $headers); + $res = $res['body']; + + $this->assertEquals(9, count($res)); + $this->assertEquals(30, count($res['requests'])); + $this->assertEquals(30, count($res['storage'])); + $this->assertEquals($requestsCount, $res['requests'][array_key_last($res['requests'])]['value']); + $this->validateDates($res['requests']); + $this->assertEquals($databasesCount, $res['databases'][array_key_last($res['databases'])]['value']); + $this->validateDates($res['databases']); + $this->assertEquals($documentsCount, $res['documents'][array_key_last($res['documents'])]['value']); + $this->validateDates($res['documents']); + + $res = $this->client->call(Client::METHOD_GET, '/databases/usage?range=30d', array_merge($headers, [ + 'x-appwrite-project' => $projectId, + 'x-appwrite-mode' => 'admin' + ])); + $res = $res['body']; + $this->assertEquals($databasesCount, $res['databasesCount'][array_key_last($res['databasesCount'])]['value']); + $this->validateDates($res['databasesCount']); + $this->assertEquals($collectionsCount, $res['collectionsCount'][array_key_last($res['collectionsCount'])]['value']); + $this->validateDates($res['collectionsCount']); + $this->assertEquals($documentsCount, $res['documentsCount'][array_key_last($res['documentsCount'])]['value']); + $this->validateDates($res['documentsCount']); + + $this->assertEquals($databasesCreate, $res['databasesCreate'][array_key_last($res['databasesCreate'])]['value']); + $this->validateDates($res['databasesCreate']); + $this->assertEquals($databasesRead, $res['databasesRead'][array_key_last($res['databasesRead'])]['value']); + $this->validateDates($res['databasesRead']); + $this->assertEquals($databasesDelete, $res['databasesDelete'][array_key_last($res['databasesDelete'])]['value']); + $this->validateDates($res['databasesDelete']); + + $this->assertEquals($collectionsCreate, $res['collectionsCreate'][array_key_last($res['collectionsCreate'])]['value']); + $this->validateDates($res['collectionsCreate']); + $this->assertEquals($collectionsRead, $res['collectionsRead'][array_key_last($res['collectionsRead'])]['value']); + $this->validateDates($res['collectionsRead']); + $this->assertEquals($collectionsUpdate, $res['collectionsUpdate'][array_key_last($res['collectionsUpdate'])]['value']); + $this->validateDates($res['collectionsUpdate']); + $this->assertEquals($collectionsDelete, $res['collectionsDelete'][array_key_last($res['collectionsDelete'])]['value']); + $this->validateDates($res['collectionsDelete']); + + $this->assertEquals($documentsCreate, $res['documentsCreate'][array_key_last($res['documentsCreate'])]['value']); + $this->validateDates($res['documentsCreate']); + $this->assertEquals($documentsRead, $res['documentsRead'][array_key_last($res['documentsRead'])]['value']); + $this->validateDates($res['documentsRead']); + $this->assertEquals($documentsDelete, $res['documentsDelete'][array_key_last($res['documentsDelete'])]['value']); + $this->validateDates($res['documentsDelete']); + + $res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/usage?range=30d', array_merge($headers, [ + 'x-appwrite-project' => $projectId, + 'x-appwrite-mode' => 'admin' + ])); + $res = $res['body']; + $this->assertEquals($collectionsCount, $res['collectionsCount'][array_key_last($res['collectionsCount'])]['value']); + $this->validateDates($res['collectionsCount']); + $this->assertEquals($documentsCount, $res['documentsCount'][array_key_last($res['documentsCount'])]['value']); + $this->validateDates($res['documentsCount']); + + $this->assertEquals($collectionsCreate, $res['collectionsCreate'][array_key_last($res['collectionsCreate'])]['value']); + $this->validateDates($res['collectionsCreate']); + $this->assertEquals($collectionsRead, $res['collectionsRead'][array_key_last($res['collectionsRead'])]['value']); + $this->validateDates($res['collectionsRead']); + $this->assertEquals($collectionsUpdate, $res['collectionsUpdate'][array_key_last($res['collectionsUpdate'])]['value']); + $this->validateDates($res['collectionsUpdate']); + $this->assertEquals($collectionsDelete, $res['collectionsDelete'][array_key_last($res['collectionsDelete'])]['value']); + $this->validateDates($res['collectionsDelete']); + + $this->assertEquals($documentsCreate, $res['documentsCreate'][array_key_last($res['documentsCreate'])]['value']); + $this->validateDates($res['documentsCreate']); + $this->assertEquals($documentsRead, $res['documentsRead'][array_key_last($res['documentsRead'])]['value']); + $this->validateDates($res['documentsRead']); + $this->assertEquals($documentsDelete, $res['documentsDelete'][array_key_last($res['documentsDelete'])]['value']); + $this->validateDates($res['documentsDelete']); + + $res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/usage?range=30d', array_merge($headers, [ + 'x-appwrite-project' => $projectId, + 'x-appwrite-mode' => 'admin' + ])); + $res = $res['body']; + $this->assertEquals($documentsCount, $res['documentsCount'][array_key_last($res['documentsCount'])]['value']); + $this->validateDates($res['documentsCount']); + + $this->assertEquals($documentsCreate, $res['documentsCreate'][array_key_last($res['documentsCreate'])]['value']); + $this->validateDates($res['documentsCreate']); + $this->assertEquals($documentsRead, $res['documentsRead'][array_key_last($res['documentsRead'])]['value']); + $this->validateDates($res['documentsRead']); + $this->assertEquals($documentsDelete, $res['documentsDelete'][array_key_last($res['documentsDelete'])]['value']); + $this->validateDates($res['documentsDelete']); + + $data['requestsCount'] = $requestsCount; + return $data; + } + + + /** @depends testDatabaseStats */ + public function testPrepareFunctionsStats(array $data): array + { + $headers = $data['headers']; + $functionId = ''; + $executionTime = 0; + $executions = 0; + $failures = 0; + + $response1 = $this->client->call(Client::METHOD_POST, '/functions', $headers, [ + 'functionId' => 'unique()', + 'name' => 'Test', + 'runtime' => 'php-8.0', + 'vars' => [ + 'funcKey1' => 'funcValue1', + 'funcKey2' => 'funcValue2', + 'funcKey3' => 'funcValue3', + ], + 'events' => [ + 'users.*.create', + 'users.*.delete', + ], + 'schedule' => '0 0 1 1 *', + 'timeout' => 10, + ]); + + $functionId = $response1['body']['$id'] ?? ''; + + $this->assertEquals(201, $response1['headers']['status-code']); + $this->assertNotEmpty($response1['body']['$id']); + + $code = realpath(__DIR__ . '/../../resources/functions') . "/php/code.tar.gz"; + $this->packageCode('php'); + + $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge($headers, ['content-type' => 'multipart/form-data',]), [ + 'entrypoint' => 'index.php', + 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), + 'activate' => true + ]); + + $deploymentId = $deployment['body']['$id'] ?? ''; + + $this->assertEquals(202, $deployment['headers']['status-code']); + $this->assertNotEmpty($deployment['body']['$id']); + $this->assertEquals(true, DateTime::isValid($deployment['body']['$createdAt'])); + $this->assertEquals('index.php', $deployment['body']['entrypoint']); + + //Wait for deployment to build. + sleep(30); + + $response = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, $headers, []); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertNotEmpty($response['body']['$id']); + $this->assertEquals(true, DateTime::isValid($response['body']['$createdAt'])); + $this->assertEquals(true, DateTime::isValid($response['body']['$updatedAt'])); + $this->assertEquals($deploymentId, $response['body']['deployment']); + + $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', $headers, [ + 'async' => false, + ]); + + $this->assertEquals(201, $execution['headers']['status-code']); + $this->assertNotEmpty($execution['body']['$id']); + $this->assertEquals($functionId, $execution['body']['functionId']); + $executionTime += (int) ($execution['body']['duration'] * 1000); + if ($execution['body']['status'] == 'failed') { + $failures++; + } elseif ($execution['body']['status'] == 'completed') { + $executions++; + } + + $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', $headers, [ + 'async' => false, + ]); + + $this->assertEquals(201, $execution['headers']['status-code']); + $this->assertNotEmpty($execution['body']['$id']); + $this->assertEquals($functionId, $execution['body']['functionId']); + if ($execution['body']['status'] == 'failed') { + $failures++; + } elseif ($execution['body']['status'] == 'completed') { + $executions++; + } + $executionTime += (int) ($execution['body']['duration'] * 1000); + + $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', $headers, [ + 'async' => true, + ]); + + sleep(10); + + $execution = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $execution['body']['$id'], $headers); + + if ($execution['body']['status'] == 'failed') { + $failures++; + } elseif ($execution['body']['status'] == 'completed') { + $executions++; + } + $executionTime += (int) ($execution['body']['duration'] * 1000); + + return array_merge($data, [ + 'functionId' => $functionId, + 'executionTime' => $executionTime, + 'executions' => $executions, + 'failures' => $failures, + ]); + } + + /** @depends testPrepareFunctionsStats */ + #[Retry(count: 1)] + public function testFunctionsStats(array $data): void + { + $headers = $data['headers']; + $functionId = $data['functionId']; + $executionTime = $data['executionTime']; + $executions = $data['executions']; + $failures = $data['failures']; + + sleep(20); + + $response = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/usage', $headers, [ + 'range' => '30d' + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(9, count($response['body'])); + $this->assertEquals('30d', $response['body']['range']); + $this->assertIsArray($response['body']['executionsTotal']); + $this->assertIsArray($response['body']['executionsFailure']); + $this->assertIsArray($response['body']['executionsSuccess']); + $this->assertIsArray($response['body']['executionsTime']); + $this->assertIsArray($response['body']['buildsTotal']); + $this->assertIsArray($response['body']['buildsFailure']); + $this->assertIsArray($response['body']['buildsSuccess']); + $this->assertIsArray($response['body']['buildsTime']); + $response = $response['body']; + + $this->assertEquals($executions, $response['executionsTotal'][array_key_last($response['executionsTotal'])]['value']); + $this->validateDates($response['executionsTotal']); + $this->assertEquals($executionTime, $response['executionsTime'][array_key_last($response['executionsTime'])]['value']); + $this->validateDates($response['executionsTime']); + $this->assertEquals($failures, $response['executionsFailure'][array_key_last($response['executionsFailure'])]['value']); + $this->validateDates($response['executionsFailure']); + + $response = $this->client->call(Client::METHOD_GET, '/functions/usage', $headers, [ + 'range' => '30d' + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(9, count($response['body'])); + $this->assertEquals($response['body']['range'], '30d'); + $this->assertIsArray($response['body']['executionsTotal']); + $this->assertIsArray($response['body']['executionsFailure']); + $this->assertIsArray($response['body']['executionsSuccess']); + $this->assertIsArray($response['body']['executionsTime']); + $this->assertIsArray($response['body']['buildsTotal']); + $this->assertIsArray($response['body']['buildsFailure']); + $this->assertIsArray($response['body']['buildsSuccess']); + $this->assertIsArray($response['body']['buildsTime']); + $response = $response['body']; + + $this->assertEquals($executions, $response['executionsTotal'][array_key_last($response['executionsTotal'])]['value']); + $this->validateDates($response['executionsTotal']); + $this->assertEquals($executionTime, $response['executionsTime'][array_key_last($response['executionsTime'])]['value']); + $this->validateDates($response['executionsTime']); + $this->assertGreaterThan(0, $response['buildsTime'][array_key_last($response['buildsTime'])]['value']); + $this->validateDates($response['buildsTime']); + $this->assertEquals($failures, $response['executionsFailure'][array_key_last($response['executionsFailure'])]['value']); + $this->validateDates($response['executionsFailure']); + } + + protected function tearDown(): void + { + $this->usersCount = 0; + $this->requestsCount = 0; + $projectId = ''; + $headers = []; + } +}