From 1d983a949e0e616a12a810a28b2d9b661d75c05b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Fri, 7 Mar 2025 22:36:13 +0100 Subject: [PATCH 1/2] Merge site & function specs --- app/config/runtimes/specifications.php | 51 -------- .../{frameworks => }/specifications.php | 0 app/controllers/general.php | 2 +- app/init.php | 3 +- src/Appwrite/Functions/Specification.php | 16 --- .../Modules/Compute}/Specification.php | 2 +- .../Compute/Validator/Specification.php} | 8 +- .../Functions/Http/Executions/Create.php | 2 +- .../Functions/Http/Functions/Create.php | 6 +- .../Functions/Http/Functions/Update.php | 8 +- .../Functions/Http/Specifications/XList.php | 20 ++-- .../Modules/Functions/Workers/Builds.php | 2 +- .../Modules/Sites/Http/Sites/Create.php | 6 +- .../Modules/Sites/Http/Sites/Update.php | 8 +- .../Sites/Http/Specifications/XList.php | 76 ++++++++++++ src/Appwrite/Platform/Workers/Functions.php | 2 +- .../Validator/FrameworkSpecification.php | 112 ------------------ 17 files changed, 108 insertions(+), 216 deletions(-) delete mode 100644 app/config/runtimes/specifications.php rename app/config/{frameworks => }/specifications.php (100%) delete mode 100644 src/Appwrite/Functions/Specification.php rename src/Appwrite/{Sites => Platform/Modules/Compute}/Specification.php (94%) rename src/Appwrite/{Functions/Validator/RuntimeSpecification.php => Platform/Modules/Compute/Validator/Specification.php} (88%) create mode 100644 src/Appwrite/Platform/Modules/Sites/Http/Specifications/XList.php delete mode 100644 src/Appwrite/Sites/Validator/FrameworkSpecification.php diff --git a/app/config/runtimes/specifications.php b/app/config/runtimes/specifications.php deleted file mode 100644 index d3625db8a2..0000000000 --- a/app/config/runtimes/specifications.php +++ /dev/null @@ -1,51 +0,0 @@ - [ - 'slug' => Specification::S_05VCPU_512MB, - 'memory' => 512, - 'cpus' => 0.5 - ], - Specification::S_1VCPU_512MB => [ - 'slug' => Specification::S_1VCPU_512MB, - 'memory' => 512, - 'cpus' => 1 - ], - Specification::S_1VCPU_1GB => [ - 'slug' => Specification::S_1VCPU_1GB, - 'memory' => 1024, - 'cpus' => 1 - ], - Specification::S_2VCPU_2GB => [ - 'slug' => Specification::S_2VCPU_2GB, - 'memory' => 2048, - 'cpus' => 2 - ], - Specification::S_2VCPU_4GB => [ - 'slug' => Specification::S_2VCPU_4GB, - 'memory' => 4096, - 'cpus' => 2 - ], - Specification::S_4VCPU_4GB => [ - 'slug' => Specification::S_4VCPU_4GB, - 'memory' => 4096, - 'cpus' => 4 - ], - Specification::S_4VCPU_8GB => [ - 'slug' => Specification::S_4VCPU_8GB, - 'memory' => 8192, - 'cpus' => 4 - ], - Specification::S_8VCPU_4GB => [ - 'slug' => Specification::S_8VCPU_4GB, - 'memory' => 4096, - 'cpus' => 8 - ], - Specification::S_8VCPU_8GB => [ - 'slug' => Specification::S_8VCPU_8GB, - 'memory' => 8192, - 'cpus' => 8 - ] -]; diff --git a/app/config/frameworks/specifications.php b/app/config/specifications.php similarity index 100% rename from app/config/frameworks/specifications.php rename to app/config/specifications.php diff --git a/app/controllers/general.php b/app/controllers/general.php index d4728fb5af..1ebb1c80b3 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -174,7 +174,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw }; $runtimes = Config::getParam($version === 'v2' ? 'runtimes-v2' : 'runtimes', []); - $spec = Config::getParam('runtime-specifications')[$resource->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT)]; + $spec = Config::getParam('specifications')[$resource->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT)]; $runtime = match ($type) { 'function' => $runtimes[$resource->getAttribute('runtime')] ?? null, diff --git a/app/init.php b/app/init.php index 3291b160b9..90811013af 100644 --- a/app/init.php +++ b/app/init.php @@ -389,8 +389,7 @@ Config::load('storage-logos', __DIR__ . '/config/storage/logos.php'); Config::load('storage-mimes', __DIR__ . '/config/storage/mimes.php'); Config::load('storage-inputs', __DIR__ . '/config/storage/inputs.php'); Config::load('storage-outputs', __DIR__ . '/config/storage/outputs.php'); -Config::load('runtime-specifications', __DIR__ . '/config/runtimes/specifications.php'); -Config::load('framework-specifications', __DIR__ . '/config/frameworks/specifications.php'); +Config::load('specifications', __DIR__ . '/config/specifications.php'); Config::load('function-templates', __DIR__ . '/config/function-templates.php'); Config::load('site-templates', __DIR__ . '/config/site-templates.php'); diff --git a/src/Appwrite/Functions/Specification.php b/src/Appwrite/Functions/Specification.php deleted file mode 100644 index 50a3c02b62..0000000000 --- a/src/Appwrite/Functions/Specification.php +++ /dev/null @@ -1,16 +0,0 @@ -specifications as $size => $values) { if ($values['cpus'] <= $this->maxCpus && $values['memory'] <= $this->maxMemory) { - if (!empty($this->plan) && array_key_exists('runtimeSpecifications', $this->plan)) { - if (!\in_array($size, $this->plan['runtimeSpecifications'])) { + if (!empty($this->plan) && array_key_exists('specifications', $this->plan)) { + if (!\in_array($size, $this->plan['specifications'])) { continue; } } diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php index f522e2dc62..d59a3322a4 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php @@ -140,7 +140,7 @@ class Create extends Base $version = $function->getAttribute('version', 'v2'); $runtimes = Config::getParam($version === 'v2' ? 'runtimes-v2' : 'runtimes', []); - $spec = Config::getParam('runtime-specifications')[$function->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT)]; + $spec = Config::getParam('specifications')[$function->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT)]; $runtime = (isset($runtimes[$function->getAttribute('runtime', '')])) ? $runtimes[$function->getAttribute('runtime', '')] : null; diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php index 0507c68068..d2abb97b7e 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php @@ -2,10 +2,10 @@ namespace Appwrite\Platform\Modules\Functions\Http\Functions; +use Appwrite\Compute\Validator\Specification; use Appwrite\Event\Event; use Appwrite\Event\Validator\FunctionEvent; use Appwrite\Extend\Exception; -use Appwrite\Functions\Validator\RuntimeSpecification; use Appwrite\Platform\Modules\Compute\Base; use Appwrite\SDK\AuthType; use Appwrite\SDK\Method; @@ -85,9 +85,9 @@ class Create extends Base ->param('providerBranch', '', new Text(128, 0), 'Production branch for the repo linked to the function.', true) ->param('providerSilentMode', false, new Boolean(), 'Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.', true) ->param('providerRootDirectory', '', new Text(128, 0), 'Path to function code in the linked repo.', true) - ->param('specification', APP_COMPUTE_SPECIFICATION_DEFAULT, fn (array $plan) => new RuntimeSpecification( + ->param('specification', APP_COMPUTE_SPECIFICATION_DEFAULT, fn (array $plan) => new Specification( $plan, - Config::getParam('runtime-specifications', []), + Config::getParam('specifications', []), App::getEnv('_APP_COMPUTE_CPUS', APP_COMPUTE_CPUS_DEFAULT), App::getEnv('_APP_COMPUTE_MEMORY', APP_COMPUTE_MEMORY_DEFAULT) ), 'Runtime specification for the function and builds.', true, ['plan']) diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php index 9244b10c8c..cb4d2d553a 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php @@ -2,11 +2,11 @@ namespace Appwrite\Platform\Modules\Functions\Http\Functions; +use Appwrite\Compute\Validator\Specification; use Appwrite\Event\Build; use Appwrite\Event\Event; use Appwrite\Event\Validator\FunctionEvent; use Appwrite\Extend\Exception; -use Appwrite\Functions\Validator\RuntimeSpecification; use Appwrite\Platform\Modules\Compute\Base; use Appwrite\SDK\AuthType; use Appwrite\SDK\Method; @@ -89,9 +89,9 @@ class Update extends Base ->param('providerBranch', '', new Text(128, 0), 'Production branch for the repo linked to the function', true) ->param('providerSilentMode', false, new Boolean(), 'Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.', true) ->param('providerRootDirectory', '', new Text(128, 0), 'Path to function code in the linked repo.', true) - ->param('specification', APP_COMPUTE_SPECIFICATION_DEFAULT, fn (array $plan) => new RuntimeSpecification( + ->param('specification', APP_COMPUTE_SPECIFICATION_DEFAULT, fn (array $plan) => new Specification( $plan, - Config::getParam('runtime-specifications', []), + Config::getParam('specifications', []), App::getEnv('_APP_COMPUTE_CPUS', APP_COMPUTE_CPUS_DEFAULT), App::getEnv('_APP_COMPUTE_MEMORY', APP_COMPUTE_MEMORY_DEFAULT) ), 'Runtime specification for the function and builds.', true, ['plan']) @@ -206,8 +206,6 @@ class Update extends Base $live = false; } - $spec = Config::getParam('runtime-specifications')[$specification] ?? []; - // Enforce Cold Start if spec limits change. if ($function->getAttribute('specification') !== $specification && !empty($function->getAttribute('deployment'))) { $executor = new Executor(App::getEnv('_APP_EXECUTOR_HOST')); diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Specifications/XList.php b/src/Appwrite/Platform/Modules/Functions/Http/Specifications/XList.php index dbaf3daa04..375c99966d 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Specifications/XList.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Specifications/XList.php @@ -19,7 +19,7 @@ class XList extends Base public static function getName() { - return 'listFunctionsSpecifications'; + return 'listSpecifications'; } public function __construct() @@ -28,7 +28,7 @@ class XList extends Base ->setHttpMethod(Action::HTTP_REQUEST_METHOD_GET) ->setHttpPath('/v1/functions/specifications') ->groups(['api', 'functions']) - ->desc('List available function runtime specifications') + ->desc('List specifications') ->label('scope', 'functions.read') ->label('resourceType', RESOURCE_TYPE_FUNCTIONS) ->label('sdk', new Method( @@ -52,25 +52,25 @@ class XList extends Base public function action(Response $response, array $plan) { - $allRuntimeSpecs = Config::getParam('runtime-specifications', []); + $allSpecs = Config::getParam('specifications', []); - $runtimeSpecs = []; - foreach ($allRuntimeSpecs as $spec) { + $specs = []; + foreach ($allSpecs as $spec) { $spec['enabled'] = true; - if (array_key_exists('runtimeSpecifications', $plan)) { - $spec['enabled'] = in_array($spec['slug'], $plan['runtimeSpecifications']); + if (array_key_exists('specifications', $plan)) { + $spec['enabled'] = in_array($spec['slug'], $plan['specifications']); } // Only add specs that are within the limits set by environment variables if ($spec['cpus'] <= System::getEnv('_APP_COMPUTE_CPUS', 1) && $spec['memory'] <= System::getEnv('_APP_COMPUTE_MEMORY', 512)) { - $runtimeSpecs[] = $spec; + $specs[] = $spec; } } $response->dynamic(new Document([ - 'specifications' => $runtimeSpecs, - 'total' => count($runtimeSpecs) + 'specifications' => $specs, + 'total' => count($specs) ]), Response::MODEL_SPECIFICATION_LIST); } } diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index 53556f60ba..ba922b89c0 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -172,7 +172,7 @@ class Builds extends Action $version = $this->getVersion($resource); $runtime = $this->getRuntime($resource, $version); - $spec = Config::getParam('runtime-specifications')[$resource->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT)]; + $spec = Config::getParam('specifications')[$resource->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT)]; if ($resource->getCollection() === 'functions' && \is_null($runtime)) { throw new \Exception('Runtime "' . $resource->getAttribute('runtime', '') . '" is not supported'); diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Create.php index c39f618691..eb1c5b38f2 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Create.php @@ -2,13 +2,13 @@ namespace Appwrite\Platform\Modules\Sites\Http\Sites; +use Appwrite\Compute\Validator\Specification; use Appwrite\Event\Event; use Appwrite\Extend\Exception; use Appwrite\Platform\Modules\Compute\Base; use Appwrite\SDK\AuthType; use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; -use Appwrite\Sites\Validator\FrameworkSpecification; use Appwrite\Utopia\Database\Validator\CustomId; use Appwrite\Utopia\Response; use Utopia\App; @@ -77,9 +77,9 @@ class Create extends Base ->param('providerBranch', '', new Text(128, 0), 'Production branch for the repo linked to the site.', true) ->param('providerSilentMode', false, new Boolean(), 'Is the VCS (Version Control System) connection in silent mode for the repo linked to the site? In silent mode, comments will not be made on commits and pull requests.', true) ->param('providerRootDirectory', '', new Text(128, 0), 'Path to site code in the linked repo.', true) - ->param('specification', APP_COMPUTE_SPECIFICATION_DEFAULT, fn (array $plan) => new FrameworkSpecification( + ->param('specification', APP_COMPUTE_SPECIFICATION_DEFAULT, fn (array $plan) => new Specification( $plan, - Config::getParam('framework-specifications', []), + Config::getParam('specifications', []), App::getEnv('_APP_COMPUTE_CPUS', APP_COMPUTE_CPUS_DEFAULT), App::getEnv('_APP_COMPUTE_MEMORY', APP_COMPUTE_MEMORY_DEFAULT) ), 'Framework specification for the site and builds.', true, ['plan']) diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Update.php b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Update.php index f9dbdf604c..996a8209b5 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Update.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Update.php @@ -2,6 +2,7 @@ namespace Appwrite\Platform\Modules\Sites\Http\Sites; +use Appwrite\Compute\Validator\Specification; use Appwrite\Event\Build; use Appwrite\Event\Event; use Appwrite\Extend\Exception; @@ -9,7 +10,6 @@ use Appwrite\Platform\Modules\Compute\Base; use Appwrite\SDK\AuthType; use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; -use Appwrite\Sites\Validator\FrameworkSpecification; use Appwrite\Utopia\Response; use Executor\Executor; use Utopia\App; @@ -81,9 +81,9 @@ class Update extends Base ->param('providerBranch', '', new Text(128, 0), 'Production branch for the repo linked to the site.', true) ->param('providerSilentMode', false, new Boolean(), 'Is the VCS (Version Control System) connection in silent mode for the repo linked to the site? In silent mode, comments will not be made on commits and pull requests.', true) ->param('providerRootDirectory', '', new Text(128, 0), 'Path to site code in the linked repo.', true) - ->param('specification', APP_COMPUTE_SPECIFICATION_DEFAULT, fn (array $plan) => new FrameworkSpecification( + ->param('specification', APP_COMPUTE_SPECIFICATION_DEFAULT, fn (array $plan) => new Specification( $plan, - Config::getParam('framework-specifications', []), + Config::getParam('specifications', []), App::getEnv('_APP_COMPUTE_CPUS', APP_COMPUTE_CPUS_DEFAULT), App::getEnv('_APP_COMPUTE_MEMORY', APP_COMPUTE_MEMORY_DEFAULT) ), 'Framework specification for the site and builds.', true, ['plan']) @@ -204,8 +204,6 @@ class Update extends Base $live = false; } - $spec = Config::getParam('framework-specifications')[$specification] ?? []; - // Enforce Cold Start if spec limits change. if ($site->getAttribute('specification') !== $specification && !empty($site->getAttribute('deploymentId'))) { $executor = new Executor(App::getEnv('_APP_EXECUTOR_HOST')); diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Specifications/XList.php b/src/Appwrite/Platform/Modules/Sites/Http/Specifications/XList.php new file mode 100644 index 0000000000..63ee7bec10 --- /dev/null +++ b/src/Appwrite/Platform/Modules/Sites/Http/Specifications/XList.php @@ -0,0 +1,76 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_GET) + ->setHttpPath('/v1/sites/specifications') + ->groups(['api', 'sites']) + ->desc('List specifications') + ->label('scope', 'sites.read') + ->label('resourceType', RESOURCE_TYPE_SITES) + ->label('sdk', new Method( + namespace: 'sites', + name: 'listSpecifications', + description: <<inject('response') + ->inject('plan') + ->callback([$this, 'action']); + } + + public function action(Response $response, array $plan) + { + $allSpecs = Config::getParam('specifications', []); + + $specs = []; + foreach ($allSpecs as $spec) { + $spec['enabled'] = true; + + if (array_key_exists('specifications', $plan)) { + $spec['enabled'] = in_array($spec['slug'], $plan['specifications']); + } + + // Only add specs that are within the limits set by environment variables + if ($spec['cpus'] <= System::getEnv('_APP_COMPUTE_CPUS', 1) && $spec['memory'] <= System::getEnv('_APP_COMPUTE_MEMORY', 512)) { + $specs[] = $spec; + } + } + + $response->dynamic(new Document([ + 'specifications' => $specs, + 'total' => count($specs) + ]), Response::MODEL_SPECIFICATION_LIST); + } +} diff --git a/src/Appwrite/Platform/Workers/Functions.php b/src/Appwrite/Platform/Workers/Functions.php index f6d441ef3c..b0a9512f8e 100644 --- a/src/Appwrite/Platform/Workers/Functions.php +++ b/src/Appwrite/Platform/Workers/Functions.php @@ -327,7 +327,7 @@ class Functions extends Action $user ??= new Document(); $functionId = $function->getId(); $deploymentId = $function->getAttribute('deployment', ''); - $spec = Config::getParam('runtime-specifications')[$function->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT)]; + $spec = Config::getParam('specifications')[$function->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT)]; $log->addTag('deploymentId', $deploymentId); diff --git a/src/Appwrite/Sites/Validator/FrameworkSpecification.php b/src/Appwrite/Sites/Validator/FrameworkSpecification.php deleted file mode 100644 index b8dc3b5cfd..0000000000 --- a/src/Appwrite/Sites/Validator/FrameworkSpecification.php +++ /dev/null @@ -1,112 +0,0 @@ -plan = $plan; - $this->specifications = $specifications; - $this->maxCpus = $maxCpus; - $this->maxMemory = $maxMemory; - } - - /** - * Get Allowed Specifications. - * - * Get allowed specifications taking into account the limits set by the environment variables and the plan. - * - * @return array - */ - public function getAllowedSpecifications(): array - { - $allowedSpecifications = []; - - foreach ($this->specifications as $size => $values) { - if ($values['cpus'] <= $this->maxCpus && $values['memory'] <= $this->maxMemory) { - if (!empty($this->plan) && array_key_exists('frameworkSpecifications', $this->plan)) { - if (!\in_array($size, $this->plan['frameworkSpecifications'])) { - continue; - } - } - - $allowedSpecifications[] = $size; - } - } - - return $allowedSpecifications; - } - - /** - * Get Description. - * - * Returns validator description. - * - * @return string - */ - public function getDescription(): string - { - return 'Specification must be one of: ' . implode(', ', $this->getAllowedSpecifications()); - } - - /** - * Is valid. - * - * Returns true if valid or false if not. - * - * @param mixed $value - * - * @return bool - */ - public function isValid($value): bool - { - if (empty($value)) { - return false; - } - - if (!\is_string($value)) { - return false; - } - - if (!\in_array($value, $this->getAllowedSpecifications())) { - return false; - } - - return true; - } - - /** - * Is array. - * - * Function will return true if object is array. - * - * @return bool - */ - public function isArray(): bool - { - return false; - } - - /** - * Get Type. - * - * Returns validator type. - * - * @return string - */ - public function getType(): string - { - return self::TYPE_STRING; - } -} From c6a862a0a31a6db5141e0599c0579c9220524eb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Fri, 7 Mar 2025 23:17:15 +0100 Subject: [PATCH 2/2] Specifications test, fix failures --- app/config/specifications.php | 2 +- app/init.php | 2 +- .../Modules/Compute/Specification.php | 2 +- .../Compute/Validator/Specification.php | 2 +- .../Functions/Http/Functions/Create.php | 2 +- .../Functions/Http/Functions/Update.php | 2 +- .../Modules/Sites/Http/Sites/Create.php | 2 +- .../Modules/Sites/Http/Sites/Update.php | 2 +- .../Platform/Modules/Sites/Services/Http.php | 3 ++ tests/e2e/General/UsageTest.php | 2 +- .../e2e/Services/Functions/FunctionsBase.php | 9 ++++ .../Functions/FunctionsCustomServerTest.php | 43 +++++++++++++++++-- tests/e2e/Services/Sites/SitesBase.php | 9 ++++ .../Services/Sites/SitesCustomServerTest.php | 39 ++++++++++++++++- 14 files changed, 107 insertions(+), 14 deletions(-) diff --git a/app/config/specifications.php b/app/config/specifications.php index 63ca3ea423..82f5633a96 100644 --- a/app/config/specifications.php +++ b/app/config/specifications.php @@ -1,6 +1,6 @@ [ diff --git a/app/init.php b/app/init.php index 90811013af..6b57035ce9 100644 --- a/app/init.php +++ b/app/init.php @@ -36,13 +36,13 @@ use Appwrite\Event\Realtime; use Appwrite\Event\StatsUsage; use Appwrite\Event\Webhook; use Appwrite\Extend\Exception; -use Appwrite\Functions\Specification; use Appwrite\GraphQL\Promises\Adapter\Swoole; use Appwrite\GraphQL\Schema; use Appwrite\Hooks\Hooks; use Appwrite\Network\Validator\Email; use Appwrite\Network\Validator\Origin; use Appwrite\OpenSSL\OpenSSL; +use Appwrite\Platform\Modules\Compute\Specification; use Appwrite\PubSub\Adapter\Redis as PubSub; use Appwrite\URL\URL as AppwriteURL; use Appwrite\Utopia\Request; diff --git a/src/Appwrite/Platform/Modules/Compute/Specification.php b/src/Appwrite/Platform/Modules/Compute/Specification.php index 8c9e9b9aad..cf48896a7b 100644 --- a/src/Appwrite/Platform/Modules/Compute/Specification.php +++ b/src/Appwrite/Platform/Modules/Compute/Specification.php @@ -1,6 +1,6 @@ addAction(ListUsage::getName(), new ListUsage()); $this->addAction(GetUsage::getName(), new GetUsage()); + + $this->addAction(ListSpecifications::getName(), new ListSpecifications()); } } diff --git a/tests/e2e/General/UsageTest.php b/tests/e2e/General/UsageTest.php index 00dc790869..a74101f50d 100644 --- a/tests/e2e/General/UsageTest.php +++ b/tests/e2e/General/UsageTest.php @@ -2,7 +2,7 @@ namespace Tests\E2E\General; -use Appwrite\Functions\Specification; +use Appwrite\Platform\Modules\Compute\Specification; use Appwrite\Tests\Retry; use CURLFile; use DateTime; diff --git a/tests/e2e/Services/Functions/FunctionsBase.php b/tests/e2e/Services/Functions/FunctionsBase.php index 9f0a5903f3..85e881e5eb 100644 --- a/tests/e2e/Services/Functions/FunctionsBase.php +++ b/tests/e2e/Services/Functions/FunctionsBase.php @@ -389,4 +389,13 @@ trait FunctionsBase return $deployment; } + + protected function listSpecifications(): mixed + { + $specifications = $this->client->call(Client::METHOD_GET, '/functions/specifications', array_merge([ + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + return $specifications; + } } diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index 2056d1f689..472d6f430e 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -2,7 +2,7 @@ namespace Tests\E2E\Services\Functions; -use Appwrite\Functions\Specification; +use Appwrite\Platform\Modules\Compute\Specification; use Appwrite\Tests\Retry; use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; @@ -22,6 +22,41 @@ class FunctionsCustomServerTest extends Scope use ProjectCustom; use SideServer; + public function testListSpecs(): void + { + $specifications = $this->listSpecifications(); + $this->assertEquals(200, $specifications['headers']['status-code']); + $this->assertGreaterThan(0, $specifications['body']['total']); + $this->assertArrayHasKey(0, $specifications['body']['specifications']); + $this->assertArrayHasKey('memory', $specifications['body']['specifications'][0]); + $this->assertArrayHasKey('cpus', $specifications['body']['specifications'][0]); + $this->assertArrayHasKey('enabled', $specifications['body']['specifications'][0]); + $this->assertArrayHasKey('slug', $specifications['body']['specifications'][0]); + + $function = $this->createFunction([ + 'functionId' => ID::unique(), + 'name' => 'Specs function', + 'runtime' => 'php-8.0', + 'specification' => $specifications['body']['specifications'][0]['slug'] + ]); + $this->assertEquals(201, $function['headers']['status-code']); + $this->assertEquals($specifications['body']['specifications'][0]['slug'], $function['body']['specification']); + + $function = $this->getFunction($function['body']['$id']); + $this->assertEquals(200, $function['headers']['status-code']); + $this->assertEquals($specifications['body']['specifications'][0]['slug'], $function['body']['specification']); + + $this->cleanupFunction($function['body']['$id']); + + $function = $this->createFunction([ + 'functionId' => ID::unique(), + 'name' => 'Specs function', + 'runtime' => 'php-8.0', + 'specification' => 'cheap-please' + ]); + $this->assertEquals(400, $function['headers']['status-code']); + } + public function testCreateFunction(): array { /** @@ -2006,14 +2041,14 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(201, $execution['headers']['status-code']); $this->assertStringContainsString('APPWRITE_FUNCTION_ID', $execution['body']['responseBody']); - $site = $this->updateFunction($functionId, [ + $function = $this->updateFunction($functionId, [ 'runtime' => 'node-18.0', 'name' => 'Duplicate Deployment Test', 'entrypoint' => 'index.js', 'commands' => 'rm index.js && mv maintenance.js index.js' ]); - $this->assertEquals(200, $site['headers']['status-code']); - $this->assertStringContainsString('maintenance.js', $site['body']['commands']); + $this->assertEquals(200, $function['headers']['status-code']); + $this->assertStringContainsString('maintenance.js', $function['body']['commands']); $deploymentId2 = $this->setupDuplicateDeployment($functionId, $deploymentId1); $this->assertNotEmpty($deploymentId2); diff --git a/tests/e2e/Services/Sites/SitesBase.php b/tests/e2e/Services/Sites/SitesBase.php index a7e0293409..78c65afe98 100644 --- a/tests/e2e/Services/Sites/SitesBase.php +++ b/tests/e2e/Services/Sites/SitesBase.php @@ -414,4 +414,13 @@ trait SitesBase return $deployment; } + + protected function listSpecifications(): mixed + { + $specifications = $this->client->call(Client::METHOD_GET, '/sites/specifications', array_merge([ + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + return $specifications; + } } diff --git a/tests/e2e/Services/Sites/SitesCustomServerTest.php b/tests/e2e/Services/Sites/SitesCustomServerTest.php index bd6236291c..891882b1f9 100644 --- a/tests/e2e/Services/Sites/SitesCustomServerTest.php +++ b/tests/e2e/Services/Sites/SitesCustomServerTest.php @@ -2,7 +2,7 @@ namespace Tests\E2E\Services\Sites; -use Appwrite\Sites\Specification; +use Appwrite\Platform\Modules\Compute\Specification; use Appwrite\Tests\Retry; use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; @@ -20,6 +20,43 @@ class SitesCustomServerTest extends Scope use ProjectCustom; use SideServer; + public function testListSpecs(): void + { + $specifications = $this->listSpecifications(); + $this->assertEquals(200, $specifications['headers']['status-code']); + $this->assertGreaterThan(0, $specifications['body']['total']); + $this->assertArrayHasKey(0, $specifications['body']['specifications']); + $this->assertArrayHasKey('memory', $specifications['body']['specifications'][0]); + $this->assertArrayHasKey('cpus', $specifications['body']['specifications'][0]); + $this->assertArrayHasKey('enabled', $specifications['body']['specifications'][0]); + $this->assertArrayHasKey('slug', $specifications['body']['specifications'][0]); + + $site = $this->createSite([ + 'buildRuntime' => 'node-22', + 'framework' => 'other', + 'name' => 'Specs site', + 'siteId' => ID::unique(), + 'specification' => $specifications['body']['specifications'][0]['slug'] + ]); + $this->assertEquals(201, $site['headers']['status-code']); + $this->assertEquals($specifications['body']['specifications'][0]['slug'], $site['body']['specification']); + + $site = $this->getSite($site['body']['$id']); + $this->assertEquals(200, $site['headers']['status-code']); + $this->assertEquals($specifications['body']['specifications'][0]['slug'], $site['body']['specification']); + + $this->cleanupSite($site['body']['$id']); + + $site = $this->createSite([ + 'buildRuntime' => 'node-22', + 'framework' => 'other', + 'name' => 'Specs site', + 'siteId' => ID::unique(), + 'specification' => 'cheap-please' + ]); + $this->assertEquals(400, $site['headers']['status-code']); + } + public function testCreateSite(): void { /**