diff --git a/app/config/function-templates.php b/app/config/function-templates.php index c8562648be..dddd8596f4 100644 --- a/app/config/function-templates.php +++ b/app/config/function-templates.php @@ -56,7 +56,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['starter'], + 'useCases' => ['starter'], 'runtimes' => [ ...getRuntimes(TEMPLATE_RUNTIMES['NODE'], 'npm install', 'src/main.js', 'node/starter'), ...getRuntimes( @@ -93,7 +93,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['databases'], + 'useCases' => ['databases'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -136,7 +136,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['databases'], + 'useCases' => ['databases'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -178,7 +178,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['databases'], + 'useCases' => ['databases'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -229,7 +229,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['databases'], + 'useCases' => ['databases'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -265,7 +265,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['databases'], + 'useCases' => ['databases'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -331,7 +331,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['ai'], + 'useCases' => ['ai'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -391,7 +391,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['messaging'], + 'useCases' => ['messaging'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -453,7 +453,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['ai'], + 'useCases' => ['ai'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -488,7 +488,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['ai'], + 'useCases' => ['ai'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -534,7 +534,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['utilities'], + 'useCases' => ['utilities'], 'runtimes' => [ ...getRuntimes(TEMPLATE_RUNTIMES['NODE'], 'npm install', 'src/main.js', 'node/generate-pdf') ], @@ -555,7 +555,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['dev-tools'], + 'useCases' => ['dev-tools'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -597,7 +597,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['utilities'], + 'useCases' => ['utilities'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -648,7 +648,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['databases'], + 'useCases' => ['databases'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -729,7 +729,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['databases'], + 'useCases' => ['databases'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -822,7 +822,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['messaging'], + 'useCases' => ['messaging'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -907,7 +907,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['messaging'], + 'useCases' => ['messaging'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -962,7 +962,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['utilities'], + 'useCases' => ['utilities'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1044,7 +1044,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['utilities'], + 'useCases' => ['utilities'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1085,7 +1085,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['utilities'], + 'useCases' => ['utilities'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1142,7 +1142,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 30, - 'usecases' => ['ai'], + 'useCases' => ['ai'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1175,7 +1175,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 30, - 'usecases' => ['ai'], + 'useCases' => ['ai'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1208,7 +1208,7 @@ return [ 'events' => ['buckets.*.files.*.create'], 'cron' => '', 'timeout' => 15, - 'usecases' => ['ai'], + 'useCases' => ['ai'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1266,7 +1266,7 @@ return [ 'events' => ['buckets.*.files.*.create'], 'cron' => '', 'timeout' => 15, - 'usecases' => ['ai'], + 'useCases' => ['ai'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1324,7 +1324,7 @@ return [ 'events' => ['buckets.*.files.*.create'], 'cron' => '', 'timeout' => 15, - 'usecases' => ['ai'], + 'useCases' => ['ai'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1382,7 +1382,7 @@ return [ 'events' => ['databases.*.collections.*.documents.*.create'], 'cron' => '', 'timeout' => 15, - 'usecases' => ['ai'], + 'useCases' => ['ai'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1440,7 +1440,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 300, - 'usecases' => ['ai'], + 'useCases' => ['ai'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1474,7 +1474,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 300, - 'usecases' => ['ai'], + 'useCases' => ['ai'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1516,7 +1516,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['ai'], + 'useCases' => ['ai'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1556,7 +1556,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 300, - 'usecases' => ['ai'], + 'useCases' => ['ai'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1590,7 +1590,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 30, - 'usecases' => ['ai'], + 'useCases' => ['ai'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1653,7 +1653,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 30, - 'usecases' => ['ai'], + 'useCases' => ['ai'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1716,7 +1716,7 @@ return [ 'cron' => '', 'events' => [], 'timeout' => 15, - 'usecases' => ['ai'], + 'useCases' => ['ai'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1771,7 +1771,7 @@ return [ 'cron' => '', 'events' => [], 'timeout' => 15, - 'usecases' => ['ai'], + 'useCases' => ['ai'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1812,7 +1812,7 @@ return [ 'cron' => '', 'events' => [], 'timeout' => 15, - 'usecases' => ['ai'], + 'useCases' => ['ai'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1852,7 +1852,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['ai'], + 'useCases' => ['ai'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1894,7 +1894,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 300, - 'usecases' => ['ai'], + 'useCases' => ['ai'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1928,7 +1928,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['utilities'], + 'useCases' => ['utilities'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], @@ -1983,7 +1983,7 @@ return [ 'events' => [], 'cron' => '', 'timeout' => 15, - 'usecases' => ['utilities'], + 'useCases' => ['utilities'], 'runtimes' => [ ...getRuntimes( TEMPLATE_RUNTIMES['NODE'], diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 88e919730e..558b123f65 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -2367,7 +2367,7 @@ App::get('/v1/functions/templates') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TEMPLATE_FUNCTION_LIST) ->param('runtimes', [], new ArrayList(new WhiteList(array_keys(Config::getParam('runtimes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'List of runtimes allowed for filtering function templates. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' runtimes are allowed.', true) - ->param('useCases', [], new ArrayList(new WhiteList(['dev-tools','starter','databases','ai','messaging','utilities']), APP_LIMIT_ARRAY_PARAMS_SIZE), 'List of usecases allowed for filtering function templates. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' usecases are allowed.', true) + ->param('useCases', [], new ArrayList(new WhiteList(['dev-tools','starter','databases','ai','messaging','utilities']), APP_LIMIT_ARRAY_PARAMS_SIZE), 'List of use cases allowed for filtering function templates. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' use cases are allowed.', true) ->param('limit', 25, new Range(1, 5000), 'Limit the number of templates returned in the response. Default limit is 25, and maximum limit is 5000.', true) ->param('offset', 0, new Range(0, 5000), 'Offset the list of returned templates. Maximum offset is 5000.', true) ->inject('response') @@ -2382,7 +2382,7 @@ App::get('/v1/functions/templates') if (!empty($usecases)) { $templates = \array_filter($templates, function ($template) use ($usecases) { - return \count(\array_intersect($usecases, $template['usecases'])) > 0; + return \count(\array_intersect($usecases, $template['useCases'])) > 0; }); } diff --git a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php index 87638f1b11..61c8afd9bd 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php @@ -8,6 +8,7 @@ use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideClient; +use Utopia\Config\Config; use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; @@ -966,6 +967,10 @@ class FunctionsCustomClientTest extends Scope public function testGetFunctionTemplates() { + /** + * Test for SUCCESS + */ + $expectedTemplates = array_slice(Config::getParam('function-templates', []), 0, 25); $templates = $this->client->call(Client::METHOD_GET, '/functions/templates', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -975,24 +980,47 @@ class FunctionsCustomClientTest extends Scope $this->assertGreaterThan(0, $templates['body']['total']); $this->assertIsArray($templates['body']['templates']); $this->assertArrayHasKey('runtimes', $templates['body']['templates'][0]); + $this->assertArrayHasKey('useCases', $templates['body']['templates'][0]); + for ($i = 0; $i < 25; $i++) { + $this->assertEquals($expectedTemplates[$i]['name'], $templates['body']['templates'][$i]['name']); + $this->assertEquals($expectedTemplates[$i]['id'], $templates['body']['templates'][$i]['id']); + $this->assertEquals($expectedTemplates[$i]['icon'], $templates['body']['templates'][$i]['icon']); + $this->assertEquals($expectedTemplates[$i]['tagline'], $templates['body']['templates'][$i]['tagline']); + $this->assertEquals($expectedTemplates[$i]['useCases'], $templates['body']['templates'][$i]['useCases']); + $this->assertEquals($expectedTemplates[$i]['vcsProvider'], $templates['body']['templates'][$i]['vcsProvider']); + $this->assertEquals($expectedTemplates[$i]['runtimes'], $templates['body']['templates'][$i]['runtimes']); + $this->assertEquals($expectedTemplates[$i]['variables'], $templates['body']['templates'][$i]['variables']); + } + + $templates_offset = $this->client->call(Client::METHOD_GET, '/functions/templates', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'limit' => 1, + 'offset' => 2 + ]); + + $this->assertEquals(200, $templates_offset['headers']['status-code']); + $this->assertEquals(1, $templates_offset['body']['total']); + // assert that offset works as expected + $this->assertEquals($templates['body']['templates'][2]['id'], $templates_offset['body']['templates'][0]['id']); $templates = $this->client->call(Client::METHOD_GET, '/functions/templates', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'usecases' => ['starter', 'ai'], + 'useCases' => ['starter', 'ai'], 'runtimes' => ['bun-1.0', 'dart-2.16'] ]); $this->assertEquals(200, $templates['headers']['status-code']); - $this->assertEquals(3, $templates['body']['total']); + $this->assertGreaterThanOrEqual(3, $templates['body']['total']); $this->assertIsArray($templates['body']['templates']); + foreach ($templates['body']['templates'] as $template) { + $this->assertContains($template['useCases'][0], ['starter', 'ai']); + } $this->assertArrayHasKey('runtimes', $templates['body']['templates'][0]); - $this->assertEquals('starter', $templates['body']['templates'][0]['usecases'][0]); - $this->assertEquals('ai', $templates['body']['templates'][1]['usecases'][0]); - $this->assertEquals('ai', $templates['body']['templates'][2]['usecases'][0]); $this->assertContains('bun-1.0', array_column($templates['body']['templates'][0]['runtimes'], 'name')); - $this->assertContains('dart-2.16', array_column($templates['body']['templates'][1]['runtimes'], 'name')); $templates = $this->client->call(Client::METHOD_GET, '/functions/templates', array_merge([ 'content-type' => 'application/json', @@ -1000,7 +1028,7 @@ class FunctionsCustomClientTest extends Scope ], $this->getHeaders()), [ 'limit' => 5, 'offset' => 2, - 'usecases' => ['databases'], + 'useCases' => ['databases'], 'runtimes' => ['node-16.0'] ]); @@ -1008,7 +1036,34 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(5, $templates['body']['total']); $this->assertIsArray($templates['body']['templates']); $this->assertArrayHasKey('runtimes', $templates['body']['templates'][0]); - $this->assertEquals('databases', $templates['body']['templates'][0]['usecases'][0]); + foreach ($templates['body']['templates'] as $template) { + $this->assertContains($template['useCases'][0], ['databases']); + } $this->assertContains('node-16.0', array_column($templates['body']['templates'][0]['runtimes'], 'name')); + + /** + * Test for FAILURE + */ + $templates = $this->client->call(Client::METHOD_GET, '/functions/templates', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'limit' => 5001, + 'offset' => 10, + ]); + + $this->assertEquals(400, $templates['headers']['status-code']); + $this->assertEquals('Invalid `limit` param: Value must be a valid range between 1 and 5,000', $templates['body']['message']); + + $templates = $this->client->call(Client::METHOD_GET, '/functions/templates', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'limit' => 5, + 'offset' => 5001, + ]); + + $this->assertEquals(400, $templates['headers']['status-code']); + $this->assertEquals('Invalid `offset` param: Value must be a valid range between 0 and 5,000', $templates['body']['message']); } }