Merge remote-tracking branch 'origin/1.6.x' into feat-key-segmented-usage

# Conflicts:
#	composer.lock
This commit is contained in:
Jake Barnby 2025-02-17 17:12:45 +13:00
commit 390cdaa6a5
No known key found for this signature in database
GPG key ID: C437A8CC85B96E9C
8 changed files with 173 additions and 117 deletions

View file

@ -45,13 +45,13 @@
"ext-sockets": "*",
"appwrite/php-runtimes": "0.16.*",
"appwrite/php-clamav": "2.0.*",
"utopia-php/abuse": "0.49.*",
"utopia-php/abuse": "0.50.*",
"utopia-php/analytics": "0.10.*",
"utopia-php/audit": "0.49.*",
"utopia-php/audit": "0.51.*",
"utopia-php/cache": "0.11.*",
"utopia-php/cli": "0.15.*",
"utopia-php/config": "0.2.*",
"utopia-php/database": "0.58.5",
"utopia-php/database": "0.59.0",
"utopia-php/domains": "0.5.*",
"utopia-php/dsn": "0.2.1",
"utopia-php/framework": "0.33.*",

80
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "a7081f31ed2111c7b3a5a9c25b69bf80",
"content-hash": "b17c58729c4380afcba7714e9bced863",
"packages": [
{
"name": "adhocore/jwt",
@ -3377,16 +3377,16 @@
},
{
"name": "utopia-php/abuse",
"version": "0.49.0",
"version": "0.50.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/abuse.git",
"reference": "76612c274b895aa3d4d1fa27557a6402463eea99"
"reference": "3ff67819e9de61506c5ca070a70552f7ebe99f80"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/76612c274b895aa3d4d1fa27557a6402463eea99",
"reference": "76612c274b895aa3d4d1fa27557a6402463eea99",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/3ff67819e9de61506c5ca070a70552f7ebe99f80",
"reference": "3ff67819e9de61506c5ca070a70552f7ebe99f80",
"shasum": ""
},
"require": {
@ -3394,7 +3394,7 @@
"ext-pdo": "*",
"ext-redis": "*",
"php": ">=8.0",
"utopia-php/database": "0.58.*"
"utopia-php/database": "0.59.*"
},
"require-dev": {
"laravel/pint": "1.*",
@ -3422,9 +3422,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/abuse/issues",
"source": "https://github.com/utopia-php/abuse/tree/0.49.0"
"source": "https://github.com/utopia-php/abuse/tree/0.50.0"
},
"time": "2025-02-04T07:33:59+00:00"
"time": "2025-02-12T09:13:59+00:00"
},
{
"name": "utopia-php/analytics",
@ -3474,21 +3474,21 @@
},
{
"name": "utopia-php/audit",
"version": "0.49.0",
"version": "0.51.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/audit.git",
"reference": "9d5c5e0cf0f6d9157b911fc3971da4331d71c96d"
"reference": "a5a4b73a57e27a0fac8025b1d6038e145a1ca04e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/9d5c5e0cf0f6d9157b911fc3971da4331d71c96d",
"reference": "9d5c5e0cf0f6d9157b911fc3971da4331d71c96d",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/a5a4b73a57e27a0fac8025b1d6038e145a1ca04e",
"reference": "a5a4b73a57e27a0fac8025b1d6038e145a1ca04e",
"shasum": ""
},
"require": {
"php": ">=8.0",
"utopia-php/database": "0.58.*"
"utopia-php/database": "0.59.*"
},
"require-dev": {
"laravel/pint": "1.*",
@ -3515,9 +3515,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/audit/issues",
"source": "https://github.com/utopia-php/audit/tree/0.49.0"
"source": "https://github.com/utopia-php/audit/tree/0.51.0"
},
"time": "2025-02-04T07:27:18+00:00"
"time": "2025-02-12T09:12:44+00:00"
},
{
"name": "utopia-php/cache",
@ -3717,16 +3717,16 @@
},
{
"name": "utopia-php/database",
"version": "0.58.5",
"version": "0.59.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
"reference": "55308014c697639c6cb270cb5a33cc88fc1ef839"
"reference": "0eed7f1ad3eb66ff4a7d73b68dd9d3e05089eb18"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/database/zipball/55308014c697639c6cb270cb5a33cc88fc1ef839",
"reference": "55308014c697639c6cb270cb5a33cc88fc1ef839",
"url": "https://api.github.com/repos/utopia-php/database/zipball/0eed7f1ad3eb66ff4a7d73b68dd9d3e05089eb18",
"reference": "0eed7f1ad3eb66ff4a7d73b68dd9d3e05089eb18",
"shasum": ""
},
"require": {
@ -3767,9 +3767,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
"source": "https://github.com/utopia-php/database/tree/0.58.5"
"source": "https://github.com/utopia-php/database/tree/0.59.0"
},
"time": "2025-02-10T08:26:52+00:00"
"time": "2025-02-12T08:08:29+00:00"
},
{
"name": "utopia-php/domains",
@ -4170,16 +4170,16 @@
},
{
"name": "utopia-php/migration",
"version": "0.6.17",
"version": "0.6.19",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/migration.git",
"reference": "677a5c4688d7f54d1631a91f76a35d51346cf96b"
"reference": "3c9497f7a54ef88b1077c48d8326893133ad78eb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/677a5c4688d7f54d1631a91f76a35d51346cf96b",
"reference": "677a5c4688d7f54d1631a91f76a35d51346cf96b",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/3c9497f7a54ef88b1077c48d8326893133ad78eb",
"reference": "3c9497f7a54ef88b1077c48d8326893133ad78eb",
"shasum": ""
},
"require": {
@ -4187,7 +4187,7 @@
"ext-curl": "*",
"ext-openssl": "*",
"php": ">=8.1",
"utopia-php/database": "0.58.*",
"utopia-php/database": "0.59.*",
"utopia-php/dsn": "0.2.*",
"utopia-php/framework": "0.33.*",
"utopia-php/storage": "0.18.*"
@ -4220,9 +4220,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/migration/issues",
"source": "https://github.com/utopia-php/migration/tree/0.6.17"
"source": "https://github.com/utopia-php/migration/tree/0.6.19"
},
"time": "2025-02-05T05:27:29+00:00"
"time": "2025-02-13T07:50:21+00:00"
},
{
"name": "utopia-php/mongo",
@ -5560,16 +5560,16 @@
},
{
"name": "myclabs/deep-copy",
"version": "1.12.1",
"version": "1.13.0",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845"
"reference": "024473a478be9df5fdaca2c793f2232fe788e414"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845",
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414",
"reference": "024473a478be9df5fdaca2c793f2232fe788e414",
"shasum": ""
},
"require": {
@ -5608,7 +5608,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.1"
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.0"
},
"funding": [
{
@ -5616,7 +5616,7 @@
"type": "tidelift"
}
],
"time": "2024-11-08T17:47:46+00:00"
"time": "2025-02-12T12:17:51+00:00"
},
{
"name": "nikic/php-parser",
@ -6190,16 +6190,16 @@
},
{
"name": "phpstan/phpdoc-parser",
"version": "2.0.0",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "c00d78fb6b29658347f9d37ebe104bffadf36299"
"reference": "72e51f7c32c5aef7c8b462195b8c599b11199893"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/c00d78fb6b29658347f9d37ebe104bffadf36299",
"reference": "c00d78fb6b29658347f9d37ebe104bffadf36299",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/72e51f7c32c5aef7c8b462195b8c599b11199893",
"reference": "72e51f7c32c5aef7c8b462195b8c599b11199893",
"shasum": ""
},
"require": {
@ -6231,9 +6231,9 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/2.0.0"
"source": "https://github.com/phpstan/phpdoc-parser/tree/2.0.1"
},
"time": "2024-10-13T11:29:49+00:00"
"time": "2025-02-13T12:25:43+00:00"
},
{
"name": "phpunit/php-code-coverage",

View file

@ -6,15 +6,33 @@ use Appwrite\Auth\Auth;
use Exception;
use Throwable;
use Utopia\Audit\Audit;
use Utopia\CLI\Console;
use Utopia\Database\Database;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Exception\Authorization;
use Utopia\Database\Exception\Structure;
use Utopia\Platform\Action;
use Utopia\Queue\Message;
use Utopia\System\System;
class Audits extends Action
{
private const BATCH_SIZE_DEVELOPMENT = 1; // smaller batch size for development
private const BATCH_SIZE_PRODUCTION = 5_000;
private const BATCH_AGGREGATION_INTERVAL = 60; // in seconds
private int $lastTriggeredTime = 0;
private array $logs = [];
private function getBatchSize(): int
{
return System::getEnv('_APP_ENV', 'development') === 'development'
? self::BATCH_SIZE_DEVELOPMENT
: self::BATCH_SIZE_PRODUCTION;
}
public static function getName(): string
{
return 'audits';
@ -30,6 +48,8 @@ class Audits extends Action
->inject('message')
->inject('dbForProject')
->callback(fn ($message, $dbForProject) => $this->action($message, $dbForProject));
$this->lastTriggeredTime = time();
}
@ -44,13 +64,14 @@ class Audits extends Action
*/
public function action(Message $message, Database $dbForProject): void
{
$payload = $message->getPayload() ?? [];
if (empty($payload)) {
throw new Exception('Missing payload');
}
Console::info('Aggregating audit logs');
$event = $payload['event'] ?? '';
$auditPayload = $payload['payload'] ?? '';
$mode = $payload['mode'] ?? '';
@ -63,23 +84,48 @@ class Audits extends Action
$userEmail = $user->getAttribute('email', '');
$userType = $user->getAttribute('type', Auth::ACTIVITY_TYPE_USER);
$audit = new Audit($dbForProject);
$audit->log(
userId: $user->getInternalId(),
// Pass first, most verbose event pattern
event: $event,
resource: $resource,
userAgent: $userAgent,
ip: $ip,
location: '',
data: [
// Create event data
$eventData = [
'userId' => $user->getInternalId(),
'event' => $event,
'resource' => $resource,
'userAgent' => $userAgent,
'ip' => $ip,
'location' => '',
'data' => [
'userId' => $user->getId(),
'userName' => $userName,
'userEmail' => $userEmail,
'userType' => $userType,
'mode' => $mode,
'data' => $auditPayload,
]
);
],
'timestamp' => DateTime::formatTz(DateTime::now())
];
$this->logs[] = $eventData;
// 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) {
$shouldProcessBatch = (time() - $this->lastTriggeredTime) >= self::BATCH_AGGREGATION_INTERVAL;
}
if ($shouldProcessBatch) {
Console::log('Processing batch with ' . count($this->logs) . ' events');
$audit = new Audit($dbForProject);
try {
$audit->logBatch($this->logs);
Console::success('Audit logs processed successfully');
} catch (Throwable $e) {
Console::error('Error processing audit logs: ' . $e->getMessage());
} finally {
// Clear the pending events after successful batch processing
$this->logs = [];
$this->lastTriggeredTime = time();
}
}
}
}

