Merge branch '1.7.x' into fix-usage-queues

This commit is contained in:
Christy Jacob 2025-06-04 13:58:56 +04:00 committed by GitHub
commit c0fd5f6233
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
51 changed files with 492 additions and 449 deletions

View file

@ -7,4 +7,5 @@ return [
"png" => "image/png",
"heic" => "image/heic",
"webp" => "image/webp",
"gif" => "image/gif",
];

View file

@ -8,4 +8,5 @@ return [
"webp" => "image/webp",
"heic" => "image/heic",
"avif" => "image/avif",
"gif" => "image/gif",
];

View file

@ -0,0 +1,6 @@
<?php
use Utopia\Image\Image;
use Utopia\System\System;
Image::setResourceLimit('memory', intval(System::getEnv('_APP_IMAGES_RESOURCE_LIMIT_MEMORY', 1024*1024*64)));

View file

@ -1215,6 +1215,7 @@ App::post('/v1/vcs/github/events')
if ($event == $github::EVENT_PUSH) {
$providerBranchCreated = $parsedPayload["branchCreated"] ?? false;
$providerBranchDeleted = $parsedPayload["branchDeleted"] ?? false;
$providerBranch = $parsedPayload["branch"] ?? '';
$providerBranchUrl = $parsedPayload["branchUrl"] ?? '';
$providerRepositoryId = $parsedPayload["repositoryId"] ?? '';
@ -1236,8 +1237,8 @@ App::post('/v1/vcs/github/events')
Query::limit(100),
]));
// create new deployment only on push and not when branch is created
if (!$providerBranchCreated) {
// create new deployment only on push and not when branch is created or deleted
if (!$providerBranchCreated && !$providerBranchDeleted) {
$createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, '', false, $dbForPlatform, $queueForBuilds, $getProjectDB, $request);
}
} elseif ($event == $github::EVENT_INSTALLATION) {

View file

@ -749,12 +749,6 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
return false;
} elseif ($type === 'redirect') {
$url = $rule->getAttribute('redirectUrl', '');
$query = ($swooleRequest->server['query_string'] ?? '');
if (!empty($query)) {
$url .= '?' . $query;
}
$response->redirect($url, \intval($rule->getAttribute('redirectStatusCode', 301)));
return true;
} else {

View file

@ -2,6 +2,8 @@
use Utopia\Config\Config;
require_once __DIR__ . '/../config/storage/resource_limits.php';
Config::load('template-runtimes', __DIR__ . '/../config/template-runtimes.php');
Config::load('events', __DIR__ . '/../config/events.php');
Config::load('auth', __DIR__ . '/../config/auth.php');

View file

@ -52,6 +52,7 @@ use Utopia\Storage\Device\S3;
use Utopia\Storage\Device\Wasabi;
use Utopia\Storage\Storage;
use Utopia\System\System;
use Utopia\Telemetry\Adapter as Telemetry;
use Utopia\Telemetry\Adapter\None as NoTelemetry;
use Utopia\Validator\Hostname;
use Utopia\Validator\WhiteList;
@ -454,7 +455,7 @@ App::setResource('getLogsDB', function (Group $pools, Cache $cache) {
App::setResource('telemetry', fn () => new NoTelemetry());
App::setResource('cache', function (Group $pools) {
App::setResource('cache', function (Group $pools, Telemetry $telemetry) {
$list = Config::getParam('pools-cache', []);
$adapters = [];
@ -462,8 +463,10 @@ App::setResource('cache', function (Group $pools) {
$adapters[] = new CachePool($pools->get($value));
}
return new Cache(new Sharding($adapters));
}, ['pools']);
$cache = new Cache(new Sharding($adapters));
$cache->setTelemetry($telemetry);
return $cache;
}, ['pools', 'telemetry']);
App::setResource('redis', function () {
$host = System::getEnv('_APP_REDIS_HOST', 'localhost');
@ -486,24 +489,24 @@ App::setResource('timelimit', function (\Redis $redis) {
};
}, ['redis']);
App::setResource('deviceForLocal', function () {
return new Local();
});
App::setResource('deviceForFiles', function ($project) {
return getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId());
}, ['project']);
App::setResource('deviceForSites', function ($project) {
return getDevice(APP_STORAGE_SITES . '/app-' . $project->getId());
}, ['project']);
App::setResource('deviceForImports', function ($project) {
return getDevice(APP_STORAGE_IMPORTS . '/app-' . $project->getId());
}, ['project']);
App::setResource('deviceForFunctions', function ($project) {
return getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId());
}, ['project']);
App::setResource('deviceForBuilds', function ($project) {
return getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId());
}, ['project']);
App::setResource('deviceForLocal', function (Telemetry $telemetry) {
return new Device\Telemetry($telemetry, new Local());
}, ['telemetry']);
App::setResource('deviceForFiles', function ($project, Telemetry $telemetry) {
return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
App::setResource('deviceForSites', function ($project, Telemetry $telemetry) {
return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_SITES . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
App::setResource('deviceForImports', function ($project, Telemetry $telemetry) {
return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_IMPORTS . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
App::setResource('deviceForFunctions', function ($project, Telemetry $telemetry) {
return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
App::setResource('deviceForBuilds', function ($project, Telemetry $telemetry) {
return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
function getDevice(string $root, string $connection = ''): Device
{

View file

@ -18,7 +18,9 @@ use Appwrite\Event\StatsUsage;
use Appwrite\Event\Webhook;
use Appwrite\Platform\Appwrite;
use Executor\Executor;
use Swoole\Process;
use Swoole\Runtime;
use Swoole\Timer;
use Utopia\Abuse\Adapters\TimeLimit\Redis as TimeLimitRedis;
use Utopia\Cache\Adapter\Pool as CachePool;
use Utopia\Cache\Adapter\Sharding;
@ -40,7 +42,9 @@ use Utopia\Queue\Message;
use Utopia\Queue\Publisher;
use Utopia\Queue\Server;
use Utopia\Registry\Registry;
use Utopia\Storage\Device\Telemetry as TelemetryDevice;
use Utopia\System\System;
use Utopia\Telemetry\Adapter as Telemetry;
use Utopia\Telemetry\Adapter\None as NoTelemetry;
Authorization::disable();
@ -311,29 +315,29 @@ Server::setResource('pools', function (Registry $register) {
Server::setResource('telemetry', fn () => new NoTelemetry());
Server::setResource('deviceForSites', function (Document $project) {
return getDevice(APP_STORAGE_SITES . '/app-' . $project->getId());
}, ['project']);
Server::setResource('deviceForSites', function (Document $project, Telemetry $telemetry) {
return new TelemetryDevice($telemetry, getDevice(APP_STORAGE_SITES . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
Server::setResource('deviceForImports', function (Document $project) {
return getDevice(APP_STORAGE_IMPORTS . '/app-' . $project->getId());
}, ['project']);
Server::setResource('deviceForImports', function (Document $project, Telemetry $telemetry) {
return new TelemetryDevice($telemetry, getDevice(APP_STORAGE_IMPORTS . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
Server::setResource('deviceForFunctions', function (Document $project) {
return getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId());
}, ['project']);
Server::setResource('deviceForFunctions', function (Document $project, Telemetry $telemetry) {
return new TelemetryDevice($telemetry, getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
Server::setResource('deviceForFiles', function (Document $project) {
return getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId());
}, ['project']);
Server::setResource('deviceForFiles', function (Document $project, Telemetry $telemetry) {
return new TelemetryDevice($telemetry, getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
Server::setResource('deviceForBuilds', function (Document $project) {
return getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId());
}, ['project']);
Server::setResource('deviceForBuilds', function (Document $project, Telemetry $telemetry) {
return new TelemetryDevice($telemetry, getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
Server::setResource('deviceForCache', function (Document $project) {
return getDevice(APP_STORAGE_CACHE . '/app-' . $project->getId());
}, ['project']);
Server::setResource('deviceForCache', function (Document $project, Telemetry $telemetry) {
return new TelemetryDevice($telemetry, getDevice(APP_STORAGE_CACHE . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
Server::setResource(
'isResourceBlocked',
@ -480,8 +484,15 @@ $worker
});
$worker->workerStart()
->action(function () use ($workerName) {
Console::info("Worker $workerName started");
->action(function () use ($worker, $workerName) {
Console::info("Worker $workerName started");
Process::signal(SIGTERM, function () use ($worker, $workerName) {
Console::info("Stopping worker $workerName.");
$worker->stop();
Timer::clearAll();
});
});
$worker->start();

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php doctor $@
exec php /usr/src/code/app/cli.php doctor $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php install $@
exec php /usr/src/code/app/cli.php install $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php maintenance $@
exec php /usr/src/code/app/cli.php maintenance $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php migrate $@
exec php /usr/src/code/app/cli.php migrate $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php queue-count --type=failed $@
exec php /usr/src/code/app/cli.php queue-count --type=failed $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php queue-count --type=processing $@
exec php /usr/src/code/app/cli.php queue-count --type=processing $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php queue-count --type=success $@
exec php /usr/src/code/app/cli.php queue-count --type=success $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php queue-retry $@
exec php /usr/src/code/app/cli.php queue-retry $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/realtime.php $@
exec php /usr/src/code/app/realtime.php $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php schedule-executions $@
exec php /usr/src/code/app/cli.php schedule-executions $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php schedule-functions $@
exec php /usr/src/code/app/cli.php schedule-functions $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php schedule-messages $@
exec php /usr/src/code/app/cli.php schedule-messages $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php screenshot $@
exec php /usr/src/code/app/cli.php screenshot $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php sdks $@
exec php /usr/src/code/app/cli.php sdks $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php specs $@
exec php /usr/src/code/app/cli.php specs $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php ssl $@
exec php /usr/src/code/app/cli.php ssl $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php stats-resources $@
exec php /usr/src/code/app/cli.php stats-resources $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
/usr/src/code/vendor/bin/phpunit --configuration /usr/src/code/phpunit.xml $@
exec /usr/src/code/vendor/bin/phpunit --configuration /usr/src/code/phpunit.xml $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php upgrade $@
exec php /usr/src/code/app/cli.php upgrade $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php vars $@
exec php /usr/src/code/app/cli.php vars $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php audits $@
exec php /usr/src/code/app/worker.php audits $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php builds $@
exec php /usr/src/code/app/worker.php builds $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php certificates $@
exec php /usr/src/code/app/worker.php certificates $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php databases $@
exec php /usr/src/code/app/worker.php databases $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php deletes $@
exec php /usr/src/code/app/worker.php deletes $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php functions $@
exec php /usr/src/code/app/worker.php functions $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php mails $@
exec php /usr/src/code/app/worker.php mails $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php messaging $@
exec php /usr/src/code/app/worker.php messaging $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php migrations $@
exec php /usr/src/code/app/worker.php migrations $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php stats-resources $@
exec php /usr/src/code/app/worker.php stats-resources $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php stats-usage $@
exec php /usr/src/code/app/worker.php stats-usage $@

View file

@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php webhooks $@
exec php /usr/src/code/app/worker.php webhooks $@

117
composer.lock generated
View file

@ -283,16 +283,16 @@
},
{
"name": "brick/math",
"version": "0.12.3",
"version": "0.13.1",
"source": {
"type": "git",
"url": "https://github.com/brick/math.git",
"reference": "866551da34e9a618e64a819ee1e01c20d8a588ba"
"reference": "fc7ed316430118cc7836bf45faff18d5dfc8de04"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/brick/math/zipball/866551da34e9a618e64a819ee1e01c20d8a588ba",
"reference": "866551da34e9a618e64a819ee1e01c20d8a588ba",
"url": "https://api.github.com/repos/brick/math/zipball/fc7ed316430118cc7836bf45faff18d5dfc8de04",
"reference": "fc7ed316430118cc7836bf45faff18d5dfc8de04",
"shasum": ""
},
"require": {
@ -331,7 +331,7 @@
],
"support": {
"issues": "https://github.com/brick/math/issues",
"source": "https://github.com/brick/math/tree/0.12.3"
"source": "https://github.com/brick/math/tree/0.13.1"
},
"funding": [
{
@ -339,7 +339,7 @@
"type": "github"
}
],
"time": "2025-02-28T13:11:00+00:00"
"time": "2025-03-29T13:50:30+00:00"
},
{
"name": "chillerlan/php-qrcode",
@ -2323,20 +2323,20 @@
},
{
"name": "ramsey/uuid",
"version": "4.7.6",
"version": "4.8.1",
"source": {
"type": "git",
"url": "https://github.com/ramsey/uuid.git",
"reference": "91039bc1faa45ba123c4328958e620d382ec7088"
"reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/91039bc1faa45ba123c4328958e620d382ec7088",
"reference": "91039bc1faa45ba123c4328958e620d382ec7088",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28",
"reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28",
"shasum": ""
},
"require": {
"brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12",
"brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13",
"ext-json": "*",
"php": "^8.0",
"ramsey/collection": "^1.2 || ^2.0"
@ -2345,26 +2345,23 @@
"rhumsaa/uuid": "self.version"
},
"require-dev": {
"captainhook/captainhook": "^5.10",
"captainhook/captainhook": "^5.25",
"captainhook/plugin-composer": "^5.3",
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
"doctrine/annotations": "^1.8",
"ergebnis/composer-normalize": "^2.15",
"mockery/mockery": "^1.3",
"dealerdirect/phpcodesniffer-composer-installer": "^1.0",
"ergebnis/composer-normalize": "^2.47",
"mockery/mockery": "^1.6",
"paragonie/random-lib": "^2",
"php-mock/php-mock": "^2.2",
"php-mock/php-mock-mockery": "^1.3",
"php-parallel-lint/php-parallel-lint": "^1.1",
"phpbench/phpbench": "^1.0",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.8",
"phpstan/phpstan-mockery": "^1.1",
"phpstan/phpstan-phpunit": "^1.1",
"phpunit/phpunit": "^8.5 || ^9",
"ramsey/composer-repl": "^1.4",
"slevomat/coding-standard": "^8.4",
"squizlabs/php_codesniffer": "^3.5",
"vimeo/psalm": "^4.9"
"php-mock/php-mock": "^2.6",
"php-mock/php-mock-mockery": "^1.5",
"php-parallel-lint/php-parallel-lint": "^1.4.0",
"phpbench/phpbench": "^1.2.14",
"phpstan/extension-installer": "^1.4",
"phpstan/phpstan": "^2.1",
"phpstan/phpstan-mockery": "^2.0",
"phpstan/phpstan-phpunit": "^2.0",
"phpunit/phpunit": "^9.6",
"slevomat/coding-standard": "^8.18",
"squizlabs/php_codesniffer": "^3.13"
},
"suggest": {
"ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.",
@ -2399,19 +2396,9 @@
],
"support": {
"issues": "https://github.com/ramsey/uuid/issues",
"source": "https://github.com/ramsey/uuid/tree/4.7.6"
"source": "https://github.com/ramsey/uuid/tree/4.8.1"
},
"funding": [
{
"url": "https://github.com/ramsey",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/ramsey/uuid",
"type": "tidelift"
}
],
"time": "2024-04-27T21:32:50+00:00"
"time": "2025-06-01T06:28:46+00:00"
},
{
"name": "spomky-labs/otphp",
@ -3798,16 +3785,16 @@
},
{
"name": "utopia-php/image",
"version": "0.8.3",
"version": "0.8.4",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/image.git",
"reference": "8820b0e53b3636b7bdf815e92394d333fef06f26"
"reference": "ce788ff0121a79286fdbe3ef3eba566de646df65"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/image/zipball/8820b0e53b3636b7bdf815e92394d333fef06f26",
"reference": "8820b0e53b3636b7bdf815e92394d333fef06f26",
"url": "https://api.github.com/repos/utopia-php/image/zipball/ce788ff0121a79286fdbe3ef3eba566de646df65",
"reference": "ce788ff0121a79286fdbe3ef3eba566de646df65",
"shasum": ""
},
"require": {
@ -3841,9 +3828,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/image/issues",
"source": "https://github.com/utopia-php/image/tree/0.8.3"
"source": "https://github.com/utopia-php/image/tree/0.8.4"
},
"time": "2025-05-15T10:39:28+00:00"
"time": "2025-06-03T08:32:20+00:00"
},
{
"name": "utopia-php/locale",
@ -4597,16 +4584,16 @@
},
{
"name": "utopia-php/vcs",
"version": "0.10.2",
"version": "0.10.4",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/vcs.git",
"reference": "1f9823ebcb8fd098607de0074f18f48e28985012"
"reference": "f635b368909eb3c3fe57344fe43525e74e8fdc03"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/1f9823ebcb8fd098607de0074f18f48e28985012",
"reference": "1f9823ebcb8fd098607de0074f18f48e28985012",
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/f635b368909eb3c3fe57344fe43525e74e8fdc03",
"reference": "f635b368909eb3c3fe57344fe43525e74e8fdc03",
"shasum": ""
},
"require": {
@ -4640,9 +4627,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/vcs/issues",
"source": "https://github.com/utopia-php/vcs/tree/0.10.2"
"source": "https://github.com/utopia-php/vcs/tree/0.10.4"
},
"time": "2025-04-17T04:35:25+00:00"
"time": "2025-06-02T09:18:36+00:00"
},
{
"name": "utopia-php/websocket",
@ -4820,16 +4807,16 @@
"packages-dev": [
{
"name": "appwrite/sdk-generator",
"version": "0.41.0",
"version": "0.41.1",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator.git",
"reference": "96316272a3cee1a3abf5b9f05ae49ebbff03725e"
"reference": "6d9318abf4542a757c87abf056557d6afa1dc06b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/96316272a3cee1a3abf5b9f05ae49ebbff03725e",
"reference": "96316272a3cee1a3abf5b9f05ae49ebbff03725e",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/6d9318abf4542a757c87abf056557d6afa1dc06b",
"reference": "6d9318abf4542a757c87abf056557d6afa1dc06b",
"shasum": ""
},
"require": {
@ -4865,9 +4852,9 @@
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
"support": {
"issues": "https://github.com/appwrite/sdk-generator/issues",
"source": "https://github.com/appwrite/sdk-generator/tree/0.41.0"
"source": "https://github.com/appwrite/sdk-generator/tree/0.41.1"
},
"time": "2025-05-26T09:47:45+00:00"
"time": "2025-06-01T04:20:04+00:00"
},
{
"name": "doctrine/annotations",
@ -5344,16 +5331,16 @@
},
{
"name": "nikic/php-parser",
"version": "v5.4.0",
"version": "v5.5.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "447a020a1f875a434d62f2a401f53b82a396e494"
"reference": "ae59794362fe85e051a58ad36b289443f57be7a9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494",
"reference": "447a020a1f875a434d62f2a401f53b82a396e494",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9",
"reference": "ae59794362fe85e051a58ad36b289443f57be7a9",
"shasum": ""
},
"require": {
@ -5396,9 +5383,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0"
"source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0"
},
"time": "2024-12-30T11:07:19+00:00"
"time": "2025-05-31T08:24:38+00:00"
},
{
"name": "phar-io/manifest",

View file

@ -213,7 +213,7 @@ services:
appwrite-console:
<<: *x-logging
container_name: appwrite-console
image: appwrite/console:6.0.13
image: appwrite/console:6.0.32
restart: unless-stopped
networks:
- appwrite

View file

@ -12,13 +12,13 @@ use Utopia\Database\Exception\Authorization;
use Utopia\Database\Exception\Structure;
use Utopia\Platform\Action;
use Utopia\Queue\Message;
use Utopia\Queue\Result\Commit;
use Utopia\Queue\Result\NoCommit;
use Utopia\System\System;
class Audits extends Action
{
protected const BATCH_SIZE_DEVELOPMENT = 1; // smaller batch size for development
protected const BATCH_SIZE_PRODUCTION = 5_000;
protected const BATCH_AGGREGATION_INTERVAL = 60; // in seconds
protected const int BATCH_AGGREGATION_INTERVAL = 60; // in seconds
private int $lastTriggeredTime = 0;
@ -27,9 +27,7 @@ class Audits extends Action
protected function getBatchSize(): int
{
return System::getEnv('_APP_ENV', 'development') === 'development'
? self::BATCH_SIZE_DEVELOPMENT
: self::BATCH_SIZE_PRODUCTION;
return intval(System::getEnv('_APP_QUEUE_PREFETCH_COUNT', 1));
}
public static function getName(): string
@ -57,13 +55,13 @@ class Audits extends Action
* @param Message $message
* @param callable $getProjectDB
* @param Document $project
* @return void
* @return Commit|NoCommit
* @throws Throwable
* @throws \Utopia\Database\Exception
* @throws Authorization
* @throws Structure
*/
public function action(Message $message, callable $getProjectDB, Document $project): void
public function action(Message $message, callable $getProjectDB, Document $project): Commit|NoCommit
{
$payload = $message->getPayload() ?? [];
@ -123,29 +121,32 @@ class Audits extends Action
// Check if we should process the batch by checking both for the batch size and the elapsed time
$batchSize = $this->getBatchSize();
$shouldProcessBatch = \count($this->logs) >= $batchSize;
if (!$shouldProcessBatch && \count($this->logs) > 0) {
$logCount = array_reduce($this->logs, fn (int $current, $logs) => $current + count($logs['logs']), 0);
$shouldProcessBatch = $logCount >= $batchSize;
if (!$shouldProcessBatch && $logCount > 0) {
$shouldProcessBatch = (\time() - $this->lastTriggeredTime) >= self::BATCH_AGGREGATION_INTERVAL;
}
if ($shouldProcessBatch) {
try {
foreach ($this->logs as $internalId => $projectLogs) {
$dbForProject = $getProjectDB($projectLogs['project']);
Console::log('Processing batch with ' . count($projectLogs['logs']) . ' events');
$audit = new Audit($dbForProject);
$audit->logBatch($projectLogs['logs']);
Console::success('Audit logs processed successfully');
unset($this->logs[$internalId]);
}
} catch (Throwable $e) {
Console::error('Error processing audit logs: ' . $e->getMessage());
} finally {
$this->lastTriggeredTime = time();
}
if (!$shouldProcessBatch) {
return new NoCommit();
}
try {
foreach ($this->logs as $internalId => $projectLogs) {
$dbForProject = $getProjectDB($projectLogs['project']);
Console::log('Processing batch with ' . count($projectLogs['logs']) . ' events');
$audit = new Audit($dbForProject);
$audit->logBatch($projectLogs['logs']);
Console::success('Audit logs processed successfully');
unset($this->logs[$internalId]);
}
} catch (Throwable $e) {
Console::error('Error processing audit logs: ' . $e->getMessage());
}
$this->lastTriggeredTime = time();
return new Commit();
}
}

View file

@ -87,7 +87,7 @@ class Comment
$i = 0;
foreach ($projects as $projectId => $project) {
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https';
$hostname = System::getEnv('_APP_DOMAIN');
$hostname = System::getEnv('_APP_CONSOLE_DOMAIN', System::getEnv('_APP_DOMAIN'));
$text .= "## {$project['name']}\n\n";
$text .= "Project ID: `{$projectId}`\n\n";
@ -103,10 +103,12 @@ class Comment
$text .= "| :- | :- | :- | :- | :- |\n";
foreach ($project['site'] as $siteId => $site) {
$imageStatus = in_array($site['status'], ['processing', 'building']) ? 'building' : $site['status'];
$extension = $site['status'] === 'building' ? 'gif' : 'png';
$pathLight = '/images/vcs/status-' . $site['status'] . '-light.' . $extension;
$pathDark = '/images/vcs/status-' . $site['status'] . '-dark.' . $extension;
$pathLight = '/images/vcs/status-' . $imageStatus . '-light.' . $extension;
$pathDark = '/images/vcs/status-' . $imageStatus . '-dark.' . $extension;
$status = match ($site['status']) {
'waiting' => $this->generatImage($pathLight, $pathDark, 'Queued', 85) . ' _Queued_',
@ -149,10 +151,11 @@ class Comment
$text .= "| :- | :- | :- | :- |\n";
foreach ($project['function'] as $functionId => $function) {
$extension = $function['status'] === 'building' ? 'gif' : 'png';
$imageStatus = in_array($function['status'], ['processing', 'building']) ? 'building' : $function['status'];
$extension = $imageStatus === 'building' ? 'gif' : 'png';
$pathLight = '/images/vcs/status-' . $function['status'] . '-light.' . $extension;
$pathDark = '/images/vcs/status-' . $function['status'] . '-dark.' . $extension;
$pathLight = '/images/vcs/status-' . $imageStatus . '-light.' . $extension;
$pathDark = '/images/vcs/status-' . $imageStatus . '-dark.' . $extension;
$status = match ($function['status']) {
'waiting' => $this->generatImage($pathLight, $pathDark, 'Queued', 85) . ' _Queued_',
@ -168,7 +171,8 @@ class Comment
$action = '[Authorize](' . $function['action']['url'] . ')';
}
$text .= "| &nbsp;**{$function['name']}**<br>`$functionId`";
$text .= "| &nbsp;**{$function['name']}**";
$text .= "| `{$functionId}`";
$text .= "| {$status}";
$text .= "| {$action}";
$text .= "|\n";
@ -197,7 +201,7 @@ class Comment
public function generatImage(string $pathLight, string $pathDark, string $alt, int $width): string
{
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https';
$hostname = System::getEnv('_APP_DOMAIN');
$hostname = System::getEnv('_APP_CONSOLE_DOMAIN', System::getEnv('_APP_DOMAIN'));
$imageLight = $protocol . '://' . $hostname . $pathLight;
$imageDark = $protocol . '://' . $hostname . $pathDark;

View file

@ -3,7 +3,6 @@
namespace Tests\E2E\General;
use Appwrite\Platform\Modules\Compute\Specification;
use Appwrite\Tests\Retry;
use CURLFile;
use DateTime;
use Tests\E2E\Client;
@ -183,40 +182,43 @@ class UsageTest extends Scope
/**
* @depends testPrepareUsersStats
*/
#[Retry(count: 1)]
public function testUsersStats(array $data): array
{
$requestsTotal = $data['requestsTotal'];
$response = $this->client->call(
Client::METHOD_GET,
'/project/usage',
$this->getConsoleHeaders(),
[
'period' => '1h',
'startDate' => self::getToday(),
'endDate' => self::getTomorrow(),
]
);
$this->assertEventually(function () {
$response = $this->client->call(
Client::METHOD_GET,
'/project/usage',
$this->getConsoleHeaders(),
[
'period' => '1h',
'startDate' => self::getToday(),
'endDate' => self::getTomorrow(),
]
);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertGreaterThanOrEqual(31, count($response['body']));
$this->validateDates($response['body']['network']);
$this->validateDates($response['body']['requests']);
$this->validateDates($response['body']['users']);
$this->assertArrayHasKey('executionsBreakdown', $response['body']);
$this->assertArrayHasKey('bucketsBreakdown', $response['body']);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertGreaterThanOrEqual(31, count($response['body']));
$this->validateDates($response['body']['network']);
$this->validateDates($response['body']['requests']);
$this->validateDates($response['body']['users']);
$this->assertArrayHasKey('executionsBreakdown', $response['body']);
$this->assertArrayHasKey('bucketsBreakdown', $response['body']);
});
$response = $this->client->call(
Client::METHOD_GET,
'/users/usage?range=90d',
$this->getConsoleHeaders()
);
$this->assertEventually(function () {
$response = $this->client->call(
Client::METHOD_GET,
'/users/usage?range=90d',
$this->getConsoleHeaders()
);
$this->assertEquals('90d', $response['body']['range']);
$this->assertEquals(90, count($response['body']['users']));
$this->assertEquals(90, count($response['body']['sessions']));
$this->assertEquals((self::CREATE / 2), $response['body']['users'][array_key_last($response['body']['users'])]['value']);
$this->assertEquals('90d', $response['body']['range']);
$this->assertEquals(90, count($response['body']['users']));
$this->assertEquals(90, count($response['body']['sessions']));
$this->assertEquals((self::CREATE / 2), $response['body']['users'][array_key_last($response['body']['users'])]['value']);
});
return array_merge($data, [
'requestsTotal' => $requestsTotal
@ -359,7 +361,6 @@ class UsageTest extends Scope
/**
* @depends testPrepareStorageStats
*/
#[Retry(count: 10)]
public function testStorageStats(array $data): array
{
$bucketId = $data['bucketId'];
@ -368,44 +369,50 @@ class UsageTest extends Scope
$storageTotal = $data['storageTotal'];
$filesTotal = $data['filesTotal'];
$response = $this->client->call(
Client::METHOD_GET,
'/project/usage',
$this->getConsoleHeaders(),
[
'period' => '1d',
'startDate' => self::getToday(),
'endDate' => self::getTomorrow(),
]
);
$this->assertEventually(function () use ($requestsTotal, $storageTotal) {
$response = $this->client->call(
Client::METHOD_GET,
'/project/usage',
$this->getConsoleHeaders(),
[
'period' => '1d',
'startDate' => self::getToday(),
'endDate' => self::getTomorrow(),
]
);
$this->assertGreaterThanOrEqual(31, count($response['body']));
$this->assertEquals(1, count($response['body']['requests']));
$this->assertEquals($requestsTotal, $response['body']['requests'][array_key_last($response['body']['requests'])]['value']);
$this->validateDates($response['body']['requests']);
$this->assertEquals($storageTotal, $response['body']['filesStorageTotal']);
$this->assertGreaterThanOrEqual(31, count($response['body']));
$this->assertEquals(1, count($response['body']['requests']));
$this->assertEquals($requestsTotal, $response['body']['requests'][array_key_last($response['body']['requests'])]['value']);
$this->validateDates($response['body']['requests']);
$this->assertEquals($storageTotal, $response['body']['filesStorageTotal']);
});
$response = $this->client->call(
Client::METHOD_GET,
'/storage/usage?range=30d',
$this->getConsoleHeaders()
);
$this->assertEventually(function () use ($bucketsTotal, $filesTotal, $storageTotal) {
$response = $this->client->call(
Client::METHOD_GET,
'/storage/usage?range=30d',
$this->getConsoleHeaders()
);
$this->assertEquals($storageTotal, $response['body']['storage'][array_key_last($response['body']['storage'])]['value']);
$this->validateDates($response['body']['storage']);
$this->assertEquals($bucketsTotal, $response['body']['buckets'][array_key_last($response['body']['buckets'])]['value']);
$this->validateDates($response['body']['buckets']);
$this->assertEquals($filesTotal, $response['body']['files'][array_key_last($response['body']['files'])]['value']);
$this->validateDates($response['body']['files']);
$this->assertEquals($storageTotal, $response['body']['storage'][array_key_last($response['body']['storage'])]['value']);
$this->validateDates($response['body']['storage']);
$this->assertEquals($bucketsTotal, $response['body']['buckets'][array_key_last($response['body']['buckets'])]['value']);
$this->validateDates($response['body']['buckets']);
$this->assertEquals($filesTotal, $response['body']['files'][array_key_last($response['body']['files'])]['value']);
$this->validateDates($response['body']['files']);
});
$response = $this->client->call(
Client::METHOD_GET,
'/storage/' . $bucketId . '/usage?range=30d',
$this->getConsoleHeaders()
);
$this->assertEventually(function () use ($bucketId, $storageTotal, $filesTotal) {
$response = $this->client->call(
Client::METHOD_GET,
'/storage/' . $bucketId . '/usage?range=30d',
$this->getConsoleHeaders()
);
$this->assertEquals($storageTotal, $response['body']['storage'][array_key_last($response['body']['storage'])]['value']);
$this->assertEquals($filesTotal, $response['body']['files'][array_key_last($response['body']['files'])]['value']);
$this->assertEquals($storageTotal, $response['body']['storage'][array_key_last($response['body']['storage'])]['value']);
$this->assertEquals($filesTotal, $response['body']['files'][array_key_last($response['body']['files'])]['value']);
});
return $data;
}
@ -577,7 +584,7 @@ class UsageTest extends Scope
}
/** @depends testPrepareDatabaseStats */
#[Retry(count: 1)]
public function testDatabaseStats(array $data): array
{
$databaseId = $data['databaseId'];
@ -587,60 +594,66 @@ class UsageTest extends Scope
$collectionsTotal = $data['collectionsTotal'];
$documentsTotal = $data['documentsTotal'];
sleep(self::WAIT);
$this->assertEventually(function () use ($requestsTotal, $databasesTotal, $documentsTotal) {
$response = $this->client->call(
Client::METHOD_GET,
'/project/usage',
$this->getConsoleHeaders(),
[
'period' => '1d',
'startDate' => self::getToday(),
'endDate' => self::getTomorrow(),
]
);
$response = $this->client->call(
Client::METHOD_GET,
'/project/usage',
$this->getConsoleHeaders(),
[
'period' => '1d',
'startDate' => self::getToday(),
'endDate' => self::getTomorrow(),
]
);
$this->assertGreaterThanOrEqual(31, count($response['body']));
$this->assertEquals(1, count($response['body']['requests']));
$this->assertEquals(1, count($response['body']['network']));
$this->assertEquals($requestsTotal, $response['body']['requests'][array_key_last($response['body']['requests'])]['value']);
$this->validateDates($response['body']['requests']);
$this->assertEquals($databasesTotal, $response['body']['databasesTotal']);
$this->assertEquals($documentsTotal, $response['body']['documentsTotal']);
});
$this->assertGreaterThanOrEqual(31, count($response['body']));
$this->assertEquals(1, count($response['body']['requests']));
$this->assertEquals(1, count($response['body']['network']));
$this->assertEquals($requestsTotal, $response['body']['requests'][array_key_last($response['body']['requests'])]['value']);
$this->validateDates($response['body']['requests']);
$this->assertEquals($databasesTotal, $response['body']['databasesTotal']);
$this->assertEquals($documentsTotal, $response['body']['documentsTotal']);
$this->assertEventually(function () use ($collectionsTotal, $databasesTotal, $documentsTotal) {
$response = $this->client->call(
Client::METHOD_GET,
'/databases/usage?range=30d',
$this->getConsoleHeaders()
);
$response = $this->client->call(
Client::METHOD_GET,
'/databases/usage?range=30d',
$this->getConsoleHeaders()
);
$this->assertEquals($databasesTotal, $response['body']['databases'][array_key_last($response['body']['databases'])]['value']);
$this->validateDates($response['body']['databases']);
$this->assertEquals($collectionsTotal, $response['body']['collections'][array_key_last($response['body']['collections'])]['value']);
$this->validateDates($response['body']['collections']);
$this->assertEquals($documentsTotal, $response['body']['documents'][array_key_last($response['body']['documents'])]['value']);
$this->validateDates($response['body']['documents']);
});
$this->assertEquals($databasesTotal, $response['body']['databases'][array_key_last($response['body']['databases'])]['value']);
$this->validateDates($response['body']['databases']);
$this->assertEquals($collectionsTotal, $response['body']['collections'][array_key_last($response['body']['collections'])]['value']);
$this->validateDates($response['body']['collections']);
$this->assertEquals($documentsTotal, $response['body']['documents'][array_key_last($response['body']['documents'])]['value']);
$this->validateDates($response['body']['documents']);
$this->assertEventually(function () use ($databaseId, $collectionsTotal, $documentsTotal) {
$response = $this->client->call(
Client::METHOD_GET,
'/databases/' . $databaseId . '/usage?range=30d',
$this->getConsoleHeaders()
);
$response = $this->client->call(
Client::METHOD_GET,
'/databases/' . $databaseId . '/usage?range=30d',
$this->getConsoleHeaders()
);
$this->assertEquals($collectionsTotal, $response['body']['collections'][array_key_last($response['body']['collections'])]['value']);
$this->validateDates($response['body']['collections']);
$this->assertEquals($collectionsTotal, $response['body']['collections'][array_key_last($response['body']['collections'])]['value']);
$this->validateDates($response['body']['collections']);
$this->assertEquals($documentsTotal, $response['body']['documents'][array_key_last($response['body']['documents'])]['value']);
$this->validateDates($response['body']['documents']);
});
$this->assertEquals($documentsTotal, $response['body']['documents'][array_key_last($response['body']['documents'])]['value']);
$this->validateDates($response['body']['documents']);
$this->assertEventually(function () use ($databaseId, $collectionId, $documentsTotal) {
$response = $this->client->call(
Client::METHOD_GET,
'/databases/' . $databaseId . '/collections/' . $collectionId . '/usage?range=30d',
$this->getConsoleHeaders()
);
$response = $this->client->call(
Client::METHOD_GET,
'/databases/' . $databaseId . '/collections/' . $collectionId . '/usage?range=30d',
$this->getConsoleHeaders()
);
$this->assertEquals($documentsTotal, $response['body']['documents'][array_key_last($response['body']['documents'])]['value']);
$this->validateDates($response['body']['documents']);
$this->assertEquals($documentsTotal, $response['body']['documents'][array_key_last($response['body']['documents'])]['value']);
$this->validateDates($response['body']['documents']);
});
return $data;
}
@ -799,67 +812,69 @@ class UsageTest extends Scope
}
/** @depends testPrepareFunctionsStats */
#[Retry(count: 1)]
public function testFunctionsStats(array $data): array
{
$functionId = $data['functionId'];
$executionTime = $data['executionTime'];
$executions = $data['executions'];
$response = $this->client->call(
Client::METHOD_GET,
'/functions/' . $functionId . '/usage?range=30d',
$this->getConsoleHeaders()
);
$this->assertEventually(function () use ($functionId, $executions, $executionTime) {
$response = $this->client->call(
Client::METHOD_GET,
'/functions/' . $functionId . '/usage?range=30d',
$this->getConsoleHeaders()
);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(24, count($response['body']));
$this->assertEquals('30d', $response['body']['range']);
$this->assertIsArray($response['body']['deployments']);
$this->assertIsArray($response['body']['deploymentsStorage']);
$this->assertIsNumeric($response['body']['deploymentsStorageTotal']);
$this->assertIsNumeric($response['body']['buildsMbSecondsTotal']);
$this->assertIsNumeric($response['body']['executionsMbSecondsTotal']);
$this->assertIsArray($response['body']['builds']);
$this->assertIsArray($response['body']['buildsTime']);
$this->assertIsArray($response['body']['buildsMbSeconds']);
$this->assertIsArray($response['body']['executions']);
$this->assertIsArray($response['body']['executionsTime']);
$this->assertIsArray($response['body']['executionsMbSeconds']);
$this->assertEquals($executions, $response['body']['executions'][array_key_last($response['body']['executions'])]['value']);
$this->validateDates($response['body']['executions']);
$this->assertEquals($executionTime, $response['body']['executionsTime'][array_key_last($response['body']['executionsTime'])]['value']);
$this->validateDates($response['body']['executionsTime']);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(24, count($response['body']));
$this->assertEquals('30d', $response['body']['range']);
$this->assertIsArray($response['body']['deployments']);
$this->assertIsArray($response['body']['deploymentsStorage']);
$this->assertIsNumeric($response['body']['deploymentsStorageTotal']);
$this->assertIsNumeric($response['body']['buildsMbSecondsTotal']);
$this->assertIsNumeric($response['body']['executionsMbSecondsTotal']);
$this->assertIsArray($response['body']['builds']);
$this->assertIsArray($response['body']['buildsTime']);
$this->assertIsArray($response['body']['buildsMbSeconds']);
$this->assertIsArray($response['body']['executions']);
$this->assertIsArray($response['body']['executionsTime']);
$this->assertIsArray($response['body']['executionsMbSeconds']);
$this->assertEquals($executions, $response['body']['executions'][array_key_last($response['body']['executions'])]['value']);
$this->validateDates($response['body']['executions']);
$this->assertEquals($executionTime, $response['body']['executionsTime'][array_key_last($response['body']['executionsTime'])]['value']);
$this->validateDates($response['body']['executionsTime']);
});
$response = $this->client->call(
Client::METHOD_GET,
'/functions/usage?range=30d',
$this->getConsoleHeaders()
);
$this->assertEventually(function () use ($executions, $executionTime) {
$response = $this->client->call(
Client::METHOD_GET,
'/functions/usage?range=30d',
$this->getConsoleHeaders()
);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(25, count($response['body']));
$this->assertEquals($response['body']['range'], '30d');
$this->assertIsArray($response['body']['functions']);
$this->assertIsArray($response['body']['deployments']);
$this->assertIsArray($response['body']['deploymentsStorage']);
$this->assertIsArray($response['body']['builds']);
$this->assertIsArray($response['body']['buildsTime']);
$this->assertIsArray($response['body']['buildsMbSeconds']);
$this->assertIsArray($response['body']['executions']);
$this->assertIsArray($response['body']['executionsTime']);
$this->assertIsArray($response['body']['executionsMbSeconds']);
$this->assertEquals($executions, $response['body']['executions'][array_key_last($response['body']['executions'])]['value']);
$this->validateDates($response['body']['executions']);
$this->assertEquals($executionTime, $response['body']['executionsTime'][array_key_last($response['body']['executionsTime'])]['value']);
$this->validateDates($response['body']['executionsTime']);
$this->assertGreaterThan(0, $response['body']['buildsTime'][array_key_last($response['body']['buildsTime'])]['value']);
$this->validateDates($response['body']['buildsTime']);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(25, count($response['body']));
$this->assertEquals($response['body']['range'], '30d');
$this->assertIsArray($response['body']['functions']);
$this->assertIsArray($response['body']['deployments']);
$this->assertIsArray($response['body']['deploymentsStorage']);
$this->assertIsArray($response['body']['builds']);
$this->assertIsArray($response['body']['buildsTime']);
$this->assertIsArray($response['body']['buildsMbSeconds']);
$this->assertIsArray($response['body']['executions']);
$this->assertIsArray($response['body']['executionsTime']);
$this->assertIsArray($response['body']['executionsMbSeconds']);
$this->assertEquals($executions, $response['body']['executions'][array_key_last($response['body']['executions'])]['value']);
$this->validateDates($response['body']['executions']);
$this->assertEquals($executionTime, $response['body']['executionsTime'][array_key_last($response['body']['executionsTime'])]['value']);
$this->validateDates($response['body']['executionsTime']);
$this->assertGreaterThan(0, $response['body']['buildsTime'][array_key_last($response['body']['buildsTime'])]['value']);
$this->validateDates($response['body']['buildsTime']);
});
return $data;
}
public function testPrepareSitesStats(): array
{
$siteId = $this->setupSite([
@ -927,7 +942,6 @@ class UsageTest extends Scope
}
/** @depends testPrepareSitesStats */
#[Retry(count: 1)]
public function testSitesStats(array $data)
{
$siteId = $data['siteId'];
@ -935,67 +949,72 @@ class UsageTest extends Scope
$executions = $data['executions'] ?? 0;
$deploymentsSuccess = $data['deploymentsSuccess'];
$deploymentsFailed = $data['deploymentsFailed'];
$response = $this->client->call(
Client::METHOD_GET,
'/sites/' . $siteId . '/usage?range=30d',
$this->getConsoleHeaders()
);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(30, count($response['body']));
$this->assertEquals('30d', $response['body']['range']);
$this->assertIsArray($response['body']['deployments']);
$this->assertEquals($deploymentsSuccess, $response['body']['buildsSuccessTotal']);
$this->assertEquals($deploymentsFailed, $response['body']['buildsFailedTotal']);
$this->assertIsArray($response['body']['deploymentsStorage']);
$this->assertIsNumeric($response['body']['deploymentsStorageTotal']);
$this->assertIsNumeric($response['body']['buildsMbSecondsTotal']);
$this->assertIsNumeric($response['body']['executionsMbSecondsTotal']);
$this->assertIsArray($response['body']['builds']);
$this->assertIsArray($response['body']['buildsTime']);
$this->assertIsArray($response['body']['buildsMbSeconds']);
$this->assertIsArray($response['body']['executions']);
$this->assertIsArray($response['body']['executionsTime']);
$this->assertIsArray($response['body']['executionsMbSeconds']);
$this->assertIsArray($response['body']['buildsSuccess']);
$this->assertIsArray($response['body']['buildsFailed']);
$this->assertIsArray($response['body']['requests']);
$this->assertIsArray($response['body']['inbound']);
$this->assertIsArray($response['body']['outbound']);
$this->assertEquals($executions, $response['body']['executions'][array_key_last($response['body']['executions'])]['value']);
$this->validateDates($response['body']['executions']);
$this->assertEquals($executionTime, $response['body']['executionsTime'][array_key_last($response['body']['executionsTime'])]['value']);
$this->validateDates($response['body']['executionsTime']);
$this->assertEventually(function () use ($siteId, $deploymentsSuccess, $deploymentsFailed, $executions, $executionTime) {
$response = $this->client->call(
Client::METHOD_GET,
'/sites/' . $siteId . '/usage?range=30d',
$this->getConsoleHeaders()
);
$response = $this->client->call(
Client::METHOD_GET,
'/sites/usage?range=30d',
$this->getConsoleHeaders()
);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(30, count($response['body']));
$this->assertEquals('30d', $response['body']['range']);
$this->assertIsArray($response['body']['deployments']);
$this->assertEquals($deploymentsSuccess, $response['body']['buildsSuccessTotal']);
$this->assertEquals($deploymentsFailed, $response['body']['buildsFailedTotal']);
$this->assertIsArray($response['body']['deploymentsStorage']);
$this->assertIsNumeric($response['body']['deploymentsStorageTotal']);
$this->assertIsNumeric($response['body']['buildsMbSecondsTotal']);
$this->assertIsNumeric($response['body']['executionsMbSecondsTotal']);
$this->assertIsArray($response['body']['builds']);
$this->assertIsArray($response['body']['buildsTime']);
$this->assertIsArray($response['body']['buildsMbSeconds']);
$this->assertIsArray($response['body']['executions']);
$this->assertIsArray($response['body']['executionsTime']);
$this->assertIsArray($response['body']['executionsMbSeconds']);
$this->assertIsArray($response['body']['buildsSuccess']);
$this->assertIsArray($response['body']['buildsFailed']);
$this->assertIsArray($response['body']['requests']);
$this->assertIsArray($response['body']['inbound']);
$this->assertIsArray($response['body']['outbound']);
$this->assertEquals($executions, $response['body']['executions'][array_key_last($response['body']['executions'])]['value']);
$this->validateDates($response['body']['executions']);
$this->assertEquals($executionTime, $response['body']['executionsTime'][array_key_last($response['body']['executionsTime'])]['value']);
$this->validateDates($response['body']['executionsTime']);
});
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(31, count($response['body']));
$this->assertEquals($response['body']['range'], '30d');
$this->assertIsArray($response['body']['sites']);
$this->assertIsArray($response['body']['deployments']);
$this->assertIsArray($response['body']['deploymentsStorage']);
$this->assertIsArray($response['body']['builds']);
$this->assertIsArray($response['body']['buildsTime']);
$this->assertIsArray($response['body']['buildsMbSeconds']);
$this->assertIsArray($response['body']['executions']);
$this->assertIsArray($response['body']['executionsTime']);
$this->assertIsArray($response['body']['executionsMbSeconds']);
$this->assertIsArray($response['body']['buildsSuccess']);
$this->assertIsArray($response['body']['buildsFailed']);
$this->assertIsArray($response['body']['requests']);
$this->assertIsArray($response['body']['inbound']);
$this->assertIsArray($response['body']['outbound']);
$this->assertEquals($executions, $response['body']['executions'][array_key_last($response['body']['executions'])]['value']);
$this->validateDates($response['body']['executions']);
$this->assertEquals($executionTime, $response['body']['executionsTime'][array_key_last($response['body']['executionsTime'])]['value']);
$this->validateDates($response['body']['executionsTime']);
$this->assertGreaterThan(0, $response['body']['buildsTime'][array_key_last($response['body']['buildsTime'])]['value']);
$this->validateDates($response['body']['buildsTime']);
$this->assertEventually(function () use ($executions, $executionTime) {
$response = $this->client->call(
Client::METHOD_GET,
'/sites/usage?range=30d',
$this->getConsoleHeaders()
);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(31, count($response['body']));
$this->assertEquals($response['body']['range'], '30d');
$this->assertIsArray($response['body']['sites']);
$this->assertIsArray($response['body']['deployments']);
$this->assertIsArray($response['body']['deploymentsStorage']);
$this->assertIsArray($response['body']['builds']);
$this->assertIsArray($response['body']['buildsTime']);
$this->assertIsArray($response['body']['buildsMbSeconds']);
$this->assertIsArray($response['body']['executions']);
$this->assertIsArray($response['body']['executionsTime']);
$this->assertIsArray($response['body']['executionsMbSeconds']);
$this->assertIsArray($response['body']['buildsSuccess']);
$this->assertIsArray($response['body']['buildsFailed']);
$this->assertIsArray($response['body']['requests']);
$this->assertIsArray($response['body']['inbound']);
$this->assertIsArray($response['body']['outbound']);
$this->assertEquals($executions, $response['body']['executions'][array_key_last($response['body']['executions'])]['value']);
$this->validateDates($response['body']['executions']);
$this->assertEquals($executionTime, $response['body']['executionsTime'][array_key_last($response['body']['executionsTime'])]['value']);
$this->validateDates($response['body']['executionsTime']);
$this->assertGreaterThan(0, $response['body']['buildsTime'][array_key_last($response['body']['buildsTime'])]['value']);
$this->validateDates($response['body']['buildsTime']);
});
}
/** @depends testFunctionsStats */
@ -1032,30 +1051,33 @@ class UsageTest extends Scope
$domain = $rule['body']['domain'];
$response = $this->client->call(
Client::METHOD_GET,
'/functions/' . $functionId . '/usage?range=30d',
$this->getConsoleHeaders()
);
$this->assertEventually(function () use (&$response, $functionId) {
$response = $this->client->call(
Client::METHOD_GET,
'/functions/' . $functionId . '/usage?range=30d',
$this->getConsoleHeaders()
);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(24, count($response['body']));
$this->assertEquals('30d', $response['body']['range']);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(24, count($response['body']));
$this->assertEquals('30d', $response['body']['range']);
});
$functionsMetrics = $response['body'];
$response = $this->client->call(
Client::METHOD_GET,
'/project/usage',
$this->getConsoleHeaders(),
[
'period' => '1h',
'startDate' => self::getToday(),
'endDate' => self::getTomorrow(),
]
);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEventually(function () use (&$response) {
$response = $this->client->call(
Client::METHOD_GET,
'/project/usage',
$this->getConsoleHeaders(),
[
'period' => '1h',
'startDate' => self::getToday(),
'endDate' => self::getTomorrow(),
]
);
$this->assertEquals(200, $response['headers']['status-code']);
});
$projectMetrics = $response['body'];
@ -1070,8 +1092,6 @@ class UsageTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
$tries = 0;
$this->assertEventually(function () use ($functionId, $functionsMetrics, $projectMetrics) {
// Compare new values with old values
$response = $this->client->call(

View file

@ -2,6 +2,7 @@
namespace Tests\E2E\Scopes;
use Appwrite\Tests\Async;
use Appwrite\Tests\Retryable;
use PHPUnit\Framework\TestCase;
use Tests\E2E\Client;
@ -10,6 +11,7 @@ use Utopia\Database\Helpers\ID;
abstract class Scope extends TestCase
{
use Retryable;
use Async;
protected ?Client $client = null;
protected string $endpoint = 'http://localhost/v1';
@ -43,6 +45,18 @@ abstract class Scope extends TestCase
return [];
}
protected function assertLastRequest(callable $probe, $timeoutMs = 20_000, $waitMs = 500): array
{
$this->assertEventually(function () use (&$request, $probe) {
$request = json_decode(file_get_contents('http://request-catcher:5000/__last_request__'), true);
$request['data'] = json_decode($request['data'], true);
call_user_func($probe, $request);
}, $timeoutMs, $waitMs);
return $request;
}
protected function getLastRequest(): array
{
sleep(2);

View file

@ -2034,7 +2034,6 @@ class AccountCustomClientTest extends Scope
$this->assertEquals($response['body']['users'][0]['email'], $email);
}
#[Retry(count: 2)]
public function testCreatePhone(): array
{
$number = '+123456789';
@ -2058,17 +2057,15 @@ class AccountCustomClientTest extends Scope
$userId = $response['body']['userId'];
\sleep(7);
$smsRequest = $this->getLastRequest();
$this->assertEquals('http://request-catcher:5000/mock-sms', $smsRequest['url']);
$this->assertEquals('Appwrite Mock Message Sender', $smsRequest['headers']['User-Agent']);
$this->assertEquals('username', $smsRequest['headers']['X-Username']);
$this->assertEquals('password', $smsRequest['headers']['X-Key']);
$this->assertEquals('POST', $smsRequest['method']);
$this->assertEquals('+123456789', $smsRequest['data']['from']);
$this->assertEquals($number, $smsRequest['data']['to']);
$smsRequest = $this->assertLastRequest(function (array $request) use ($number) {
$this->assertEquals('http://request-catcher:5000/mock-sms', $request['url']);
$this->assertEquals('Appwrite Mock Message Sender', $request['headers']['User-Agent']);
$this->assertEquals('username', $request['headers']['X-Username']);
$this->assertEquals('password', $request['headers']['X-Key']);
$this->assertEquals('POST', $request['method']);
$this->assertEquals('+123456789', $request['data']['from']);
$this->assertEquals($number, $request['data']['to']);
});
$data['token'] = $smsRequest['data']['message'];
$data['id'] = $userId;
@ -2396,7 +2393,6 @@ class AccountCustomClientTest extends Scope
/**
* @depends testUpdatePhone
*/
#[Retry(count: 3)]
public function testPhoneVerification(array $data): array
{
$session = $data['session'] ?? '';
@ -2416,10 +2412,10 @@ class AccountCustomClientTest extends Scope
$this->assertEmpty($response['body']['secret']);
$this->assertTrue((new DatetimeValidator())->isValid($response['body']['expire']));
$smsRequest = $this->getLastRequest();
$message = $smsRequest['data']['message'];
$token = substr($message, 0, 6);
$smsRequest = $this->assertLastRequest(function ($request) {
$this->assertArrayHasKey('data', $request);
$this->assertArrayHasKey('message', $request['data']);
});
/**
* Test for FAILURE

View file

@ -49,7 +49,7 @@ trait FunctionsBase
'x-appwrite-key' => $this->getProject()['apiKey'],
]));
$this->assertEquals('ready', $deployment['body']['status'], 'Deployment status is not ready, deployment: ' . json_encode($deployment['body'], JSON_PRETTY_PRINT));
}, 50000, 500);
}, 100000, 500);
// Not === so multipart/form-data works fine too
if (($params['activate'] ?? false) == true) {

View file

@ -206,15 +206,17 @@ class MessagingConsoleClientTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
$logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
$this->assertEventually(function () use ($topic) {
$logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
$this->assertEquals($logs['headers']['status-code'], 200);
$this->assertIsArray($logs['body']['logs']);
$this->assertCount(2, $logs['body']['logs']);
$this->assertIsNumeric($logs['body']['total']);
$this->assertEquals($logs['headers']['status-code'], 200);
$this->assertIsArray($logs['body']['logs']);
$this->assertCount(2, $logs['body']['logs']);
$this->assertIsNumeric($logs['body']['total']);
});
$logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([
'content-type' => 'application/json',

View file

@ -871,7 +871,7 @@ trait MigrationsBase
$this->assertEquals(1, $deployments['body']['total']);
$this->assertEquals('ready', $deployments['body']['deployments'][0]['status'], 'Deployment status is not ready, deployment: ' . json_encode($deployments['body']['deployments'][0], JSON_PRETTY_PRINT));
}, 50000, 500);
}, 100000, 500);
// Attempt execution
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', [

View file

@ -265,7 +265,7 @@ trait SitesBase
$this->assertEventually(function () use ($siteId, $deploymentId) {
$deployment = $this->getDeployment($siteId, $deploymentId);
$this->assertEquals('ready', $deployment['body']['status'], 'Deployment status is not ready, deployment: ' . json_encode($deployment['body'], JSON_PRETTY_PRINT));
}, 100000, 500);
}, 150000, 500);
$this->assertEventually(function () use ($siteId, $deploymentId) {
$site = $this->getSite($siteId);