From e42275e0b7f85b45818ba4ccef200a6e551007fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 9 Jul 2025 11:26:05 +0200 Subject: [PATCH 01/10] Minify tests --- .env | 5 +- .github/workflows/tests.yml | 87 ++++++++++++++++++- app/controllers/mock.php | 26 ------ docker-compose.yml | 3 +- .../Modules/Functions/Workers/Builds.php | 3 +- .../Functions/FunctionsCustomServerTest.php | 43 --------- .../Services/Sites/SitesConsoleClientTest.php | 3 + tests/resources/functions/dart/main.dart | 21 ----- tests/resources/functions/php-v2/index.php | 7 -- tests/resources/functions/python/main.py | 21 ----- tests/resources/functions/ruby/main.rb | 19 ---- tests/resources/functions/swift/index.swift | 17 ---- 12 files changed, 95 insertions(+), 160 deletions(-) delete mode 100644 tests/resources/functions/dart/main.dart delete mode 100644 tests/resources/functions/php-v2/index.php delete mode 100644 tests/resources/functions/python/main.py delete mode 100644 tests/resources/functions/ruby/main.rb delete mode 100644 tests/resources/functions/swift/index.swift diff --git a/.env b/.env index 42c23ac87f..76af83a946 100644 --- a/.env +++ b/.env @@ -85,8 +85,9 @@ _APP_COMPUTE_MAINTENANCE_INTERVAL=600 _APP_COMPUTE_RUNTIMES_NETWORK=runtimes _APP_EXECUTOR_SECRET=your-secret-key _APP_EXECUTOR_HOST=http://exc1/v1 -_APP_FUNCTIONS_RUNTIMES=php-8.0,node-18.0,python-3.9,ruby-3.1 -_APP_SITES_RUNTIMES=static-1,node-22,flutter-3.32 +_APP_BROWSER_HOST=http://appwrite-browser:3000/v1 +_APP_FUNCTIONS_RUNTIMES=node-22 +_APP_SITES_RUNTIMES=static-1,node-22 _APP_MAINTENANCE_INTERVAL=86400 _APP_MAINTENANCE_START_TIME=12:00 _APP_MAINTENANCE_RETENTION_CACHE=2592000 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a69e11b892..57a1a1aefa 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -178,6 +178,7 @@ jobs: - name: Load and Start Appwrite run: | docker load --input /tmp/${{ env.IMAGE }}.tar + sed -i 's/_APP_BROWSER_HOST=http:\/\/appwrite-browser:3000\/v1/_APP_BROWSER_HOST=http:\/\/invalid-browser\/v1/' .env docker compose up -d sleep 30 @@ -198,7 +199,7 @@ jobs: docker compose exec -T \ -e _APP_DATABASE_SHARED_TABLES \ -e _APP_DATABASE_SHARED_TABLES_V1 \ - appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group devKeys + appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group devKeys screenshots e2e_shared_mode_test: name: E2E Shared Mode Service Test @@ -277,7 +278,7 @@ jobs: docker compose exec -T \ -e _APP_DATABASE_SHARED_TABLES \ -e _APP_DATABASE_SHARED_TABLES_V1 \ - appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group devKeys + appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group devKeys screenshots e2e_dev_keys: name: E2E Service Test (Dev Keys) @@ -358,3 +359,85 @@ jobs: -e _APP_DATABASE_SHARED_TABLES \ -e _APP_DATABASE_SHARED_TABLES_V1 \ appwrite test /usr/src/code/tests/e2e/Services/Projects --debug --group=devKeys + + e2e_screenshots_keys: + name: E2E Service Test (Site Screenshots) + runs-on: ubuntu-latest + needs: setup + steps: + - name: checkout + uses: actions/checkout@v4 + + - name: Load Cache + uses: actions/cache@v4 + with: + key: ${{ env.CACHE_KEY }} + path: /tmp/${{ env.IMAGE }}.tar + fail-on-cache-miss: true + + - name: Load and Start Appwrite + run: | + docker load --input /tmp/${{ env.IMAGE }}.tar + sed -i 's/_APP_OPTIONS_ABUSE=disabled/_APP_OPTIONS_ABUSE=enabled/' .env + docker compose up -d + sleep 30 + + - name: Run Site tests with browser connected in dedicated table mode + run: | + echo "Keeping original value of _APP_BROWSER_HOST" + echo "Using project tables" + export _APP_DATABASE_SHARED_TABLES= + export _APP_DATABASE_SHARED_TABLES_V1= + + docker compose exec -T \ + -e _APP_DATABASE_SHARED_TABLES \ + -e _APP_DATABASE_SHARED_TABLES_V1 \ + appwrite test /usr/src/code/tests/e2e/Services/Sites --debug --group=screenshots + + e2e_screenshots_shared_mode: + name: E2E Shared Mode Service Test (Site Screenshots) + runs-on: ubuntu-latest + needs: [ setup, check_database_changes ] + if: needs.check_database_changes.outputs.database_changed == 'true' + strategy: + fail-fast: false + matrix: + tables-mode: [ + 'Shared V1', + 'Shared V2', + ] + steps: + - name: checkout + uses: actions/checkout@v4 + + - name: Load Cache + uses: actions/cache@v4 + with: + key: ${{ env.CACHE_KEY }} + path: /tmp/${{ env.IMAGE }}.tar + fail-on-cache-miss: true + + - name: Load and Start Appwrite + run: | + docker load --input /tmp/${{ env.IMAGE }}.tar + sed -i 's/_APP_OPTIONS_ABUSE=disabled/_APP_OPTIONS_ABUSE=enabled/' .env + docker compose up -d + sleep 30 + + - name: Run Site tests with browser connected in ${{ matrix.tables-mode }} table mode + run: | + echo "Keeping original value of _APP_BROWSER_HOST" + if [ "${{ matrix.tables-mode }}" == "Shared V1" ]; then + echo "Using shared tables V1" + export _APP_DATABASE_SHARED_TABLES=database_db_main + export _APP_DATABASE_SHARED_TABLES_V1=database_db_main + elif [ "${{ matrix.tables-mode }}" == "Shared V2" ]; then + echo "Using shared tables V2" + export _APP_DATABASE_SHARED_TABLES=database_db_main + export _APP_DATABASE_SHARED_TABLES_V1= + fi + + docker compose exec -T \ + -e _APP_DATABASE_SHARED_TABLES \ + -e _APP_DATABASE_SHARED_TABLES_V1 \ + appwrite test /usr/src/code/tests/e2e/Services/Sites --debug --group=screenshots diff --git a/app/controllers/mock.php b/app/controllers/mock.php index fd7b9ab495..0684e5294a 100644 --- a/app/controllers/mock.php +++ b/app/controllers/mock.php @@ -129,32 +129,6 @@ App::get('/v1/mock/tests/general/oauth2/failure') ]); }); -App::patch('/v1/mock/functions-v2') - ->desc('Update Function Version to V2 (outdated code syntax)') - ->groups(['mock', 'api', 'functions']) - ->label('scope', 'functions.write') - ->label('docs', false) - ->param('functionId', '', new UID(), 'Function ID.') - ->inject('response') - ->inject('dbForProject') - ->action(function (string $functionId, Response $response, Database $dbForProject) { - $isDevelopment = System::getEnv('_APP_ENV', 'development') === 'development'; - - if (!$isDevelopment) { - throw new Exception(Exception::GENERAL_NOT_IMPLEMENTED); - } - - $function = $dbForProject->getDocument('functions', $functionId); - - if ($function->isEmpty()) { - throw new Exception(Exception::FUNCTION_NOT_FOUND); - } - - $dbForProject->updateDocument('functions', $function->getId(), $function->setAttribute('version', 'v2')); - - $response->noContent(); - }); - App::post('/v1/mock/api-key-unprefixed') ->desc('Create API Key (without standard prefix)') ->groups(['mock', 'api', 'projects']) diff --git a/docker-compose.yml b/docker-compose.yml index a01165d949..ba23c4780c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -456,6 +456,7 @@ services: - redis - mariadb environment: + - _APP_BROWSER_HOST - _APP_ENV - _APP_WORKER_PER_CORE - _APP_OPENSSL_KEY_V1 @@ -977,7 +978,7 @@ services: - OPR_EXECUTOR_ENV=$_APP_ENV - OPR_EXECUTOR_RUNTIMES=$_APP_FUNCTIONS_RUNTIMES,$_APP_SITES_RUNTIMES - OPR_EXECUTOR_SECRET=$_APP_EXECUTOR_SECRET - - OPR_EXECUTOR_RUNTIME_VERSIONS=v2,v5 + - OPR_EXECUTOR_RUNTIME_VERSIONS=v5 - OPR_EXECUTOR_LOGGING_CONFIG=$_APP_LOGGING_CONFIG - OPR_EXECUTOR_STORAGE_DEVICE=$_APP_STORAGE_DEVICE - OPR_EXECUTOR_STORAGE_S3_ACCESS_KEY=$_APP_STORAGE_S3_ACCESS_KEY diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index 25b3473829..adfc14abc8 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -959,8 +959,9 @@ class Builds extends Action $config['sleep'] = $framework['screenshotSleep']; } + $browserEndpoint = Config::getParam('_APP_BROWSER_HOST', 'http://appwrite-browser:3000/v1'); $fetchResponse = $client->fetch( - url: 'http://appwrite-browser:3000/v1/screenshots', + url: $browserEndpoint . '/screenshots', method: 'POST', body: $config ); diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index 6a8db0a88c..846ca37262 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -1461,49 +1461,6 @@ class FunctionsCustomServerTest extends Scope $this->cleanupFunction($functionId); } - public function testv2Function() - { - $functionId = $this->setupFunction([ - 'functionId' => ID::unique(), - 'name' => 'Test PHP V2', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', - 'events' => [], - 'timeout' => 15, - ]); - - $variable = $this->client->call(Client::METHOD_PATCH, '/mock/functions-v2', [ - 'content-type' => 'application/json', - 'origin' => 'http://localhost', - 'cookie' => 'a_session_console=' . $this->getRoot()['session'], - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-mode' => 'admin', - ], [ - 'functionId' => $functionId - ]); - $this->assertEquals(204, $variable['headers']['status-code']); - - $this->setupDeployment($functionId, [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php-v2'), - 'activate' => true - ]); - - $execution = $this->createExecution($functionId, [ - 'body' => 'foobar', - 'async' => 'false' - ]); - - $this->assertEquals(201, $execution['headers']['status-code']); - $this->assertEquals('completed', $execution['body']['status']); - $this->assertEquals(200, $execution['body']['responseStatusCode']); - - $output = json_decode($execution['body']['responseBody'], true); - $this->assertEquals(true, $output['v2Woks']); - - $this->cleanupFunction($functionId); - } - public function testGetRuntimes() { $runtimes = $this->client->call(Client::METHOD_GET, '/functions/runtimes', array_merge([ diff --git a/tests/e2e/Services/Sites/SitesConsoleClientTest.php b/tests/e2e/Services/Sites/SitesConsoleClientTest.php index 1a84f46ed7..28ce2a35ec 100644 --- a/tests/e2e/Services/Sites/SitesConsoleClientTest.php +++ b/tests/e2e/Services/Sites/SitesConsoleClientTest.php @@ -14,6 +14,9 @@ class SitesConsoleClientTest extends Scope use SideConsole; use SitesBase; + /** + * @group screenshots + */ public function testSiteScreenshot(): void { $siteId = $this->setupSite([ diff --git a/tests/resources/functions/dart/main.dart b/tests/resources/functions/dart/main.dart deleted file mode 100644 index 1ed09c3485..0000000000 --- a/tests/resources/functions/dart/main.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'dart:io' show Platform; - -Future main(final context) async { - context.log('Amazing Function Log'); - - response.json({ - 'APPWRITE_FUNCTION_ID' : Platform.environment['APPWRITE_FUNCTION_ID'] ?? '', - 'APPWRITE_FUNCTION_NAME' : Platform.environment['APPWRITE_FUNCTION_NAME'] ?? '', - 'APPWRITE_FUNCTION_DEPLOYMENT' : Platform.environment['APPWRITE_FUNCTION_DEPLOYMENT'] ?? '', - 'APPWRITE_FUNCTION_TRIGGER' : context.req.headers['x-appwrite-trigger'] ?? '', - 'APPWRITE_FUNCTION_RUNTIME_NAME' : Platform.environment['APPWRITE_FUNCTION_RUNTIME_NAME'] ?? '', - 'APPWRITE_FUNCTION_RUNTIME_VERSION' : Platform.environment['APPWRITE_FUNCTION_RUNTIME_VERSION'] ?? '', - 'APPWRITE_FUNCTION_EVENT' : context.req.headers['x-appwrite-event'] ?? '', - 'APPWRITE_FUNCTION_EVENT_DATA' : context.req.bodyRaw ?? '', - 'APPWRITE_FUNCTION_DATA' : context.req.bodyRaw ?? '', - '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' : Platform.environment['APPWRITE_FUNCTION_PROJECT_ID'] ?? '', - 'CUSTOM_VARIABLE' : request.variables['CUSTOM_VARIABLE'] - }); -} \ No newline at end of file diff --git a/tests/resources/functions/php-v2/index.php b/tests/resources/functions/php-v2/index.php deleted file mode 100644 index 2bf5d83304..0000000000 --- a/tests/resources/functions/php-v2/index.php +++ /dev/null @@ -1,7 +0,0 @@ -json([ - 'v2Woks' => true - ]); -}; diff --git a/tests/resources/functions/python/main.py b/tests/resources/functions/python/main.py deleted file mode 100644 index fda0b36f0e..0000000000 --- a/tests/resources/functions/python/main.py +++ /dev/null @@ -1,21 +0,0 @@ -import json -import os - -def main(context): - context.log('Amazing Function Log') - - return context.res.json({ - 'APPWRITE_FUNCTION_ID' : os.environ.get('APPWRITE_FUNCTION_ID',''), - 'APPWRITE_FUNCTION_NAME' : os.environ.get('APPWRITE_FUNCTION_NAME',''), - 'APPWRITE_FUNCTION_DEPLOYMENT' : os.environ.get('APPWRITE_FUNCTION_DEPLOYMENT',''), - 'APPWRITE_FUNCTION_TRIGGER' : context.req.headers.get('x-appwrite-trigger', ''), - 'APPWRITE_FUNCTION_RUNTIME_NAME' : os.environ.get('APPWRITE_FUNCTION_RUNTIME_NAME',''), - 'APPWRITE_FUNCTION_RUNTIME_VERSION' : os.environ.get('APPWRITE_FUNCTION_RUNTIME_VERSION',''), - 'APPWRITE_FUNCTION_EVENT' : context.req.headers.get('x-appwrite-event', ''), - 'APPWRITE_FUNCTION_EVENT_DATA' : context.req.body_raw, - 'APPWRITE_FUNCTION_DATA' : context.req.body_raw, - 'APPWRITE_FUNCTION_USER_ID' : context.req.headers.get('x-appwrite-user-id', ''), - 'APPWRITE_FUNCTION_JWT' : context.req.headers.get('x-appwrite-user-jwt', ''), - 'APPWRITE_FUNCTION_PROJECT_ID' : os.environ.get('APPWRITE_FUNCTION_PROJECT_ID',''), - 'CUSTOM_VARIABLE' : os.environ.get('CUSTOM_VARIABLE',''), - }) \ No newline at end of file diff --git a/tests/resources/functions/ruby/main.rb b/tests/resources/functions/ruby/main.rb deleted file mode 100644 index c14f591fa1..0000000000 --- a/tests/resources/functions/ruby/main.rb +++ /dev/null @@ -1,19 +0,0 @@ -def main(context) - context.log('Amazing Function Log') - - return context.res.json({ - 'APPWRITE_FUNCTION_ID' => ENV['APPWRITE_FUNCTION_ID'] || '', - 'APPWRITE_FUNCTION_NAME' => ENV['APPWRITE_FUNCTION_NAME'] || '', - 'APPWRITE_FUNCTION_DEPLOYMENT' => ENV['APPWRITE_FUNCTION_DEPLOYMENT'] || '', - 'APPWRITE_FUNCTION_TRIGGER' => context.req.headers['x-appwrite-trigger'] || '', - 'APPWRITE_FUNCTION_RUNTIME_NAME' => ENV['APPWRITE_FUNCTION_RUNTIME_NAME'] || '', - 'APPWRITE_FUNCTION_RUNTIME_VERSION' => ENV['APPWRITE_FUNCTION_RUNTIME_VERSION'] || '', - 'APPWRITE_FUNCTION_EVENT' => context.req.headers['x-appwrite-event'] || '', - 'APPWRITE_FUNCTION_EVENT_DATA' => context.req.body_raw || '', - 'APPWRITE_FUNCTION_DATA' => context.req.body_raw || '', - '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' => ENV['APPWRITE_FUNCTION_PROJECT_ID'] || '', - 'CUSTOM_VARIABLE' => ENV['CUSTOM_VARIABLE'] || '' - }) -end \ No newline at end of file diff --git a/tests/resources/functions/swift/index.swift b/tests/resources/functions/swift/index.swift deleted file mode 100644 index b3dcdbc91a..0000000000 --- a/tests/resources/functions/swift/index.swift +++ /dev/null @@ -1,17 +0,0 @@ -func main(req: RequestValue, res: RequestResponse) throws -> RequestResponse { - return res.json(data: [ - "APPWRITE_FUNCTION_ID": req.variables["APPWRITE_FUNCTION_ID"], - "APPWRITE_FUNCTION_NAME": req.variables["APPWRITE_FUNCTION_NAME"], - "APPWRITE_FUNCTION_DEPLOYMENT": req.variables["APPWRITE_FUNCTION_DEPLOYMENT"], - "APPWRITE_FUNCTION_TRIGGER": req.variables["APPWRITE_FUNCTION_TRIGGER"], - "APPWRITE_FUNCTION_RUNTIME_NAME": req.variables["APPWRITE_FUNCTION_RUNTIME_NAME"], - "APPWRITE_FUNCTION_RUNTIME_VERSION": req.variables["APPWRITE_FUNCTION_RUNTIME_VERSION"], - "APPWRITE_FUNCTION_EVENT": req.variables["APPWRITE_FUNCTION_EVENT"], - "APPWRITE_FUNCTION_EVENT_DATA": req.variables["APPWRITE_FUNCTION_EVENT_DATA"], - "APPWRITE_FUNCTION_DATA": req.variables["APPWRITE_FUNCTION_DATA"], - "APPWRITE_FUNCTION_USER_ID": req.variables["APPWRITE_FUNCTION_USER_ID"], - "APPWRITE_FUNCTION_JWT": req.variables["APPWRITE_FUNCTION_JWT"], - "APPWRITE_FUNCTION_PROJECT_ID": req.variables["APPWRITE_FUNCTION_PROJECT_ID"], - "CUSTOM_VARIABLE": req.variables["CUSTOM_VARIABLE"] - ]) -} \ No newline at end of file From 1a3f8bbd4822e8c03229f44673ceb4e1a539887a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 9 Jul 2025 14:29:36 +0200 Subject: [PATCH 02/10] quality fixes --- .github/workflows/tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 57a1a1aefa..9ea04f596c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -178,7 +178,7 @@ jobs: - name: Load and Start Appwrite run: | docker load --input /tmp/${{ env.IMAGE }}.tar - sed -i 's/_APP_BROWSER_HOST=http:\/\/appwrite-browser:3000\/v1/_APP_BROWSER_HOST=http:\/\/invalid-browser\/v1/' .env + sed -i 's|^_APP_BROWSER_HOST=.*|_APP_BROWSER_HOST=http://invalid-browser/v1|' .env docker compose up -d sleep 30 @@ -199,7 +199,7 @@ jobs: docker compose exec -T \ -e _APP_DATABASE_SHARED_TABLES \ -e _APP_DATABASE_SHARED_TABLES_V1 \ - appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group devKeys screenshots + appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group devKeys,screenshots e2e_shared_mode_test: name: E2E Shared Mode Service Test @@ -278,7 +278,7 @@ jobs: docker compose exec -T \ -e _APP_DATABASE_SHARED_TABLES \ -e _APP_DATABASE_SHARED_TABLES_V1 \ - appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group devKeys screenshots + appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group devKeys,screenshots e2e_dev_keys: name: E2E Service Test (Dev Keys) From 5ace34790d21554e45558d86acb1cc5fb4de1dd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 9 Jul 2025 16:58:55 +0200 Subject: [PATCH 03/10] Migrate many tests to JS --- tests/e2e/General/UsageTest.php | 6 +- .../Functions/FunctionsConsoleClientTest.php | 4 +- .../Functions/FunctionsCustomClientTest.php | 36 +++---- .../Functions/FunctionsCustomServerTest.php | 98 +++++++++---------- .../FunctionsScheduleTest.php | 21 ++-- .../Services/GraphQL/FunctionsClientTest.php | 6 +- .../Services/GraphQL/FunctionsServerTest.php | 6 +- .../Services/Migrations/MigrationsBase.php | 7 +- tests/e2e/Services/Proxy/ProxyBase.php | 2 +- .../Realtime/RealtimeConsoleClientTest.php | 7 +- .../Realtime/RealtimeCustomClientTest.php | 7 +- .../functions/{node => basic}/index.js | 29 +++++- .../functions/{node => basic}/maintenance.js | 0 tests/resources/functions/cookies/index.js | 3 + .../functions/dynamic-api-key/index.js | 15 +++ .../dynamic-api-key/package-lock.json | 31 ++++++ .../functions/dynamic-api-key/package.json | 15 +++ .../{php-scopes => dynamic-api-key}/setup.sh | 3 +- .../functions/event-handler/index.js | 5 + .../resources/functions/php-cookie/index.php | 5 - tests/resources/functions/php-event/index.php | 8 -- tests/resources/functions/php-fn/index.php | 23 ----- .../functions/php-scopes/composer.json | 18 ---- .../resources/functions/php-scopes/index.php | 18 ---- tests/resources/functions/php/index.php | 39 -------- tests/resources/functions/timeout/index.js | 4 + tests/resources/functions/timeout/index.php | 6 -- 27 files changed, 193 insertions(+), 229 deletions(-) rename tests/resources/functions/{node => basic}/index.js (53%) rename tests/resources/functions/{node => basic}/maintenance.js (100%) create mode 100644 tests/resources/functions/cookies/index.js create mode 100644 tests/resources/functions/dynamic-api-key/index.js create mode 100644 tests/resources/functions/dynamic-api-key/package-lock.json create mode 100644 tests/resources/functions/dynamic-api-key/package.json rename tests/resources/functions/{php-scopes => dynamic-api-key}/setup.sh (94%) create mode 100644 tests/resources/functions/event-handler/index.js delete mode 100644 tests/resources/functions/php-cookie/index.php delete mode 100644 tests/resources/functions/php-event/index.php delete mode 100644 tests/resources/functions/php-fn/index.php delete mode 100644 tests/resources/functions/php-scopes/composer.json delete mode 100644 tests/resources/functions/php-scopes/index.php delete mode 100644 tests/resources/functions/php/index.php create mode 100644 tests/resources/functions/timeout/index.js delete mode 100644 tests/resources/functions/timeout/index.php diff --git a/tests/e2e/General/UsageTest.php b/tests/e2e/General/UsageTest.php index 6ff9dafada..6389258e3a 100644 --- a/tests/e2e/General/UsageTest.php +++ b/tests/e2e/General/UsageTest.php @@ -675,7 +675,8 @@ class UsageTest extends Scope [ 'functionId' => 'unique()', 'name' => 'Test', - 'runtime' => 'php-8.0', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'vars' => [ 'funcKey1' => 'funcValue1', 'funcKey2' => 'funcValue2', @@ -697,8 +698,7 @@ class UsageTest extends Scope $this->assertNotEmpty($response['body']['$id']); $deploymentId = $this->setupDeployment($functionId, [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php'), + 'code' => $this->packageFunction('basic'), 'activate' => true, ]); $this->assertNotEmpty($deploymentId); diff --git a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php index 24215f5352..b8b064f077 100644 --- a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php +++ b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php @@ -481,7 +481,7 @@ class FunctionsConsoleClientTest extends Scope $deploymentId = $this->setupDeployment($functionId, [ 'entrypoint' => 'index.js', - 'code' => $this->packageFunction('node'), + 'code' => $this->packageFunction('generic'), 'activate' => true ]); @@ -511,7 +511,7 @@ class FunctionsConsoleClientTest extends Scope $deploymentId = $this->setupDeployment($functionId, [ 'entrypoint' => 'index.js', - 'code' => $this->packageFunction('node'), + 'code' => $this->packageFunction('generic'), 'activate' => true ]); diff --git a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php index a47bc62d47..6fae88fcd2 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php @@ -43,8 +43,8 @@ class FunctionsCustomClientTest extends Scope 'functionId' => ID::unique(), 'name' => 'Test', 'execute' => [Role::user($this->getUser()['$id'])->toString()], - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'events' => [ 'users.*.create', 'users.*.delete', @@ -52,8 +52,7 @@ class FunctionsCustomClientTest extends Scope 'timeout' => 10, ]); $this->setupDeployment($functionId, [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); @@ -82,15 +81,14 @@ class FunctionsCustomClientTest extends Scope */ $functionId = $this->setupFunction([ 'functionId' => ID::unique(), - 'name' => 'Test', + 'name' => 'Test ', 'execute' => [Role::any()->toString()], - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'timeout' => 10, ]); $deploymentId = $this->setupDeployment($functionId, [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php-fn'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); @@ -142,10 +140,10 @@ class FunctionsCustomClientTest extends Scope */ $functionId = $this->setupFunction([ 'functionId' => ID::unique(), - 'name' => 'Test', + 'name' => 'Test guest execution', 'execute' => [Role::any()->toString()], - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'vars' => [ 'funcKey1' => 'funcValue1', 'funcKey2' => 'funcValue2', @@ -154,8 +152,7 @@ class FunctionsCustomClientTest extends Scope 'timeout' => 10, ]); $this->setupDeployment($functionId, [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php-fn'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); @@ -193,15 +190,14 @@ class FunctionsCustomClientTest extends Scope */ $functionId = $this->setupFunction([ 'functionId' => ID::unique(), - 'name' => 'Test', + 'name' => 'Test synchronous execution', 'execute' => [Role::any()->toString()], - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'timeout' => 10, ]); $deploymentId = $this->setupDeployment($functionId, [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php-fn'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); @@ -244,7 +240,7 @@ class FunctionsCustomClientTest extends Scope ]); $this->setupDeployment($functionId, [ 'entrypoint' => 'index.js', - 'code' => $this->packageFunction('node'), + 'code' => $this->packageFunction('generic'), 'activate' => true ]); diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index 846ca37262..d562e52e52 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -322,8 +322,8 @@ class FunctionsCustomServerTest extends Scope 'functionId' => ID::unique(), 'name' => 'Test', 'execute' => [Role::user($this->getUser()['$id'])->toString()], - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'events' => [ 'users.*.create', 'users.*.delete', @@ -338,8 +338,7 @@ class FunctionsCustomServerTest extends Scope 'x-appwrite-key' => $this->getProject()['apiKey'], 'x-sdk-language' => 'cli', ], [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); @@ -514,7 +513,7 @@ class FunctionsCustomServerTest extends Scope $functionId = $data['functionId']; $deployment = $this->createDeployment($functionId, [ - 'code' => $this->packageFunction('php'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); @@ -533,7 +532,7 @@ class FunctionsCustomServerTest extends Scope }, 50000, 500); $deployment = $this->createDeployment($functionId, [ - 'code' => $this->packageFunction('php'), + 'code' => $this->packageFunction('basic'), 'activate' => 'false' ]); @@ -573,7 +572,7 @@ class FunctionsCustomServerTest extends Scope $functionId = $data['functionId']; $deployment = $this->createDeployment($functionId, [ - 'code' => $this->packageFunction('php'), + 'code' => $this->packageFunction('basic'), 'activate' => 'false' ]); @@ -1236,9 +1235,9 @@ class FunctionsCustomServerTest extends Scope { $functionId = $this->setupFunction([ 'functionId' => ID::unique(), - 'name' => 'Test php-8.0', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'name' => 'Test timeout execution', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'events' => [], 'schedule' => '', 'timeout' => 5, // Should timeout after 5 seconds @@ -1344,7 +1343,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEmpty($output['APPWRITE_FUNCTION_USER_ID']); $this->assertEmpty($output['APPWRITE_FUNCTION_JWT']); $this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']); - $this->assertStringContainsString('Amazing Function Log', $execution['body']['logs']); + $this->assertStringContainsString('log-works', $execution['body']['logs']); $this->assertEmpty($execution['body']['errors']); $executionId = $execution['body']['$id'] ?? ''; @@ -1357,7 +1356,7 @@ class FunctionsCustomServerTest extends Scope $this->assertCount(1, $executions['body']['executions']); $this->assertEquals($executions['body']['executions'][0]['$id'], $executionId); $this->assertEquals($executions['body']['executions'][0]['trigger'], 'http'); - $this->assertStringContainsString('Amazing Function Log', $executions['body']['executions'][0]['logs']); + $this->assertStringContainsString('log-works', $executions['body']['executions'][0]['logs']); $this->cleanupFunction($functionId); } @@ -1488,17 +1487,16 @@ class FunctionsCustomServerTest extends Scope { $functionId = $this->setupFunction([ 'functionId' => ID::unique(), - 'name' => 'Test PHP Event executions', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'name' => 'Test Event executions', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'events' => [ 'users.*.create', ], 'timeout' => 15, ]); $this->setupDeployment($functionId, [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php-event'), + 'code' => $this->packageFunction('event-handler'), 'activate' => true ]); @@ -1541,17 +1539,16 @@ class FunctionsCustomServerTest extends Scope { $functionId = $this->setupFunction([ 'functionId' => ID::unique(), - 'name' => 'Test PHP Scopes executions', - 'commands' => 'bash setup.sh && composer install', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'name' => 'Test Scopes executions', + 'commands' => 'bash setup.sh && npm install', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'scopes' => ['users.read'], 'timeout' => 15, ]); $deploymentId = $this->setupDeployment($functionId, [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php-scopes'), + 'code' => $this->packageFunction('dynamic-api-key'), 'activate' => true, ]); @@ -1600,16 +1597,15 @@ class FunctionsCustomServerTest extends Scope { $functionId = $this->setupFunction([ 'functionId' => ID::unique(), - 'name' => 'Test PHP Cookie executions', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'name' => 'Test Cookie executions', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'timeout' => 15, ]); $this->assertNotEmpty($functionId); $deploymentId = $this->setupDeployment($functionId, [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php-cookie'), + 'code' => $this->packageFunction('cookies'), 'activate' => true ]); $this->assertNotEmpty($deploymentId); @@ -1642,9 +1638,9 @@ class FunctionsCustomServerTest extends Scope { $functionId = $this->setupFunction([ 'functionId' => ID::unique(), - 'name' => 'Test PHP Cookie executions', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'name' => 'Test Cookie executions', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'timeout' => 15, 'execute' => ['any'] ]); @@ -1652,8 +1648,7 @@ class FunctionsCustomServerTest extends Scope $domain = $this->setupFunctionDomain($functionId); $this->setupDeployment($functionId, [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php-cookie'), + 'code' => $this->packageFunction('cookies'), 'activate' => true ]); @@ -1865,7 +1860,7 @@ class FunctionsCustomServerTest extends Scope $domain = $this->setupFunctionDomain($functionId); $this->setupDeployment($functionId, [ - 'code' => $this->packageFunction('node'), + 'code' => $this->packageFunction('generic'), 'activate' => true ]); @@ -1958,7 +1953,7 @@ class FunctionsCustomServerTest extends Scope $functionId = $functionId = $function['body']['$id'] ?? ''; $deploymentId = $this->setupDeployment($functionId, [ - 'code' => $this->packageFunction('node'), + 'code' => $this->packageFunction('generic'), 'activate' => true ]); @@ -1992,7 +1987,7 @@ class FunctionsCustomServerTest extends Scope $this->assertNotEmpty($functionId); $deploymentId1 = $this->setupDeployment($functionId, [ - 'code' => $this->packageFunction('node'), + 'code' => $this->packageFunction('generic'), 'activate' => true ]); $this->assertNotEmpty($deploymentId1); @@ -2046,13 +2041,12 @@ class FunctionsCustomServerTest extends Scope $functionId = $this->setupFunction([ 'functionId' => ID::unique(), - 'runtime' => 'php-8.0', + 'runtime' => 'node-22', 'name' => 'Re-activate Test', - 'entrypoint' => 'index.php', + 'entrypoint' => 'index.js', ]); $this->assertNotEmpty($functionId); - $function = $this->getFunction($functionId); $this->assertEquals(200, $function['headers']['status-code']); $this->assertArrayHasKey('latestDeploymentId', $function['body']); @@ -2063,7 +2057,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEmpty($function['body']['latestDeploymentStatus']); $deploymentId1 = $this->setupDeployment($functionId, [ - 'code' => $this->packageFunction('php-cookie'), + 'code' => $this->packageFunction('cookies'), 'activate' => true ]); $this->assertNotEmpty($deploymentId1); @@ -2081,7 +2075,7 @@ class FunctionsCustomServerTest extends Scope $this->assertStringContainsString('cookieValue', $execution['body']['responseBody']); $deploymentId2 = $this->setupDeployment($functionId, [ - 'code' => $this->packageFunction('php'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); $this->assertNotEmpty($deploymentId2); @@ -2149,8 +2143,8 @@ class FunctionsCustomServerTest extends Scope $functionId = $this->setupFunction([ 'functionId' => ID::unique(), 'name' => 'Test Error Pages', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'timeout' => 15, 'commands' => 'cd non-existing-directory', 'execute' => ['any'] @@ -2160,8 +2154,7 @@ class FunctionsCustomServerTest extends Scope $proxyClient->setEndpoint('http://' . $domain); $deployment = $this->createDeployment($functionId, [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); @@ -2178,8 +2171,7 @@ class FunctionsCustomServerTest extends Scope // canceled deployment $deployment = $this->createDeployment($functionId, [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); @@ -2207,8 +2199,8 @@ class FunctionsCustomServerTest extends Scope $functionId = $this->setupFunction([ 'functionId' => ID::unique(), 'name' => 'Test Error Pages', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'timeout' => 15, 'commands' => '', 'execute' => ['users'] @@ -2219,7 +2211,7 @@ class FunctionsCustomServerTest extends Scope $proxyClient->setEndpoint('http://' . $domain); $deploymentId = $this->setupDeployment($functionId, [ - 'code' => $this->packageFunction('php'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); $this->assertNotEmpty($deploymentId); @@ -2241,8 +2233,8 @@ class FunctionsCustomServerTest extends Scope $functionId = $this->setupFunction([ 'functionId' => ID::unique(), 'name' => 'Test Error Pages', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'timeout' => 15, 'commands' => '', 'execute' => ['any'] @@ -2253,7 +2245,7 @@ class FunctionsCustomServerTest extends Scope $proxyClient->setEndpoint('http://' . $domain); $deploymentId = $this->setupDeployment($functionId, [ - 'code' => $this->packageFunction('php'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); $this->assertNotEmpty($deploymentId); diff --git a/tests/e2e/Services/FunctionsSchedule/FunctionsScheduleTest.php b/tests/e2e/Services/FunctionsSchedule/FunctionsScheduleTest.php index 4f4b0c960d..c3dd2c7fc8 100644 --- a/tests/e2e/Services/FunctionsSchedule/FunctionsScheduleTest.php +++ b/tests/e2e/Services/FunctionsSchedule/FunctionsScheduleTest.php @@ -25,8 +25,8 @@ class FunctionsScheduleTest extends Scope 'functionId' => ID::unique(), 'name' => 'Test', 'execute' => [Role::user($this->getUser()['$id'])->toString()], - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'events' => [ 'users.*.create', 'users.*.delete', @@ -36,8 +36,7 @@ class FunctionsScheduleTest extends Scope ]); $this->setupDeployment($functionId, [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); @@ -77,14 +76,13 @@ class FunctionsScheduleTest extends Scope 'functionId' => ID::unique(), 'name' => 'Test', 'execute' => [Role::user($this->getUser()['$id'])->toString()], - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'timeout' => 10, 'logging' => true, ]); $this->setupDeployment($functionId, [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); @@ -179,15 +177,14 @@ class FunctionsScheduleTest extends Scope 'functionId' => ID::unique(), 'name' => 'Test', 'execute' => [Role::user($this->getUser()['$id'])->toString()], - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'timeout' => 10, 'logging' => true, ]); $this->setupDeployment($functionId, [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); diff --git a/tests/e2e/Services/GraphQL/FunctionsClientTest.php b/tests/e2e/Services/GraphQL/FunctionsClientTest.php index 14b714d551..ea2723b803 100644 --- a/tests/e2e/Services/GraphQL/FunctionsClientTest.php +++ b/tests/e2e/Services/GraphQL/FunctionsClientTest.php @@ -26,8 +26,8 @@ class FunctionsClientTest extends Scope 'variables' => [ 'functionId' => ID::unique(), 'name' => 'Test Function', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'execute' => [Role::any()->toString()], ] ]; @@ -96,7 +96,7 @@ class FunctionsClientTest extends Scope 'map' => \json_encode([ 'code' => ["variables.code"] ]), - 'code' => $this->packageFunction('php') + 'code' => $this->packageFunction('basic') ]; $deployment = $this->client->call(Client::METHOD_POST, '/graphql', [ diff --git a/tests/e2e/Services/GraphQL/FunctionsServerTest.php b/tests/e2e/Services/GraphQL/FunctionsServerTest.php index d211dcceea..de419ebf0e 100644 --- a/tests/e2e/Services/GraphQL/FunctionsServerTest.php +++ b/tests/e2e/Services/GraphQL/FunctionsServerTest.php @@ -26,8 +26,8 @@ class FunctionsServerTest extends Scope 'variables' => [ 'functionId' => ID::unique(), 'name' => 'Test Function', - 'entrypoint' => 'index.php', - 'runtime' => 'php-8.0', + 'entrypoint' => 'index.js', + 'runtime' => 'node-22', 'execute' => [Role::any()->toString()], ] ]; @@ -95,7 +95,7 @@ class FunctionsServerTest extends Scope 'map' => \json_encode([ 'code' => ["variables.code"] ]), - 'code' => $this->packageFunction('php'), + 'code' => $this->packageFunction('basic'), ]; $deployment = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ diff --git a/tests/e2e/Services/Migrations/MigrationsBase.php b/tests/e2e/Services/Migrations/MigrationsBase.php index b8b9439e64..0b8f75b804 100644 --- a/tests/e2e/Services/Migrations/MigrationsBase.php +++ b/tests/e2e/Services/Migrations/MigrationsBase.php @@ -805,13 +805,12 @@ trait MigrationsBase $functionId = $this->setupFunction([ 'functionId' => ID::unique(), 'name' => 'Test', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php' + 'runtime' => 'node-22', + 'entrypoint' => 'index.js' ]); $deploymentId = $this->setupDeployment($functionId, [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); diff --git a/tests/e2e/Services/Proxy/ProxyBase.php b/tests/e2e/Services/Proxy/ProxyBase.php index 9f8e92d56f..b04a8594cb 100644 --- a/tests/e2e/Services/Proxy/ProxyBase.php +++ b/tests/e2e/Services/Proxy/ProxyBase.php @@ -244,7 +244,7 @@ trait ProxyBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ - 'code' => $this->packageFunction('node'), + 'code' => $this->packageFunction('generic'), 'activate' => 'true' ]); diff --git a/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php b/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php index 1f60f9fde6..80b4ae46d2 100644 --- a/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php +++ b/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php @@ -524,8 +524,8 @@ class RealtimeConsoleClientTest extends Scope ], $this->getHeaders()), [ 'functionId' => ID::unique(), 'name' => 'Test', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'events' => [ 'users.*.create', 'users.*.delete', @@ -564,8 +564,7 @@ class RealtimeConsoleClientTest extends Scope 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $projectId, ], $this->getHeaders()), [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); diff --git a/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php b/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php index b35dae4e7f..25a5488046 100644 --- a/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php +++ b/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php @@ -1285,10 +1285,10 @@ class RealtimeCustomClientTest extends Scope 'x-appwrite-key' => $this->getProject()['apiKey'] ], [ 'functionId' => ID::unique(), - 'name' => 'Test', + 'name' => 'Test timeout execution', 'execute' => ['users'], - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'timeout' => 10, ]); @@ -1302,7 +1302,6 @@ class RealtimeCustomClientTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ - 'entrypoint' => 'index.php', 'code' => $this->packageFunction('timeout'), 'activate' => true ]); diff --git a/tests/resources/functions/node/index.js b/tests/resources/functions/basic/index.js similarity index 53% rename from tests/resources/functions/node/index.js rename to tests/resources/functions/basic/index.js index e8eb938a15..b35c2a724d 100644 --- a/tests/resources/functions/node/index.js +++ b/tests/resources/functions/basic/index.js @@ -1,5 +1,26 @@ module.exports = async(context) => { - context.log('Amazing Function Log'); + context.log('log-works'); + context.error('error-log-works'); + + if(context.req.headers['x-appwrite-user-jwt']) { + context.log('jwt-is-invalid'); + } else { + context.log('jwt-is-valid'); + } + + if(context.req.path === '/custom-response') { + const code = +(context.req.query['code'] || '200'); + const body = context.req.query['body'] || ''; + return context.res.send(body, code); + } + + context.log('body-is-' + (context.req.body ?? '')); + context.log('custom-header-is-' + (context.req.headers['x-custom-header'] ?? '')); + context.log('method-is-' + (context.req.method ?? '').toLowerCase()); + context.log('path-is-' + (context.req.path ?? '')); + context.log('user-is-' + context.req.headers['x-appwrite-user-id'] ?? ''); + + const statusCode = context.req.query['code'] || '200'; return context.res.json({ 'APPWRITE_FUNCTION_ID' : process.env.APPWRITE_FUNCTION_ID ?? '', @@ -8,6 +29,10 @@ module.exports = async(context) => { 'APPWRITE_FUNCTION_TRIGGER' : context.req.headers['x-appwrite-trigger'] ?? '', 'APPWRITE_FUNCTION_RUNTIME_NAME' : process.env.APPWRITE_FUNCTION_RUNTIME_NAME, 'APPWRITE_FUNCTION_RUNTIME_VERSION' : process.env.APPWRITE_FUNCTION_RUNTIME_VERSION, + 'APPWRITE_VERSION' : process.env.APPWRITE_VERSION ?? '', + 'APPWRITE_REGION' : process.env.APPWRITE_REGION ?? '', + 'UNICODE_TEST' : "êä", + 'GLOBAL_VARIABLE' : process.env.GLOBAL_VARIABLE ?? '', 'APPWRITE_FUNCTION_EVENT' : context.req.headers['x-appwrite-event'] ?? '', 'APPWRITE_FUNCTION_EVENT_DATA' : context.req.bodyRaw ?? '', 'APPWRITE_FUNCTION_DATA' : context.req.bodyRaw ?? '', @@ -17,5 +42,5 @@ module.exports = async(context) => { 'APPWRITE_FUNCTION_MEMORY' : process.env.APPWRITE_FUNCTION_MEMORY, 'APPWRITE_FUNCTION_CPUS' : process.env.APPWRITE_FUNCTION_CPUS, 'CUSTOM_VARIABLE' : process.env.CUSTOM_VARIABLE - }); + }, +statusCode); } \ No newline at end of file diff --git a/tests/resources/functions/node/maintenance.js b/tests/resources/functions/basic/maintenance.js similarity index 100% rename from tests/resources/functions/node/maintenance.js rename to tests/resources/functions/basic/maintenance.js diff --git a/tests/resources/functions/cookies/index.js b/tests/resources/functions/cookies/index.js new file mode 100644 index 0000000000..dd5dd7bd19 --- /dev/null +++ b/tests/resources/functions/cookies/index.js @@ -0,0 +1,3 @@ +module.exports = async(context) => { + return context.res.send(context.req.headers['cookie'] ?? ''); +}; diff --git a/tests/resources/functions/dynamic-api-key/index.js b/tests/resources/functions/dynamic-api-key/index.js new file mode 100644 index 0000000000..6c98f819c6 --- /dev/null +++ b/tests/resources/functions/dynamic-api-key/index.js @@ -0,0 +1,15 @@ +const sdk = require('node-appwrite'); + +module.exports = async(context) => { + const client = new sdk.Client(); + client.setEndpoint(process.env.APPWRITE_FUNCTION_API_ENDPOINT); + client.setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID); + client.setKey(context.req.headers['x-appwrite-key']); + + const users = new sdk.Users(client); + + const response = await users.list(); + context.log(JSON.stringify(response)); + + return context.res.json(response); +}; diff --git a/tests/resources/functions/dynamic-api-key/package-lock.json b/tests/resources/functions/dynamic-api-key/package-lock.json new file mode 100644 index 0000000000..2d86fe18d3 --- /dev/null +++ b/tests/resources/functions/dynamic-api-key/package-lock.json @@ -0,0 +1,31 @@ +{ + "name": "dynamic-api-key", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "dynamic-api-key", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "node-appwrite": "^17.0.0" + } + }, + "node_modules/node-appwrite": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/node-appwrite/-/node-appwrite-17.0.0.tgz", + "integrity": "sha512-5Moi5ENPnoAfU1/6CZP9K2NTuB6Nm3dSyhokno+24RDuP7czjXCdwzfeyjmyHieggbrLkN89AYSOv9W1XkCL9w==", + "license": "BSD-3-Clause", + "dependencies": { + "node-fetch-native-with-agent": "1.7.2" + } + }, + "node_modules/node-fetch-native-with-agent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/node-fetch-native-with-agent/-/node-fetch-native-with-agent-1.7.2.tgz", + "integrity": "sha512-5MaOOCuJEvcckoz7/tjdx1M6OusOY6Xc5f459IaruGStWnKzlI1qpNgaAwmn4LmFYcsSlj+jBMk84wmmRxfk5g==", + "license": "MIT" + } + } +} diff --git a/tests/resources/functions/dynamic-api-key/package.json b/tests/resources/functions/dynamic-api-key/package.json new file mode 100644 index 0000000000..19b8158131 --- /dev/null +++ b/tests/resources/functions/dynamic-api-key/package.json @@ -0,0 +1,15 @@ +{ + "name": "dynamic-api-key", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "node-appwrite": "^17.0.0" + } +} diff --git a/tests/resources/functions/php-scopes/setup.sh b/tests/resources/functions/dynamic-api-key/setup.sh similarity index 94% rename from tests/resources/functions/php-scopes/setup.sh rename to tests/resources/functions/dynamic-api-key/setup.sh index a2f78a4f3d..c0bb3cec58 100644 --- a/tests/resources/functions/php-scopes/setup.sh +++ b/tests/resources/functions/dynamic-api-key/setup.sh @@ -1,6 +1,7 @@ - ENDPOINT="$APPWRITE_FUNCTION_API_ENDPOINT/users" PROJECT_ID="$APPWRITE_FUNCTION_PROJECT_ID" API_KEY="$APPWRITE_FUNCTION_API_KEY" +apk add curl + curl -v -X GET $ENDPOINT -H "x-appwrite-project: $PROJECT_ID" -H "x-appwrite-key: $API_KEY" \ No newline at end of file diff --git a/tests/resources/functions/event-handler/index.js b/tests/resources/functions/event-handler/index.js new file mode 100644 index 0000000000..6df3b7fb35 --- /dev/null +++ b/tests/resources/functions/event-handler/index.js @@ -0,0 +1,5 @@ +module.exports = async(context) => { + context.log(context.req.body.$id); + context.log(context.req.body.name); + return context.res.empty(); +}; diff --git a/tests/resources/functions/php-cookie/index.php b/tests/resources/functions/php-cookie/index.php deleted file mode 100644 index 8f38f752cb..0000000000 --- a/tests/resources/functions/php-cookie/index.php +++ /dev/null @@ -1,5 +0,0 @@ -res->send($context->req->headers['cookie'] ?? ''); -}; diff --git a/tests/resources/functions/php-event/index.php b/tests/resources/functions/php-event/index.php deleted file mode 100644 index 550fd57729..0000000000 --- a/tests/resources/functions/php-event/index.php +++ /dev/null @@ -1,8 +0,0 @@ -log($context->req->body['$id']); - $context->log($context->req->body['name']); - - return $context->res->empty(); -}; diff --git a/tests/resources/functions/php-fn/index.php b/tests/resources/functions/php-fn/index.php deleted file mode 100644 index 0b6e3d206c..0000000000 --- a/tests/resources/functions/php-fn/index.php +++ /dev/null @@ -1,23 +0,0 @@ -log('Amazing Function Log'); - - return $context->res->json([ - 'APPWRITE_FUNCTION_ID' => \getenv('APPWRITE_FUNCTION_ID') ?: '', - 'APPWRITE_FUNCTION_NAME' => \getenv('APPWRITE_FUNCTION_NAME') ?: '', - 'APPWRITE_FUNCTION_DEPLOYMENT' => \getenv('APPWRITE_FUNCTION_DEPLOYMENT') ?: '', - 'APPWRITE_FUNCTION_TRIGGER' => $context->req->headers['x-appwrite-trigger'] ?? '', - 'APPWRITE_FUNCTION_RUNTIME_NAME' => \getenv('APPWRITE_FUNCTION_RUNTIME_NAME') ?: '', - 'APPWRITE_FUNCTION_RUNTIME_VERSION' => \getenv('APPWRITE_FUNCTION_RUNTIME_VERSION') ?: '', - 'APPWRITE_VERSION' => \getenv('APPWRITE_VERSION') ?: '', - 'APPWRITE_REGION' => \getenv('APPWRITE_REGION') ?: '', - 'APPWRITE_FUNCTION_EVENT' => $context->req->headers['x-appwrite-event'] ?? '', - 'APPWRITE_FUNCTION_EVENT_DATA' => $context->req->bodyRaw ?? '', - 'APPWRITE_FUNCTION_DATA' => $context->req->bodyRaw ?? '', - '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' => \getenv('APPWRITE_FUNCTION_PROJECT_ID') ?: '', - 'CUSTOM_VARIABLE' => \getenv('CUSTOM_VARIABLE') ?: '', - ]); -}; diff --git a/tests/resources/functions/php-scopes/composer.json b/tests/resources/functions/php-scopes/composer.json deleted file mode 100644 index 8eacdab3ec..0000000000 --- a/tests/resources/functions/php-scopes/composer.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "appwrite/php-scopes", - "description": "PHP scopes test script", - "type": "library", - "license": "BSD-3-Clause", - "authors": [ - { - "name": "Team Appwrite", - "email": "team@appwrite.io" - } - ], - "require": { - "php": ">=7.4.0", - "ext-curl": "*", - "ext-json": "*", - "appwrite/appwrite": "11.0.*" - } -} diff --git a/tests/resources/functions/php-scopes/index.php b/tests/resources/functions/php-scopes/index.php deleted file mode 100644 index 905d924eb7..0000000000 --- a/tests/resources/functions/php-scopes/index.php +++ /dev/null @@ -1,18 +0,0 @@ -setEndpoint(getenv('APPWRITE_FUNCTION_API_ENDPOINT')) - ->setProject(getenv('APPWRITE_FUNCTION_PROJECT_ID')) - ->setKey($context->req->headers['x-appwrite-key']); - $users = new Users($client); - $response = $users->list(); - $context->log($response); - return $context->res->json($response); -}; diff --git a/tests/resources/functions/php/index.php b/tests/resources/functions/php/index.php deleted file mode 100644 index 6c67f27ee1..0000000000 --- a/tests/resources/functions/php/index.php +++ /dev/null @@ -1,39 +0,0 @@ -req->path === '/custom-response') { - $code = (int) ($context->req->query['code'] ?? '200'); - $body = $context->req->query['body'] ?? ''; - return $context->res->send($body, $code); - } - - $context->log('body-is-' . ($context->req->body ?? '')); - $context->log('custom-header-is-' . ($context->req->headers['x-custom-header'] ?? '')); - $context->log('method-is-' . \strtolower($context->req->method ?? '')); - $context->log('path-is-' . ($context->req->path ?? '')); - $context->log('user-is-' . $context->req->headers['x-appwrite-user-id'] ?? ''); - - if (empty($context->req->headers['x-appwrite-user-jwt'] ?? '')) { - $context->log('jwt-is-invalid'); - } else { - $context->log('jwt-is-valid'); - } - - $context->error('error-log-works'); - - $statusCode = $context->req->query['code'] ?? '200'; - - return $context->res->json([ - 'APPWRITE_FUNCTION_ID' => \getenv('APPWRITE_FUNCTION_ID') ?: '', - 'APPWRITE_FUNCTION_NAME' => \getenv('APPWRITE_FUNCTION_NAME') ?: '', - 'APPWRITE_FUNCTION_DEPLOYMENT' => \getenv('APPWRITE_FUNCTION_DEPLOYMENT') ?: '', - 'APPWRITE_FUNCTION_TRIGGER' => $context->req->headers['x-appwrite-trigger'] ?? '', - 'APPWRITE_FUNCTION_RUNTIME_NAME' => \getenv('APPWRITE_FUNCTION_RUNTIME_NAME') ?: '', - 'APPWRITE_FUNCTION_RUNTIME_VERSION' => \getenv('APPWRITE_FUNCTION_RUNTIME_VERSION') ?: '', - 'APPWRITE_REGION' => \getenv('APPWRITE_REGION') ?: '', - 'UNICODE_TEST' => "êä", - 'GLOBAL_VARIABLE' => \getenv('GLOBAL_VARIABLE') ?: '', - 'APPWRITE_FUNCTION_CPUS' => \getenv('APPWRITE_FUNCTION_CPUS') ?: '', - 'APPWRITE_FUNCTION_MEMORY' => \getenv('APPWRITE_FUNCTION_MEMORY') ?: '', - ], \intval($statusCode)); -}; diff --git a/tests/resources/functions/timeout/index.js b/tests/resources/functions/timeout/index.js new file mode 100644 index 0000000000..45ad72a323 --- /dev/null +++ b/tests/resources/functions/timeout/index.js @@ -0,0 +1,4 @@ +module.exports = async(context) => { + await new Promise(resolve => setTimeout(resolve, 1000 * 60)); + return context.res.send('OK'); +}; diff --git a/tests/resources/functions/timeout/index.php b/tests/resources/functions/timeout/index.php deleted file mode 100644 index c9aedb3a30..0000000000 --- a/tests/resources/functions/timeout/index.php +++ /dev/null @@ -1,6 +0,0 @@ -res->send('OK'); -}; From eaf9b8b228fd1cd6dd0a067e06e21ee890e4f2b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 10 Jul 2025 12:55:45 +0200 Subject: [PATCH 04/10] Migrate remaining tests to node --- composer.lock | 4 +- .../Functions/FunctionsCustomServerTest.php | 104 +++++++++--------- tests/resources/functions/basic/index.js | 6 +- .../functions/binary-request/index.js | 6 + .../functions/binary-response/index.js | 4 + .../functions/{php-large => large}/blue.mp4 | Bin tests/resources/functions/large/index.js | 3 + .../functions/php-binary-request/index.php | 6 - .../functions/php-binary-response/index.php | 6 - .../functions/php-large/composer.json | 18 --- .../functions/php-large/composer.lock | 64 ----------- tests/resources/functions/php-large/index.php | 16 --- 12 files changed, 68 insertions(+), 169 deletions(-) create mode 100644 tests/resources/functions/binary-request/index.js create mode 100644 tests/resources/functions/binary-response/index.js rename tests/resources/functions/{php-large => large}/blue.mp4 (100%) create mode 100644 tests/resources/functions/large/index.js delete mode 100644 tests/resources/functions/php-binary-request/index.php delete mode 100644 tests/resources/functions/php-binary-response/index.php delete mode 100644 tests/resources/functions/php-large/composer.json delete mode 100644 tests/resources/functions/php-large/composer.lock delete mode 100644 tests/resources/functions/php-large/index.php diff --git a/composer.lock b/composer.lock index 653d1841d5..ec39039b91 100644 --- a/composer.lock +++ b/composer.lock @@ -8239,7 +8239,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -8263,5 +8263,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index d562e52e52..4d0646b12e 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -35,7 +35,7 @@ class FunctionsCustomServerTest extends Scope $function = $this->createFunction([ 'functionId' => ID::unique(), 'name' => 'Specs function', - 'runtime' => 'php-8.0', + 'runtime' => 'node-22', 'specification' => $specifications['body']['specifications'][0]['slug'] ]); $this->assertEquals(201, $function['headers']['status-code']); @@ -50,7 +50,7 @@ class FunctionsCustomServerTest extends Scope $function = $this->createFunction([ 'functionId' => ID::unique(), 'name' => 'Specs function', - 'runtime' => 'php-8.0', + 'runtime' => 'node-22', 'specification' => 'cheap-please' ]); $this->assertEquals(400, $function['headers']['status-code']); @@ -64,8 +64,8 @@ class FunctionsCustomServerTest extends Scope $function = $this->createFunction([ 'functionId' => ID::unique(), 'name' => 'Test', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'events' => [ 'buckets.*.create', 'buckets.*.delete', @@ -79,7 +79,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(201, $function['headers']['status-code']); $this->assertNotEmpty($function['body']['$id']); $this->assertEquals('Test', $function['body']['name']); - $this->assertEquals('php-8.0', $function['body']['runtime']); + $this->assertEquals('node-22', $function['body']['runtime']); $this->assertEquals(true, $dateValidator->isValid($function['body']['$createdAt'])); $this->assertEquals(true, $dateValidator->isValid($function['body']['$updatedAt'])); $this->assertEquals('', $function['body']['deploymentId']); @@ -180,7 +180,7 @@ class FunctionsCustomServerTest extends Scope // Test search runtime $functions = $this->listFunctions([ - 'search' => 'php-8.0' + 'search' => 'node-22' ]); $this->assertEquals($functions['headers']['status-code'], 200); @@ -193,8 +193,8 @@ class FunctionsCustomServerTest extends Scope $this->setupFunction([ 'functionId' => ID::unique(), 'name' => 'Test 2', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'events' => [ 'buckets.*.create', 'buckets.*.delete', @@ -286,8 +286,8 @@ class FunctionsCustomServerTest extends Scope ], 'schedule' => '0 0 1 1 *', 'timeout' => 15, - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', ]); $dateValidator = new DatetimeValidator(); @@ -362,7 +362,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(200, $starterTemplate['headers']['status-code']); $phpRuntime = array_values(array_filter($starterTemplate['body']['runtimes'], function ($runtime) { - return $runtime['name'] === 'php-8.0'; + return $runtime['name'] === 'node-22'; }))[0]; // If this fails, the template has variables, and this test needs to be updated @@ -372,7 +372,7 @@ class FunctionsCustomServerTest extends Scope [ 'functionId' => ID::unique(), 'name' => $starterTemplate['body']['name'], - 'runtime' => 'php-8.0', + 'runtime' => 'node-22', 'execute' => $starterTemplate['body']['permissions'], 'entrypoint' => $phpRuntime['entrypoint'], 'events' => $starterTemplate['body']['events'], @@ -521,7 +521,7 @@ class FunctionsCustomServerTest extends Scope $this->assertNotEmpty($deployment['body']['$id']); $this->assertEquals('waiting', $deployment['body']['status']); $this->assertEquals(true, (new DatetimeValidator())->isValid($deployment['body']['$createdAt'])); - $this->assertEquals('index.php', $deployment['body']['entrypoint']); + $this->assertEquals('index.js', $deployment['body']['entrypoint']); $deploymentIdActive = $deployment['body']['$id'] ?? ''; @@ -581,7 +581,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(202, $deployment['headers']['status-code']); $this->assertNotEmpty($deployment['body']['$id']); $this->assertEquals(true, (new DatetimeValidator())->isValid($deployment['body']['$createdAt'])); - $this->assertEquals('index.php', $deployment['body']['entrypoint']); + $this->assertEquals('index.js', $deployment['body']['entrypoint']); $this->assertEventually(function () use ($functionId, $deploymentId) { $deployment = $this->getDeployment($functionId, $deploymentId); @@ -617,7 +617,7 @@ class FunctionsCustomServerTest extends Scope */ $functionId = $data['functionId']; - $folder = 'php-large'; + $folder = 'large'; $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/$folder && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr); @@ -632,13 +632,13 @@ class FunctionsCustomServerTest extends Scope ]; $id = ''; while (!feof($handle)) { - $curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'php-large-fx.tar.gz'); + $curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'large-fx.tar.gz'); $headers['content-range'] = 'bytes ' . ($counter * $chunkSize) . '-' . min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1) . '/' . $size; if (!empty($id)) { $headers['x-appwrite-id'] = $id; } $largeTag = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge($headers, $this->getHeaders()), [ - 'entrypoint' => 'index.php', + 'entrypoint' => 'index.js', 'code' => $curlFile, 'activate' => true, 'commands' => 'cp blue.mp4 copy.mp4 && ls -al' // +7MB buildSize @@ -651,7 +651,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(202, $largeTag['headers']['status-code']); $this->assertNotEmpty($largeTag['body']['$id']); $this->assertEquals(true, (new DatetimeValidator())->isValid($largeTag['body']['$createdAt'])); - $this->assertEquals('index.php', $largeTag['body']['entrypoint']); + $this->assertEquals('index.js', $largeTag['body']['entrypoint']); $this->assertGreaterThan(1024 * 1024 * 5, $largeTag['body']['sourceSize']); // ~7MB video file $this->assertLessThan(1024 * 1024 * 10, $largeTag['body']['sourceSize']); // ~7MB video file @@ -1119,8 +1119,8 @@ class FunctionsCustomServerTest extends Scope 'users.*.update.email', ], 'timeout' => 15, - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'specification' => Specification::S_1VCPU_1GB, ]); @@ -1147,8 +1147,8 @@ class FunctionsCustomServerTest extends Scope 'users.*.update.email', ], 'timeout' => 15, - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'specification' => Specification::S_1VCPU_512MB, ]); @@ -1177,8 +1177,8 @@ class FunctionsCustomServerTest extends Scope 'users.*.update.email', ], 'timeout' => 15, - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'specification' => 's-2vcpu-512mb', // Invalid specification ]); @@ -1279,12 +1279,12 @@ class FunctionsCustomServerTest extends Scope */ public function provideCustomExecutions(): array { + // Most disabled to keep tests fast return [ - ['folder' => 'php-fn', 'name' => 'php-8.0', 'entrypoint' => 'index.php', 'runtimeName' => 'PHP', 'runtimeVersion' => '8.0'], + // ['folder' => 'php-fn', 'name' => 'php-8.0', 'entrypoint' => 'index.php', 'runtimeName' => 'PHP', 'runtimeVersion' => '8.0'], ['folder' => 'node', 'name' => 'node-18.0', 'entrypoint' => 'index.js', 'runtimeName' => 'Node.js', 'runtimeVersion' => '18.0'], - ['folder' => 'python', 'name' => 'python-3.9', 'entrypoint' => 'main.py', 'runtimeName' => 'Python', 'runtimeVersion' => '3.9'], - ['folder' => 'ruby', 'name' => 'ruby-3.1', 'entrypoint' => 'main.rb', 'runtimeName' => 'Ruby', 'runtimeVersion' => '3.1'], - // Swift and Dart disabled on purpose, as it's very slow. + // ['folder' => 'python', 'name' => 'python-3.9', 'entrypoint' => 'main.py', 'runtimeName' => 'Python', 'runtimeVersion' => '3.9'], + // ['folder' => 'ruby', 'name' => 'ruby-3.1', 'entrypoint' => 'main.rb', 'runtimeName' => 'Ruby', 'runtimeVersion' => '3.1'], // [ 'folder' => 'dart', 'name' => 'dart-2.15', 'entrypoint' => 'main.dart', 'runtimeName' => 'Dart', 'runtimeVersion' => '2.15' ], // [ 'folder' => 'swift', 'name' => 'swift-5.5', 'entrypoint' => 'index.swift', 'runtimeName' => 'Swift', 'runtimeVersion' => '5.5' ], ]; @@ -1365,15 +1365,14 @@ class FunctionsCustomServerTest extends Scope { $functionId = $this->setupFunction([ 'functionId' => ID::unique(), - 'name' => 'Test PHP Binary executions', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'name' => 'Test Binary executions', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'timeout' => 15, 'execute' => ['any'] ]); $this->setupDeployment($functionId, [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php-binary-response'), + 'code' => $this->packageFunction('binary-response'), 'activate' => true ]); @@ -1414,15 +1413,14 @@ class FunctionsCustomServerTest extends Scope { $functionId = $this->setupFunction([ 'functionId' => ID::unique(), - 'name' => 'Test PHP Binary executions', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'name' => 'Test Binary executions', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'timeout' => 15, 'execute' => ['any'] ]); $this->setupDeployment($functionId, [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php-binary-request'), + 'code' => $this->packageFunction('binary-request'), 'activate' => true ]); @@ -1695,9 +1693,9 @@ class FunctionsCustomServerTest extends Scope { $functionId = $this->setupFunction([ 'functionId' => ID::unique(), - 'name' => 'Test PHP Binary executions', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'name' => 'Test Binary executions', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'timeout' => 15, 'execute' => ['any'] ]); @@ -1705,8 +1703,7 @@ class FunctionsCustomServerTest extends Scope $domain = $this->setupFunctionDomain($functionId); $this->setupDeployment($functionId, [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php-binary-response'), + 'code' => $this->packageFunction('binary-response'), 'activate' => true ]); @@ -1730,9 +1727,9 @@ class FunctionsCustomServerTest extends Scope { $functionId = $this->setupFunction([ 'functionId' => ID::unique(), - 'name' => 'Test PHP Binary executions', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'name' => 'Test Binary executions', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'timeout' => 15, 'execute' => ['any'] ]); @@ -1740,8 +1737,7 @@ class FunctionsCustomServerTest extends Scope $domain = $this->setupFunctionDomain($functionId); $this->setupDeployment($functionId, [ - 'entrypoint' => 'index.php', - 'code' => $this->packageFunction('php-binary-request'), + 'code' => $this->packageFunction('binary-request'), 'activate' => true ]); @@ -1768,8 +1764,8 @@ class FunctionsCustomServerTest extends Scope ], $this->getHeaders()), [ 'functionId' => ID::unique(), 'name' => 'Test', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'timeout' => 15, ]); @@ -1803,8 +1799,8 @@ class FunctionsCustomServerTest extends Scope $function1Id = $this->setupFunction([ 'functionId' => ID::unique(), 'name' => 'Test', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'timeout' => 15, 'execute' => ['any'] ]); @@ -1812,8 +1808,8 @@ class FunctionsCustomServerTest extends Scope $function2Id = $this->setupFunction([ 'functionId' => ID::unique(), 'name' => 'Test2', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'timeout' => 15, 'execute' => ['any'] ]); diff --git a/tests/resources/functions/basic/index.js b/tests/resources/functions/basic/index.js index b35c2a724d..1eb9d38c58 100644 --- a/tests/resources/functions/basic/index.js +++ b/tests/resources/functions/basic/index.js @@ -3,9 +3,9 @@ module.exports = async(context) => { context.error('error-log-works'); if(context.req.headers['x-appwrite-user-jwt']) { - context.log('jwt-is-invalid'); - } else { context.log('jwt-is-valid'); + } else { + context.log('jwt-is-invalid'); } if(context.req.path === '/custom-response') { @@ -18,7 +18,7 @@ module.exports = async(context) => { context.log('custom-header-is-' + (context.req.headers['x-custom-header'] ?? '')); context.log('method-is-' + (context.req.method ?? '').toLowerCase()); context.log('path-is-' + (context.req.path ?? '')); - context.log('user-is-' + context.req.headers['x-appwrite-user-id'] ?? ''); + context.log('user-is-' + (context.req.headers['x-appwrite-user-id'] ?? '')); const statusCode = context.req.query['code'] || '200'; diff --git a/tests/resources/functions/binary-request/index.js b/tests/resources/functions/binary-request/index.js new file mode 100644 index 0000000000..227df8dce6 --- /dev/null +++ b/tests/resources/functions/binary-request/index.js @@ -0,0 +1,6 @@ +const crypto = require('crypto') + +module.exports = async(context) => { + const hash = crypto.createHash('md5').update(context.req.bodyBinary).digest("hex") + return context.res.send(hash); +}; diff --git a/tests/resources/functions/binary-response/index.js b/tests/resources/functions/binary-response/index.js new file mode 100644 index 0000000000..284a593df0 --- /dev/null +++ b/tests/resources/functions/binary-response/index.js @@ -0,0 +1,4 @@ +module.exports = async(context) => { + const bytes = Buffer.from(Uint8Array.from([0, 10, 255])); + return context.res.binary(bytes); +}; diff --git a/tests/resources/functions/php-large/blue.mp4 b/tests/resources/functions/large/blue.mp4 similarity index 100% rename from tests/resources/functions/php-large/blue.mp4 rename to tests/resources/functions/large/blue.mp4 diff --git a/tests/resources/functions/large/index.js b/tests/resources/functions/large/index.js new file mode 100644 index 0000000000..5e8719bcf3 --- /dev/null +++ b/tests/resources/functions/large/index.js @@ -0,0 +1,3 @@ +module.exports = async(context) => { + return context.res.empty(); +}; diff --git a/tests/resources/functions/php-binary-request/index.php b/tests/resources/functions/php-binary-request/index.php deleted file mode 100644 index 53df8705e5..0000000000 --- a/tests/resources/functions/php-binary-request/index.php +++ /dev/null @@ -1,6 +0,0 @@ -req->bodyBinary); - return $context->res->send($hash); -}; diff --git a/tests/resources/functions/php-binary-response/index.php b/tests/resources/functions/php-binary-response/index.php deleted file mode 100644 index 7715663388..0000000000 --- a/tests/resources/functions/php-binary-response/index.php +++ /dev/null @@ -1,6 +0,0 @@ -res->binary($bytes); -}; diff --git a/tests/resources/functions/php-large/composer.json b/tests/resources/functions/php-large/composer.json deleted file mode 100644 index e3c6db23e9..0000000000 --- a/tests/resources/functions/php-large/composer.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "appwrite/cloud-function-demo", - "description": "Demo cloud function script", - "type": "library", - "license": "BSD-3-Clause", - "authors": [ - { - "name": "Team Appwrite", - "email": "team@appwrite.io" - } - ], - "require": { - "php": ">=7.4.0", - "ext-curl": "*", - "ext-json": "*", - "appwrite/appwrite": "1.1.*" - } -} diff --git a/tests/resources/functions/php-large/composer.lock b/tests/resources/functions/php-large/composer.lock deleted file mode 100644 index 758c73c3f9..0000000000 --- a/tests/resources/functions/php-large/composer.lock +++ /dev/null @@ -1,64 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "afdff6a172e6c44aee11f1562175f81a", - "packages": [ - { - "name": "appwrite/appwrite", - "version": "1.1.2", - "source": { - "type": "git", - "url": "https://github.com/appwrite/sdk-for-php.git", - "reference": "98b327d3fd18a72f4582019916afd735a0e9e0e7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-for-php/zipball/98b327d3fd18a72f4582019916afd735a0e9e0e7", - "reference": "98b327d3fd18a72f4582019916afd735a0e9e0e7", - "shasum": "" - }, - "require": { - "ext-curl": "*", - "ext-json": "*", - "php": ">=7.1.0" - }, - "require-dev": { - "phpunit/phpunit": "3.7.35" - }, - "type": "library", - "autoload": { - "psr-4": { - "Appwrite\\": "src/Appwrite" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Appwrite is an open-source backend as a service server that abstract and simplify complex and repetitive development tasks", - "support": { - "email": "team@localhost.test", - "issues": "https://github.com/appwrite/sdk-for-php/issues", - "source": "https://github.com/appwrite/sdk-for-php/tree/1.1.2", - "url": "https://appwrite.io/support" - }, - "time": "2020-08-15T18:24:32+00:00" - } - ], - "packages-dev": [], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": [], - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": ">=7.4.0", - "ext-curl": "*", - "ext-json": "*" - }, - "platform-dev": [], - "plugin-api-version": "2.0.0" -} diff --git a/tests/resources/functions/php-large/index.php b/tests/resources/functions/php-large/index.php deleted file mode 100644 index abcb2e53d9..0000000000 --- a/tests/resources/functions/php-large/index.php +++ /dev/null @@ -1,16 +0,0 @@ -res->json([ - 'APPWRITE_FUNCTION_ID' => \getenv('APPWRITE_FUNCTION_ID') ?: '', - 'APPWRITE_FUNCTION_NAME' => \getenv('APPWRITE_FUNCTION_NAME') ?: '', - 'APPWRITE_FUNCTION_DEPLOYMENT' => \getenv('APPWRITE_FUNCTION_DEPLOYMENT') ?: '', - 'APPWRITE_FUNCTION_TRIGGER' => $context->req->headers['x-appwrite-trigger'] ?? '', - 'APPWRITE_FUNCTION_RUNTIME_NAME' => \getenv('APPWRITE_FUNCTION_RUNTIME_NAME') ?: '', - 'APPWRITE_FUNCTION_RUNTIME_VERSION' => \getenv('APPWRITE_FUNCTION_RUNTIME_VERSION') ?: '', - 'APPWRITE_REGION' => \getenv('APPWRITE_REGION') ?: '', - 'APPWRITE_FUNCTION_CPUS' => \getenv('APPWRITE_FUNCTION_CPUS') ?: '', - 'APPWRITE_FUNCTION_MEMORY' => \getenv('APPWRITE_FUNCTION_MEMORY') ?: '', - 'UNICODE_TEST' => "êä" - ]); -}; From f02ba4c976f4af79f140df2c0d8b4f3dd1b77542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 10 Jul 2025 14:25:53 +0200 Subject: [PATCH 05/10] Fix function tests --- .../Functions/FunctionsConsoleClientTest.php | 16 +++---- .../Functions/FunctionsCustomClientTest.php | 24 +++++----- .../Functions/FunctionsCustomServerTest.php | 46 +++++++------------ .../Projects/ProjectsCustomServerTest.php | 2 - tests/e2e/Services/Proxy/ProxyBase.php | 2 +- tests/resources/functions/node/index.js | 3 ++ 6 files changed, 41 insertions(+), 52 deletions(-) create mode 100644 tests/resources/functions/node/index.js diff --git a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php index b8b064f077..9dae8efdb4 100644 --- a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php +++ b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php @@ -21,8 +21,8 @@ class FunctionsConsoleClientTest extends Scope 'functionId' => ID::unique(), 'name' => 'Test', 'execute' => [Role::user($this->getUser()['$id'])->toString()], - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'events' => [ 'users.*.create', 'users.*.delete', @@ -39,8 +39,8 @@ class FunctionsConsoleClientTest extends Scope 'functionId' => ID::unique(), 'name' => 'Test Failure', 'execute' => ['some-random-string'], - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', ]); $this->assertEquals(400, $function2['headers']['status-code']); @@ -453,7 +453,7 @@ class FunctionsConsoleClientTest extends Scope { $function = $this->createFunction([ 'functionId' => ID::unique(), - 'runtime' => 'node-18.0', + 'runtime' => 'node-22', 'name' => 'Variable E2E Test', 'entrypoint' => 'index.js', 'logging' => false, @@ -481,7 +481,7 @@ class FunctionsConsoleClientTest extends Scope $deploymentId = $this->setupDeployment($functionId, [ 'entrypoint' => 'index.js', - 'code' => $this->packageFunction('generic'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); @@ -502,7 +502,7 @@ class FunctionsConsoleClientTest extends Scope { $functionId = $this->setupFunction([ 'functionId' => ID::unique(), - 'runtime' => 'node-18.0', + 'runtime' => 'node-22', 'name' => 'Download Test', 'entrypoint' => 'index.js', 'logging' => false, @@ -511,7 +511,7 @@ class FunctionsConsoleClientTest extends Scope $deploymentId = $this->setupDeployment($functionId, [ 'entrypoint' => 'index.js', - 'code' => $this->packageFunction('generic'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); diff --git a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php index 6fae88fcd2..ccabc2a79e 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php @@ -81,7 +81,7 @@ class FunctionsCustomClientTest extends Scope */ $functionId = $this->setupFunction([ 'functionId' => ID::unique(), - 'name' => 'Test ', + 'name' => 'Test', 'execute' => [Role::any()->toString()], 'runtime' => 'node-22', 'entrypoint' => 'index.js', @@ -105,8 +105,8 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals('Test', $output['APPWRITE_FUNCTION_NAME']); $this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']); $this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']); - $this->assertEquals('PHP', $output['APPWRITE_FUNCTION_RUNTIME_NAME']); - $this->assertEquals('8.0', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']); + $this->assertEquals('Node.js', $output['APPWRITE_FUNCTION_RUNTIME_NAME']); + $this->assertEquals('22', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']); $this->assertEquals(APP_VERSION_STABLE, $output['APPWRITE_VERSION']); $this->assertEquals(System::getEnv('_APP_REGION', 'default'), $output['APPWRITE_REGION']); $this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT']); @@ -172,8 +172,8 @@ class FunctionsCustomClientTest extends Scope 'functionId' => ID::unique(), 'name' => 'Test', 'execute' => [], - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'timeout' => 10, ]); @@ -210,11 +210,11 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals('completed', $execution['body']['status']); $this->assertEquals(200, $execution['body']['responseStatusCode']); $this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']); - $this->assertEquals('Test', $output['APPWRITE_FUNCTION_NAME']); + $this->assertEquals('Test synchronous execution', $output['APPWRITE_FUNCTION_NAME']); $this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']); $this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']); - $this->assertEquals('PHP', $output['APPWRITE_FUNCTION_RUNTIME_NAME']); - $this->assertEquals('8.0', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']); + $this->assertEquals('Node.js', $output['APPWRITE_FUNCTION_RUNTIME_NAME']); + $this->assertEquals('22', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']); $this->assertEquals(APP_VERSION_STABLE, $output['APPWRITE_VERSION']); $this->assertEquals(System::getEnv('_APP_REGION', 'default'), $output['APPWRITE_REGION']); $this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT']); @@ -235,12 +235,12 @@ class FunctionsCustomClientTest extends Scope 'functionId' => ID::unique(), 'name' => 'Test', 'execute' => [Role::any()->toString()], - 'runtime' => 'node-18.0', + 'runtime' => 'node-22', 'entrypoint' => 'index.js' ]); $this->setupDeployment($functionId, [ 'entrypoint' => 'index.js', - 'code' => $this->packageFunction('generic'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); @@ -336,7 +336,7 @@ class FunctionsCustomClientTest extends Scope 'limit' => 5, 'offset' => 2, 'useCases' => ['databases'], - 'runtimes' => ['node-16.0'] + 'runtimes' => ['node-22'] ]); $this->assertEquals(200, $templates['headers']['status-code']); @@ -348,7 +348,7 @@ class FunctionsCustomClientTest extends Scope $this->assertContains($template['useCases'][0], ['databases']); } - $this->assertContains('node-16.0', array_column($templates['body']['templates'][0]['runtimes'], 'name')); + $this->assertContains('node-22', array_column($templates['body']['templates'][0]['runtimes'], 'name')); /** * Test for FAILURE diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index 4d0646b12e..488db8e6da 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -902,8 +902,8 @@ class FunctionsCustomServerTest extends Scope $this->assertStringContainsString($data['deploymentId'], $execution['body']['responseBody']); $this->assertStringContainsString('Test1', $execution['body']['responseBody']); $this->assertStringContainsString('http', $execution['body']['responseBody']); - $this->assertStringContainsString('PHP', $execution['body']['responseBody']); - $this->assertStringContainsString('8.0', $execution['body']['responseBody']); + $this->assertStringContainsString('Node.js', $execution['body']['responseBody']); + $this->assertStringContainsString('22', $execution['body']['responseBody']); $this->assertStringContainsString('Global Variable Value', $execution['body']['responseBody']); // $this->assertStringContainsString('êä', $execution['body']['responseBody']); // tests unknown utf-8 chars $this->assertNotEmpty($execution['body']['errors']); @@ -1016,8 +1016,8 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(200, $execution['body']['responseStatusCode']); $this->assertStringContainsString('Test1', $execution['body']['responseBody']); $this->assertStringContainsString('http', $execution['body']['responseBody']); - $this->assertStringContainsString('PHP', $execution['body']['responseBody']); - $this->assertStringContainsString('8.0', $execution['body']['responseBody']); + $this->assertStringContainsString('Node.js', $execution['body']['responseBody']); + $this->assertStringContainsString('22', $execution['body']['responseBody']); // $this->assertStringContainsString('êä', $execution['body']['response']); // tests unknown utf-8 chars $this->assertLessThan(1.500, $execution['body']['duration']); @@ -1282,7 +1282,7 @@ class FunctionsCustomServerTest extends Scope // Most disabled to keep tests fast return [ // ['folder' => 'php-fn', 'name' => 'php-8.0', 'entrypoint' => 'index.php', 'runtimeName' => 'PHP', 'runtimeVersion' => '8.0'], - ['folder' => 'node', 'name' => 'node-18.0', 'entrypoint' => 'index.js', 'runtimeName' => 'Node.js', 'runtimeVersion' => '18.0'], + ['folder' => 'node', 'name' => 'node-22', 'entrypoint' => 'index.js', 'runtimeName' => 'Node.js', 'runtimeVersion' => '22'], // ['folder' => 'python', 'name' => 'python-3.9', 'entrypoint' => 'main.py', 'runtimeName' => 'Python', 'runtimeVersion' => '3.9'], // ['folder' => 'ruby', 'name' => 'ruby-3.1', 'entrypoint' => 'main.rb', 'runtimeName' => 'Ruby', 'runtimeVersion' => '3.1'], // [ 'folder' => 'dart', 'name' => 'dart-2.15', 'entrypoint' => 'main.dart', 'runtimeName' => 'Dart', 'runtimeVersion' => '2.15' ], @@ -1323,27 +1323,14 @@ class FunctionsCustomServerTest extends Scope ]); $execution = $this->createExecution($functionId, [ - 'body' => 'foobar', 'async' => 'false' ]); - + $output = json_decode($execution['body']['responseBody'], true); $this->assertEquals(201, $execution['headers']['status-code']); - $this->assertEquals('completed', $execution['body']['status']); $this->assertEquals(200, $execution['body']['responseStatusCode']); - $this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']); - $this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']); - $this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']); - $this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']); - $this->assertEquals($runtimeName, $output['APPWRITE_FUNCTION_RUNTIME_NAME']); - $this->assertEquals($runtimeVersion, $output['APPWRITE_FUNCTION_RUNTIME_VERSION']); - $this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT']); - $this->assertEquals('foobar', $output['APPWRITE_FUNCTION_DATA']); - $this->assertEquals('variable', $output['CUSTOM_VARIABLE']); - $this->assertEmpty($output['APPWRITE_FUNCTION_USER_ID']); - $this->assertEmpty($output['APPWRITE_FUNCTION_JWT']); - $this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']); - $this->assertStringContainsString('log-works', $execution['body']['logs']); + $this->assertEquals('OK', $execution['body']['responseBody']); + $this->assertEmpty($execution['body']['logs']); $this->assertEmpty($execution['body']['errors']); $executionId = $execution['body']['$id'] ?? ''; @@ -1356,7 +1343,8 @@ class FunctionsCustomServerTest extends Scope $this->assertCount(1, $executions['body']['executions']); $this->assertEquals($executions['body']['executions'][0]['$id'], $executionId); $this->assertEquals($executions['body']['executions'][0]['trigger'], 'http'); - $this->assertStringContainsString('log-works', $executions['body']['executions'][0]['logs']); + $this->assertEquals(200, $executions['body']['executions'][0]['responseStatusCode']); + $this->assertEmpty($executions['body']['executions'][0]['responseBody']); $this->cleanupFunction($functionId); } @@ -1840,7 +1828,7 @@ class FunctionsCustomServerTest extends Scope { $function = $this->createFunction([ 'functionId' => ID::unique(), - 'runtime' => 'node-18.0', + 'runtime' => 'node-22', 'name' => 'Logging Test', 'entrypoint' => 'index.js', 'logging' => false, @@ -1856,7 +1844,7 @@ class FunctionsCustomServerTest extends Scope $domain = $this->setupFunctionDomain($functionId); $this->setupDeployment($functionId, [ - 'code' => $this->packageFunction('generic'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); @@ -1933,7 +1921,7 @@ class FunctionsCustomServerTest extends Scope // Check if the function specifications are correctly set in builds $function = $this->createFunction([ 'functionId' => ID::unique(), - 'runtime' => 'node-18.0', + 'runtime' => 'node-22', 'name' => 'Specification Test', 'entrypoint' => 'index.js', 'logging' => false, @@ -1949,7 +1937,7 @@ class FunctionsCustomServerTest extends Scope $functionId = $functionId = $function['body']['$id'] ?? ''; $deploymentId = $this->setupDeployment($functionId, [ - 'code' => $this->packageFunction('generic'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); @@ -1975,7 +1963,7 @@ class FunctionsCustomServerTest extends Scope { $functionId = $this->setupFunction([ 'functionId' => ID::unique(), - 'runtime' => 'node-18.0', + 'runtime' => 'node-22', 'name' => 'Duplicate Deployment Test', 'entrypoint' => 'index.js', 'commands' => '' @@ -1983,7 +1971,7 @@ class FunctionsCustomServerTest extends Scope $this->assertNotEmpty($functionId); $deploymentId1 = $this->setupDeployment($functionId, [ - 'code' => $this->packageFunction('generic'), + 'code' => $this->packageFunction('basic'), 'activate' => true ]); $this->assertNotEmpty($deploymentId1); @@ -1993,7 +1981,7 @@ class FunctionsCustomServerTest extends Scope $this->assertStringContainsString('APPWRITE_FUNCTION_ID', $execution['body']['responseBody']); $function = $this->updateFunction($functionId, [ - 'runtime' => 'node-18.0', + 'runtime' => 'node-22', 'name' => 'Duplicate Deployment Test', 'entrypoint' => 'index.js', 'commands' => 'rm index.js && mv maintenance.js index.js' diff --git a/tests/e2e/Services/Projects/ProjectsCustomServerTest.php b/tests/e2e/Services/Projects/ProjectsCustomServerTest.php index a01073f3a3..68ff53ae55 100644 --- a/tests/e2e/Services/Projects/ProjectsCustomServerTest.php +++ b/tests/e2e/Services/Projects/ProjectsCustomServerTest.php @@ -30,8 +30,6 @@ class ProjectsCustomServerTest extends Scope 'domain' => $testId . '-api.appwrite.test', ]); - \var_dump($response); - $this->assertEquals(201, $response['headers']['status-code']); $response = $this->client->call(Client::METHOD_POST, '/proxy/rules/api', $headers, [ diff --git a/tests/e2e/Services/Proxy/ProxyBase.php b/tests/e2e/Services/Proxy/ProxyBase.php index b04a8594cb..f125f433f1 100644 --- a/tests/e2e/Services/Proxy/ProxyBase.php +++ b/tests/e2e/Services/Proxy/ProxyBase.php @@ -244,7 +244,7 @@ trait ProxyBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ - 'code' => $this->packageFunction('generic'), + 'code' => $this->packageFunction('basic'), 'activate' => 'true' ]); diff --git a/tests/resources/functions/node/index.js b/tests/resources/functions/node/index.js new file mode 100644 index 0000000000..a43ed308ac --- /dev/null +++ b/tests/resources/functions/node/index.js @@ -0,0 +1,3 @@ +module.exports = async(context) => { + return context.res.send('OK'); +} \ No newline at end of file From 581235f9727e95c4612d5a74a25f35bfdbc33ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 10 Jul 2025 14:43:56 +0200 Subject: [PATCH 06/10] Fix more tests --- tests/e2e/Services/Migrations/MigrationsBase.php | 4 ++-- tests/e2e/Services/Proxy/ProxyBase.php | 2 +- .../e2e/Services/Webhooks/WebhooksCustomServerTest.php | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/e2e/Services/Migrations/MigrationsBase.php b/tests/e2e/Services/Migrations/MigrationsBase.php index 0b8f75b804..6bc1f2d427 100644 --- a/tests/e2e/Services/Migrations/MigrationsBase.php +++ b/tests/e2e/Services/Migrations/MigrationsBase.php @@ -854,8 +854,8 @@ trait MigrationsBase $this->assertEquals($functionId, $response['body']['$id']); $this->assertEquals('Test', $response['body']['name']); - $this->assertEquals('php-8.0', $response['body']['runtime']); - $this->assertEquals('index.php', $response['body']['entrypoint']); + $this->assertEquals('node-22', $response['body']['runtime']); + $this->assertEquals('index.js', $response['body']['entrypoint']); $this->assertEventually(function () use ($functionId) { diff --git a/tests/e2e/Services/Proxy/ProxyBase.php b/tests/e2e/Services/Proxy/ProxyBase.php index f125f433f1..c6d63495a0 100644 --- a/tests/e2e/Services/Proxy/ProxyBase.php +++ b/tests/e2e/Services/Proxy/ProxyBase.php @@ -227,7 +227,7 @@ trait ProxyBase 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'functionId' => ID::unique(), - 'runtime' => 'node-18.0', + 'runtime' => 'node-22', 'name' => 'Proxy Function', 'entrypoint' => 'index.js', 'commands' => '', diff --git a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php index d2f132e960..2bb9d81eec 100644 --- a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php +++ b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php @@ -399,8 +399,8 @@ class WebhooksCustomServerTest extends Scope 'functionId' => ID::unique(), 'name' => 'Test', 'execute' => [Role::any()->toString()], - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'timeout' => 10, ]); @@ -439,8 +439,8 @@ class WebhooksCustomServerTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'name' => 'Test', - 'runtime' => 'php-8.0', - 'entrypoint' => 'index.php', + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', 'execute' => [Role::any()->toString()], 'vars' => [ 'key1' => 'value1', @@ -496,7 +496,7 @@ class WebhooksCustomServerTest extends Scope 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'entrypoint' => 'index.php', + 'entrypoint' => 'index.js', 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), 'activate' => true ]); From 6dc6ff6ba043c55796e7e43f0ae28c91c20042d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 10 Jul 2025 14:44:44 +0200 Subject: [PATCH 07/10] Fix formatting --- tests/e2e/Services/Functions/FunctionsCustomServerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index 488db8e6da..83ff1a0a92 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -1325,7 +1325,7 @@ class FunctionsCustomServerTest extends Scope $execution = $this->createExecution($functionId, [ 'async' => 'false' ]); - + $output = json_decode($execution['body']['responseBody'], true); $this->assertEquals(201, $execution['headers']['status-code']); $this->assertEquals(200, $execution['body']['responseStatusCode']); From 89d54f847f0938f6070b05ee1b6fbe18fe0ef197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 10 Jul 2025 15:52:29 +0200 Subject: [PATCH 08/10] Speed up build cancellation --- .../Modules/Functions/Workers/Builds.php | 30 +++++++++++++++---- .../Functions/FunctionsCustomServerTest.php | 12 ++++---- .../Services/Sites/SitesCustomServerTest.php | 14 ++++----- 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index 580383e76a..3ccc6d5eea 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -264,7 +264,7 @@ class Builds extends Action ->setParam('deploymentId', $deployment->getId()); if ($deployment->getAttribute('status') === 'canceled') { - Console::info('Build has been canceled'); + $this->cancelDeployment($deployment->getId(), $dbForProject, $queueForRealtime); return; } @@ -391,7 +391,7 @@ class Builds extends Action Console::execute('mkdir -p ' . \escapeshellarg('/tmp/builds/' . $deploymentId), '', $stdout, $stderr); if ($dbForProject->getDocument('deployments', $deploymentId)->getAttribute('status') === 'canceled') { - Console::info('Build has been canceled'); + $this->cancelDeployment($deployment->getId(), $dbForProject, $queueForRealtime); return; } @@ -656,7 +656,7 @@ class Builds extends Action $err = null; if ($dbForProject->getDocument('deployments', $deploymentId)->getAttribute('status') === 'canceled') { - Console::info('Build has been canceled'); + $this->cancelDeployment($deployment->getId(), $dbForProject, $queueForRealtime); return; } @@ -807,7 +807,7 @@ class Builds extends Action ]); if ($dbForProject->getDocument('deployments', $deploymentId)->getAttribute('status') === 'canceled') { - Console::info('Build has been canceled'); + $this->cancelDeployment($deployment->getId(), $dbForProject, $queueForRealtime); return; } @@ -1222,7 +1222,7 @@ class Builds extends Action ->trigger(); if ($dbForProject->getDocument('deployments', $deploymentId)->getAttribute('status') === 'canceled') { - Console::info('Build has been canceled'); + $this->cancelDeployment($deployment->getId(), $dbForProject, $queueForRealtime); return; } @@ -1245,7 +1245,7 @@ class Builds extends Action Console::error($th->getTraceAsString()); if ($dbForProject->getDocument('deployments', $deploymentId)->getAttribute('status') === 'canceled') { - Console::info('Build has been canceled'); + $this->cancelDeployment($deployment->getId(), $dbForProject, $queueForRealtime); return; } @@ -1531,4 +1531,22 @@ class Builds extends Action } } } + + private function cancelDeployment(string $deploymentId, Database $dbForProject, Realtime $queueForRealtime) + { + Console::info('Build has been canceled'); + + $deployment = $dbForProject->getDocument('deployments', $deploymentId); + + $logs = $deployment->getAttribute('buildLogs', ''); + $date = \date('H:i:s'); + $logs .= "[$date] [appwrite] Build has been canceled. \n"; + + $deployment->setAttribute('buildLogs', $logs); + $deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment); + + $queueForRealtime + ->setPayload($deployment->getArrayCopy()) + ->trigger(); + } } diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index 83ff1a0a92..ff99033fdf 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -594,12 +594,12 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(200, $deployment['headers']['status-code']); $this->assertEquals('canceled', $deployment['body']['status']); - /** - * Build worker still runs the build. - * 30s sleep gives worker enough time to finish build. - * After build finished, it should still be canceled, not ready. - */ - \sleep(30); + // Ensures worker got eventually aware of cancellation and reacted properly + $this->assertEventually(function () use ($functionId, $deploymentId) { + $deployment = $this->getDeployment($functionId, $deploymentId); + $this->assertEquals(200, $deployment['headers']['status-code']); + $this->assertStringContainsString('Build has been canceled.', $deployment['body']['buildLogs']); + }); $deployment = $this->getDeployment($functionId, $deploymentId); diff --git a/tests/e2e/Services/Sites/SitesCustomServerTest.php b/tests/e2e/Services/Sites/SitesCustomServerTest.php index b3ea045430..721203fc67 100644 --- a/tests/e2e/Services/Sites/SitesCustomServerTest.php +++ b/tests/e2e/Services/Sites/SitesCustomServerTest.php @@ -937,12 +937,12 @@ class SitesCustomServerTest extends Scope $this->assertEquals(200, $deployment['headers']['status-code']); $this->assertEquals('canceled', $deployment['body']['status']); - /** - * Build worker still runs the build. - * 30s sleep gives worker enough time to finish build. - * After build finished, it should still be canceled, not ready. - */ - \sleep(30); + // Ensures worker got eventually aware of cancellation and reacted properly + $this->assertEventually(function () use ($siteId, $deploymentId) { + $deployment = $this->getDeployment($siteId, $deploymentId); + $this->assertEquals(200, $deployment['headers']['status-code']); + $this->assertStringContainsString('Build has been canceled.', $deployment['body']['buildLogs']); + }); $deployment = $this->getDeployment($siteId, $deploymentId); @@ -2657,7 +2657,7 @@ class SitesCustomServerTest extends Scope $siteId = $this->setupSite([ 'siteId' => ID::unique(), 'name' => 'Astro SSR site', - 'framework' => 'astro', + 'framework' => 'static', 'buildRuntime' => 'node-22', 'outputDirectory' => './dist', 'buildCommand' => 'npm run build', From 18492ab91718869108037148fe38c51475f84686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 10 Jul 2025 16:16:06 +0200 Subject: [PATCH 09/10] Revert unwanted change --- tests/e2e/Services/Sites/SitesCustomServerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Services/Sites/SitesCustomServerTest.php b/tests/e2e/Services/Sites/SitesCustomServerTest.php index 721203fc67..8680ca191c 100644 --- a/tests/e2e/Services/Sites/SitesCustomServerTest.php +++ b/tests/e2e/Services/Sites/SitesCustomServerTest.php @@ -2657,7 +2657,7 @@ class SitesCustomServerTest extends Scope $siteId = $this->setupSite([ 'siteId' => ID::unique(), 'name' => 'Astro SSR site', - 'framework' => 'static', + 'framework' => 'astro', 'buildRuntime' => 'node-22', 'outputDirectory' => './dist', 'buildCommand' => 'npm run build', From 0bdb64fc7734b84effa3e888515f0eee63dd4ae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Fri, 11 Jul 2025 15:54:53 +0200 Subject: [PATCH 10/10] Fix migration tests --- composer.json | 2 +- composer.lock | 52 +++++++++++++++++++++++++-------------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/composer.json b/composer.json index 4c36ab125d..5e90143b13 100644 --- a/composer.json +++ b/composer.json @@ -62,7 +62,7 @@ "utopia-php/locale": "0.4.*", "utopia-php/logger": "0.6.*", "utopia-php/messaging": "0.18.*", - "utopia-php/migration": "0.10.*", + "utopia-php/migration": "0.11.*", "utopia-php/orchestration": "0.9.*", "utopia-php/platform": "0.7.*", "utopia-php/pools": "0.8.*", diff --git a/composer.lock b/composer.lock index ec39039b91..97bacd40e9 100644 --- a/composer.lock +++ b/composer.lock @@ -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": "55bc52686a08d64930e6af7411ac0654", + "content-hash": "f53e1ccd394581428d9efcb53b46d479", "packages": [ { "name": "adhocore/jwt", @@ -69,16 +69,16 @@ }, { "name": "appwrite/appwrite", - "version": "11.1.0", + "version": "15.0.0", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-for-php.git", - "reference": "1d043f543acdb17b9fdb440b1b2dd208e400bad3" + "reference": "deb97b62e0abed8a4fd5c5d48e77365cf89867cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-for-php/zipball/1d043f543acdb17b9fdb440b1b2dd208e400bad3", - "reference": "1d043f543acdb17b9fdb440b1b2dd208e400bad3", + "url": "https://api.github.com/repos/appwrite/sdk-for-php/zipball/deb97b62e0abed8a4fd5c5d48e77365cf89867cf", + "reference": "deb97b62e0abed8a4fd5c5d48e77365cf89867cf", "shasum": "" }, "require": { @@ -104,10 +104,10 @@ "support": { "email": "team@appwrite.io", "issues": "https://github.com/appwrite/sdk-for-php/issues", - "source": "https://github.com/appwrite/sdk-for-php/tree/11.1.0", + "source": "https://github.com/appwrite/sdk-for-php/tree/15.0.0", "url": "https://appwrite.io/support" }, - "time": "2024-06-26T07:03:23+00:00" + "time": "2025-05-18T09:47:10+00:00" }, { "name": "appwrite/php-clamav", @@ -3993,20 +3993,20 @@ }, { "name": "utopia-php/migration", - "version": "0.10.4", + "version": "0.11.1", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "0c85917482db172b3ccdc0704e42af3c1cc89361" + "reference": "d528a454d5c1ed6564b2843a39ff13297bcdb1af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/0c85917482db172b3ccdc0704e42af3c1cc89361", - "reference": "0c85917482db172b3ccdc0704e42af3c1cc89361", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/d528a454d5c1ed6564b2843a39ff13297bcdb1af", + "reference": "d528a454d5c1ed6564b2843a39ff13297bcdb1af", "shasum": "" }, "require": { - "appwrite/appwrite": "11.*", + "appwrite/appwrite": "15.*", "ext-curl": "*", "ext-openssl": "*", "php": ">=8.1", @@ -4043,9 +4043,9 @@ ], "support": { "issues": "https://github.com/utopia-php/migration/issues", - "source": "https://github.com/utopia-php/migration/tree/0.10.4" + "source": "https://github.com/utopia-php/migration/tree/0.11.1" }, - "time": "2025-07-02T18:31:09+00:00" + "time": "2025-07-11T13:46:37+00:00" }, { "name": "utopia-php/orchestration", @@ -4810,16 +4810,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "0.41.11", + "version": "0.41.13", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "60122cb613a5a1c82667ecc2217e351654a8d404" + "reference": "7381d2d303af3450f71d0f420f127564c8d4e3d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/60122cb613a5a1c82667ecc2217e351654a8d404", - "reference": "60122cb613a5a1c82667ecc2217e351654a8d404", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/7381d2d303af3450f71d0f420f127564c8d4e3d5", + "reference": "7381d2d303af3450f71d0f420f127564c8d4e3d5", "shasum": "" }, "require": { @@ -4855,9 +4855,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.11" + "source": "https://github.com/appwrite/sdk-generator/tree/0.41.13" }, - "time": "2025-07-04T09:56:24+00:00" + "time": "2025-07-11T10:18:51+00:00" }, { "name": "doctrine/annotations", @@ -5084,16 +5084,16 @@ }, { "name": "laravel/pint", - "version": "v1.23.0", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "9ab851dba4faa51a3c3223dd3d07044129021024" + "reference": "0345f3b05f136801af8c339f9d16ef29e6b4df8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/9ab851dba4faa51a3c3223dd3d07044129021024", - "reference": "9ab851dba4faa51a3c3223dd3d07044129021024", + "url": "https://api.github.com/repos/laravel/pint/zipball/0345f3b05f136801af8c339f9d16ef29e6b4df8a", + "reference": "0345f3b05f136801af8c339f9d16ef29e6b4df8a", "shasum": "" }, "require": { @@ -5104,7 +5104,7 @@ "php": "^8.2.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.76.0", + "friendsofphp/php-cs-fixer": "^3.82.2", "illuminate/view": "^11.45.1", "larastan/larastan": "^3.5.0", "laravel-zero/framework": "^11.45.0", @@ -5149,7 +5149,7 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2025-07-03T10:37:47+00:00" + "time": "2025-07-10T18:09:32+00:00" }, { "name": "matthiasmullie/minify",