View file

@ -54,8 +54,10 @@ class Builds extends Action
->inject('cache')
->inject('dbForProject')
->inject('deviceForFunctions')
->inject('isResourceBlocked')
->inject('log')
->callback(fn ($message, Document $project, Database $dbForPlatform, Event $queueForEvents, Func $queueForFunctions, StatsUsage $usage, Cache $cache, Database $dbForProject, Device $deviceForFunctions, Log $log) => $this->action($message, $project, $dbForPlatform, $queueForEvents, $queueForFunctions, $usage, $cache, $dbForProject, $deviceForFunctions, $log));
->callback(fn ($message, Document $project, Database $dbForPlatform, Event $queueForEvents, Func $queueForFunctions, StatsUsage $usage, Cache $cache, Database $dbForProject, Device $deviceForFunctions, callable $isResourceBlocked, Log $log) =>
$this->action($message, $project, $dbForPlatform, $queueForEvents, $queueForFunctions, $usage, $cache, $dbForProject, $deviceForFunctions, $isResourceBlocked, $log));
}
/**
@ -72,7 +74,7 @@ class Builds extends Action
* @return void
* @throws \Utopia\Database\Exception
*/
public function action(Message $message, Document $project, Database $dbForPlatform, Event $queueForEvents, Func $queueForFunctions, StatsUsage $queueForStatsUsage, Cache $cache, Database $dbForProject, Device $deviceForFunctions, Log $log): void
public function action(Message $message, Document $project, Database $dbForPlatform, Event $queueForEvents, Func $queueForFunctions, StatsUsage $queueForStatsUsage, Cache $cache, Database $dbForProject, Device $deviceForFunctions, callable $isResourceBlocked, Log $log): void
{
$payload = $message->getPayload() ?? [];
@ -93,7 +95,7 @@ class Builds extends Action
case BUILD_TYPE_RETRY:
Console::info('Creating build for deployment: ' . $deployment->getId());
$github = new GitHub($cache);
$this->buildDeployment($deviceForFunctions, $queueForFunctions, $queueForEvents, $queueForStatsUsage, $dbForPlatform, $dbForProject, $github, $project, $resource, $deployment, $template, $log);
$this->buildDeployment($deviceForFunctions, $queueForFunctions, $queueForEvents, $queueForStatsUsage, $dbForPlatform, $dbForProject, $github, $project, $resource, $deployment, $template, $isResourceBlocked, $log);
break;
default:
@ -118,7 +120,7 @@ class Builds extends Action
* @throws \Utopia\Database\Exception
* @throws Exception
*/
protected function buildDeployment(Device $deviceForFunctions, Func $queueForFunctions, Event $queueForEvents, StatsUsage $queueForStatsUsage, Database $dbForPlatform, Database $dbForProject, GitHub $github, Document $project, Document $function, Document $deployment, Document $template, Log $log): void
protected function buildDeployment(Device $deviceForFunctions, Func $queueForFunctions, Event $queueForEvents, StatsUsage $queueForStatsUsage, Database $dbForPlatform, Database $dbForProject, GitHub $github, Document $project, Document $function, Document $deployment, Document $template, callable $isResourceBlocked, Log $log): void
{
$executor = new Executor(System::getEnv('_APP_EXECUTOR_HOST'));
@ -127,7 +129,11 @@ class Builds extends Action
$function = $dbForProject->getDocument('functions', $functionId);
if ($function->isEmpty()) {
throw new \Exception('Function not found', 404);
throw new \Exception('Function not found');
}
if ($isResourceBlocked($project, RESOURCE_TYPE_FUNCTIONS, $functionId)) {
throw new \Exception('Function blocked');
}
$deploymentId = $deployment->getId();
@ -135,15 +141,15 @@ class Builds extends Action
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
if ($deployment->isEmpty()) {
throw new \Exception('Deployment not found', 404);
throw new \Exception('Deployment not found');
}
if (empty($deployment->getAttribute('entrypoint', ''))) {
throw new \Exception('Entrypoint for your Appwrite Function is missing. Please specify it when making deployment or update the entrypoint under your function\'s "Settings" > "Configuration" > "Entrypoint".', 500);
throw new \Exception('Entrypoint for your Appwrite Function is missing. Please specify it when making deployment or update the entrypoint under your function\'s "Settings" > "Configuration" > "Entrypoint".');
}
$version = $function->getAttribute('version', 'v2');
$spec = Config::getParam('runtime-specifications')[$function->getAttribute('specifications', APP_FUNCTION_SPECIFICATION_DEFAULT)];
$spec = Config::getParam('runtime-specifications')[$function->getAttribute('specification', APP_FUNCTION_SPECIFICATION_DEFAULT)];
$runtimes = Config::getParam($version === 'v2' ? 'runtimes-v2' : 'runtimes', []);
$key = $function->getAttribute('runtime');
$runtime = $runtimes[$key] ?? null;
@ -571,7 +577,7 @@ class Builds extends Action
$build = $dbForProject->getDocument('builds', $build->getId());
if ($build->isEmpty()) {
throw new \Exception('Build not found', 404);
throw new \Exception('Build not found');
}
if ($build->getAttribute('status') === 'canceled') {

View file

@ -214,47 +214,17 @@ class StatsResources extends Action
protected function countImageTransformations(Database $dbForProject, Database $dbForLogs, string $region)
{
$totalImageTransformations = 0;
$totalDailyImageTransformations = 0;
$totalHourlyImageTransformations = 0;
$this->foreachDocument($dbForProject, 'buckets', [], function ($bucket) use ($dbForProject, $dbForLogs, $region, &$totalDailyImageTransformations, &$totalHourlyImageTransformations, &$totalImageTransformations) {
$last30Days = (new \DateTime())->sub(\DateInterval::createFromDateString('30 days'))->format('Y-m-d 00:00:00');
$this->foreachDocument($dbForProject, 'buckets', [], function ($bucket) use ($dbForProject, $last30Days, $region, &$totalImageTransformations) {
$imageTransformations = $dbForProject->count('bucket_' . $bucket->getInternalId(), [
Query::isNotNull('transformedAt')
Query::greaterThanEqual('transformedAt', $last30Days),
]);
$metric = str_replace('{bucketInternalId}', $bucket->getInternalId(), METRIC_BUCKET_ID_FILES_IMAGES_TRANSFORMED);
$this->createStatsDocuments($region, $metric, $imageTransformations, 'inf');
$this->createStatsDocuments($region, $metric, $imageTransformations);
$totalImageTransformations += $imageTransformations;
// hourly
$time = \date($this->periods['1h'], \time());
$start = $time;
$end = (new \DateTime($start))->format('Y-m-d H:59:59');
$hourlyImageTransformations = $dbForProject->count('bucket_' . $bucket->getInternalId(), [
Query::greaterThanEqual('transformedAt', $start),
Query::lessThanEqual('transformedAt', $end),
]);
$metric = str_replace('{bucketInternalId}', $bucket->getInternalId(), METRIC_BUCKET_ID_FILES_IMAGES_TRANSFORMED);
$this->createStatsDocuments($region, $metric, $hourlyImageTransformations, '1h');
$totalHourlyImageTransformations += $hourlyImageTransformations;
// daily
$time = \date($this->periods['1d'], \time());
$start = $time;
$end = (new \DateTime($start))->format('Y-m-d 11:59:59');
$dailyImageTransformations = $dbForProject->count('bucket_' . $bucket->getInternalId(), [
Query::greaterThanEqual('transformedAt', $start),
Query::lessThanEqual('transformedAt', $end),
]);
$metric = str_replace('{bucketInternalId}', $bucket->getInternalId(), METRIC_BUCKET_ID_FILES_IMAGES_TRANSFORMED);
$this->createStatsDocuments($region, $metric, $dailyImageTransformations, '1d');
$totalDailyImageTransformations += $dailyImageTransformations;
});
$this->createStatsDocuments($region, METRIC_FILES_IMAGES_TRANSFORMED, $totalImageTransformations, 'inf');
$this->createStatsDocuments($region, METRIC_FILES_IMAGES_TRANSFORMED, $totalDailyImageTransformations, '1d');
$this->createStatsDocuments($region, METRIC_FILES_IMAGES_TRANSFORMED, $totalHourlyImageTransformations, '1h');
$this->createStatsDocuments($region, METRIC_FILES_IMAGES_TRANSFORMED, $totalImageTransformations);
}
protected function countForDatabase(Database $dbForProject, Database $dbForLogs, string $region)
@ -341,30 +311,19 @@ class StatsResources extends Action
});
}
protected function createStatsDocuments(string $region, string $metric, int $value, ?string $period = null)
protected function createStatsDocuments(string $region, string $metric, int $value)
{
if ($period === null) {
foreach ($this->periods as $period => $format) {
$time = 'inf' === $period ? null : \date($format, \time());
$id = \md5("{$time}_{$period}_{$metric}");
$this->documents[] = new Document([
'$id' => $id,
'metric' => $metric,
'period' => $period,
'region' => $region,
'value' => $value,
]);
}
} else {
$time = 'inf' === $period ? null : \date($this->periods[$period], \time());
foreach ($this->periods as $period => $format) {
$time = 'inf' === $period ? null : \date($format, \time());
$id = \md5("{$time}_{$period}_{$metric}");
$this->documents[] = new Document([
'$id' => $id,
'metric' => $metric,
'period' => $period,
'region' => $region,
'value' => $value,
'time' => $time,
]);
}
}

View file

@ -463,7 +463,7 @@ trait DatabasesBase
]);
$this->assertEquals(400, $attribute['headers']['status-code']);
$this->assertEquals('Index length is longer than the maximum: 768', $attribute['body']['message']);
$this->assertStringContainsString('Index length is longer than the maximum: 76', $attribute['body']['message']);
}
public function testUpdateAttributeEnum(): void

View file

@ -1984,4 +1984,47 @@ class FunctionsCustomServerTest extends Scope
$this->cleanupFunction($functionId);
}
public function testFunctionSpecifications()
{
// Check if the function specifications are correctly set in builds
$function = $this->createFunction([
'functionId' => ID::unique(),
'runtime' => 'node-18.0',
'name' => 'Specification Test',
'entrypoint' => 'index.js',
'logging' => false,
'execute' => ['any'],
'specification' => Specification::S_2VCPU_2GB,
'commands' => 'echo $APPWRITE_FUNCTION_MEMORY:$APPWRITE_FUNCTION_CPUS',
]);
$this->assertEquals(201, $function['headers']['status-code']);
$this->assertEquals(Specification::S_2VCPU_2GB, $function['body']['specification']);
$this->assertNotEmpty($function['body']['$id']);
$functionId = $functionId = $function['body']['$id'] ?? '';
$deploymentId = $this->setupDeployment($functionId, [
'code' => $this->packageFunction('node'),
'activate' => true
]);
$this->assertEventually(function () use ($functionId, $deploymentId) {
$deployment = $this->getDeployment($functionId, $deploymentId);
$this->assertTrue(str_contains($deployment['body']['buildLogs'], '2048:2'));
}, 10000, 500);
// Check if the function specifications are correctly set in executions
$execution = $this->createExecution($functionId);
$this->assertEquals(201, $execution['headers']['status-code']);
$this->assertNotEmpty($execution['body']['$id']);
$executionResponse = json_decode($execution['body']['responseBody'], true);
$this->assertEquals('2048', $executionResponse['APPWRITE_FUNCTION_MEMORY']);
$this->assertEquals('2', $executionResponse['APPWRITE_FUNCTION_CPUS']);
$this->cleanupFunction($functionId);
}
}

View file

@ -14,6 +14,8 @@ module.exports = async(context) => {
'APPWRITE_FUNCTION_USER_ID' : context.req.headers['x-appwrite-user-id'] ?? '',
'APPWRITE_FUNCTION_JWT' : context.req.headers['x-appwrite-user-jwt'] ?? '',
'APPWRITE_FUNCTION_PROJECT_ID' : process.env.APPWRITE_FUNCTION_PROJECT_ID,
'APPWRITE_FUNCTION_MEMORY' : process.env.APPWRITE_FUNCTION_MEMORY,
'APPWRITE_FUNCTION_CPUS' : process.env.APPWRITE_FUNCTION_CPUS,
'CUSTOM_VARIABLE' : process.env.CUSTOM_VARIABLE
});
}