diff --git a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php index 06044d9984..eaf3f089e1 100644 --- a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php +++ b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php @@ -7,8 +7,10 @@ use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideConsole; use Utopia\Console; +use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Role; +use Utopia\Database\Query; class FunctionsConsoleClientTest extends Scope { @@ -70,6 +72,7 @@ class FunctionsConsoleClientTest extends Scope $variable = $this->createVariable( $functionId, [ + 'variableId' => ID::unique(), 'key' => 'APP_TEST', 'value' => 'TESTINGVALUE', 'secret' => false @@ -82,6 +85,7 @@ class FunctionsConsoleClientTest extends Scope $secretVariable = $this->createVariable( $functionId, [ + 'variableId' => ID::unique(), 'key' => 'APP_TEST_1', 'value' => 'TESTINGVALUE_1', 'secret' => true @@ -196,6 +200,7 @@ class FunctionsConsoleClientTest extends Scope $variable = $this->createVariable( $functionId, [ + 'variableId' => ID::unique(), 'key' => 'APP_TEST', 'value' => 'TESTINGVALUE', 'secret' => false @@ -208,6 +213,7 @@ class FunctionsConsoleClientTest extends Scope $variable = $this->createVariable( $functionId, [ + 'variableId' => ID::unique(), 'key' => 'APP_TEST_1', 'value' => 'TESTINGVALUE_1', 'secret' => true @@ -226,6 +232,7 @@ class FunctionsConsoleClientTest extends Scope $variable = $this->createVariable( $functionId, [ + 'variableId' => ID::unique(), 'key' => 'APP_TEST', 'value' => 'ANOTHERTESTINGVALUE', 'secret' => false @@ -234,10 +241,47 @@ class FunctionsConsoleClientTest extends Scope $this->assertEquals(409, $variable['headers']['status-code']); + // Test for invalid variableId + $variable = $this->createVariable( + $functionId, + [ + 'variableId' => '!invalid-id!', + 'key' => 'INVALID_ID_KEY', + 'value' => 'value', + ] + ); + + $this->assertEquals(400, $variable['headers']['status-code']); + + // Test for duplicate variableId + $duplicateVariableId = ID::unique(); + $variable = $this->createVariable( + $functionId, + [ + 'variableId' => $duplicateVariableId, + 'key' => 'DUP_ID_KEY_1', + 'value' => 'value1', + ] + ); + + $this->assertEquals(201, $variable['headers']['status-code']); + + $duplicate = $this->createVariable( + $functionId, + [ + 'variableId' => $duplicateVariableId, + 'key' => 'DUP_ID_KEY_2', + 'value' => 'value2', + ] + ); + + $this->assertEquals(409, $duplicate['headers']['status-code']); + // Test for invalid key $variable = $this->createVariable( $functionId, [ + 'variableId' => ID::unique(), 'key' => str_repeat("A", 256), 'value' => 'TESTINGVALUE' ] @@ -249,6 +293,7 @@ class FunctionsConsoleClientTest extends Scope $variable = $this->createVariable( $functionId, [ + 'variableId' => ID::unique(), 'key' => 'LONGKEY', 'value' => str_repeat("#", 8193), ] @@ -283,6 +328,150 @@ class FunctionsConsoleClientTest extends Scope */ } + public function testListVariablesWithLimit(): void + { + // Create a fresh function for this test + $function = $this->createFunction([ + 'functionId' => ID::unique(), + 'name' => 'Test List Variables With Limit', + 'execute' => [Role::user($this->getUser()['$id'])->toString()], + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', + 'timeout' => 10, + ]); + $this->assertEquals(201, $function['headers']['status-code']); + $functionId = $function['body']['$id']; + + $variable1 = $this->createVariable($functionId, [ + 'variableId' => ID::unique(), + 'key' => 'LIMIT_KEY_1', + 'value' => 'limit-value-1', + ]); + $this->assertEquals(201, $variable1['headers']['status-code']); + + $variable2 = $this->createVariable($functionId, [ + 'variableId' => ID::unique(), + 'key' => 'LIMIT_KEY_2', + 'value' => 'limit-value-2', + ]); + $this->assertEquals(201, $variable2['headers']['status-code']); + + // List with limit of 1 + $response = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/variables', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => [ + Query::limit(1)->toString(), + ], + 'total' => true, + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertCount(1, $response['body']['variables']); + $this->assertGreaterThanOrEqual(2, $response['body']['total']); + + $this->cleanupFunction($functionId); + } + + public function testListVariablesWithoutTotal(): void + { + // Create a fresh function for this test + $function = $this->createFunction([ + 'functionId' => ID::unique(), + 'name' => 'Test List Variables Without Total', + 'execute' => [Role::user($this->getUser()['$id'])->toString()], + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', + 'timeout' => 10, + ]); + $this->assertEquals(201, $function['headers']['status-code']); + $functionId = $function['body']['$id']; + + $variable = $this->createVariable($functionId, [ + 'variableId' => ID::unique(), + 'key' => 'NO_TOTAL_KEY', + 'value' => 'no-total-value', + ]); + $this->assertEquals(201, $variable['headers']['status-code']); + + // List with total=false + $response = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/variables', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'total' => false, + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(0, $response['body']['total']); + $this->assertGreaterThanOrEqual(1, \count($response['body']['variables'])); + + $this->cleanupFunction($functionId); + } + + public function testListVariablesCursorPagination(): void + { + // Create a fresh function for this test + $function = $this->createFunction([ + 'functionId' => ID::unique(), + 'name' => 'Test List Variables Cursor Pagination', + 'execute' => [Role::user($this->getUser()['$id'])->toString()], + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', + 'timeout' => 10, + ]); + $this->assertEquals(201, $function['headers']['status-code']); + $functionId = $function['body']['$id']; + + $variable1 = $this->createVariable($functionId, [ + 'variableId' => ID::unique(), + 'key' => 'CURSOR_KEY_1', + 'value' => 'cursor-value-1', + ]); + $this->assertEquals(201, $variable1['headers']['status-code']); + + $variable2 = $this->createVariable($functionId, [ + 'variableId' => ID::unique(), + 'key' => 'CURSOR_KEY_2', + 'value' => 'cursor-value-2', + ]); + $this->assertEquals(201, $variable2['headers']['status-code']); + + // Get first page with limit 1 + $page1 = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/variables', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => [ + Query::limit(1)->toString(), + ], + 'total' => true, + ]); + + $this->assertEquals(200, $page1['headers']['status-code']); + $this->assertCount(1, $page1['body']['variables']); + $cursorId = $page1['body']['variables'][0]['$id']; + + // Get next page using cursor + $page2 = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/variables', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => [ + Query::limit(1)->toString(), + Query::cursorAfter(new Document(['$id' => $cursorId]))->toString(), + ], + 'total' => true, + ]); + + $this->assertEquals(200, $page2['headers']['status-code']); + $this->assertCount(1, $page2['body']['variables']); + $this->assertNotEquals($cursorId, $page2['body']['variables'][0]['$id']); + + $this->cleanupFunction($functionId); + } + public function testGetVariable(): void { $data = $this->setupTestVariables(); @@ -337,6 +526,7 @@ class FunctionsConsoleClientTest extends Scope $functionId = $function['body']['$id']; $variable = $this->createVariable($functionId, [ + 'variableId' => ID::unique(), 'key' => 'APP_TEST', 'value' => 'TESTINGVALUE', 'secret' => false @@ -345,6 +535,7 @@ class FunctionsConsoleClientTest extends Scope $variableId = $variable['body']['$id']; $secretVariable = $this->createVariable($functionId, [ + 'variableId' => ID::unique(), 'key' => 'APP_TEST_1', 'value' => 'TESTINGVALUE_1', 'secret' => true @@ -457,6 +648,7 @@ class FunctionsConsoleClientTest extends Scope * Test for FAILURE */ + // Update with no parameters should fail with 400 $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $functionId . '/variables/' . $variableId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -464,6 +656,7 @@ class FunctionsConsoleClientTest extends Scope $this->assertEquals(400, $response['headers']['status-code']); + // Update with only value should succeed $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $functionId . '/variables/' . $variableId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -471,7 +664,8 @@ class FunctionsConsoleClientTest extends Scope 'value' => 'TESTINGVALUEUPDATED_2' ]); - $this->assertEquals(400, $response['headers']['status-code']); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals("TESTINGVALUEUPDATED_2", $response['body']['value']); $longKey = str_repeat("A", 256); $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $functionId . '/variables/' . $variableId, array_merge([ @@ -496,6 +690,110 @@ class FunctionsConsoleClientTest extends Scope $this->assertEquals(400, $response['headers']['status-code']); } + public function testUpdateVariableKey(): void + { + // Create a fresh function and variable for this test + $function = $this->createFunction([ + 'functionId' => ID::unique(), + 'name' => 'Test Update Variable Key', + 'execute' => [Role::user($this->getUser()['$id'])->toString()], + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', + 'timeout' => 10, + ]); + $this->assertEquals(201, $function['headers']['status-code']); + $functionId = $function['body']['$id']; + + $variable = $this->createVariable($functionId, [ + 'variableId' => ID::unique(), + 'key' => 'KEY_BEFORE', + 'value' => 'unchanged-value', + 'secret' => false + ]); + $this->assertEquals(201, $variable['headers']['status-code']); + $variableId = $variable['body']['$id']; + + // Update only key (key is nullable, but we provide a new key) + $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $functionId . '/variables/' . $variableId, array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'key' => 'KEY_AFTER', + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals('KEY_AFTER', $response['body']['key']); + $this->assertEquals('unchanged-value', $response['body']['value']); + + $this->cleanupFunction($functionId); + } + + public function testUpdateVariableValueOnly(): void + { + // Create a fresh function and variable for this test + $function = $this->createFunction([ + 'functionId' => ID::unique(), + 'name' => 'Test Update Variable Value', + 'execute' => [Role::user($this->getUser()['$id'])->toString()], + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', + 'timeout' => 10, + ]); + $this->assertEquals(201, $function['headers']['status-code']); + $functionId = $function['body']['$id']; + + $variable = $this->createVariable($functionId, [ + 'variableId' => ID::unique(), + 'key' => 'UNCHANGED_KEY', + 'value' => 'value-before', + 'secret' => false + ]); + $this->assertEquals(201, $variable['headers']['status-code']); + $variableId = $variable['body']['$id']; + + // Update only value + $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $functionId . '/variables/' . $variableId, array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'value' => 'value-after', + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals('UNCHANGED_KEY', $response['body']['key']); + $this->assertEquals('value-after', $response['body']['value']); + + $this->cleanupFunction($functionId); + } + + public function testUpdateVariableNotFound(): void + { + // Create a fresh function for this test + $function = $this->createFunction([ + 'functionId' => ID::unique(), + 'name' => 'Test Update Variable Not Found', + 'execute' => [Role::user($this->getUser()['$id'])->toString()], + 'runtime' => 'node-22', + 'entrypoint' => 'index.js', + 'timeout' => 10, + ]); + $this->assertEquals(201, $function['headers']['status-code']); + $functionId = $function['body']['$id']; + + $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $functionId . '/variables/non-existent-id', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'key' => 'NEW_KEY', + 'value' => 'new-value', + ]); + + $this->assertEquals(404, $response['headers']['status-code']); + $this->assertEquals('variable_not_found', $response['body']['type']); + + $this->cleanupFunction($functionId); + } + public function testDeleteVariable(): void { // Create a fresh function and variables for this test since it deletes them @@ -512,6 +810,7 @@ class FunctionsConsoleClientTest extends Scope $functionId = $function['body']['$id']; $variable = $this->createVariable($functionId, [ + 'variableId' => ID::unique(), 'key' => 'APP_TEST', 'value' => 'TESTINGVALUE', 'secret' => false @@ -520,6 +819,7 @@ class FunctionsConsoleClientTest extends Scope $variableId = $variable['body']['$id']; $secretVariable = $this->createVariable($functionId, [ + 'variableId' => ID::unique(), 'key' => 'APP_TEST_1', 'value' => 'TESTINGVALUE_1', 'secret' => true @@ -585,6 +885,7 @@ class FunctionsConsoleClientTest extends Scope // create variable $variable = $this->createVariable($functionId, [ + 'variableId' => ID::unique(), 'key' => 'CUSTOM_VARIABLE', 'value' => 'a_secret_value', 'secret' => true, diff --git a/tests/e2e/Services/Sites/SitesCustomServerTest.php b/tests/e2e/Services/Sites/SitesCustomServerTest.php index 7d9257c699..2beae74d3e 100644 --- a/tests/e2e/Services/Sites/SitesCustomServerTest.php +++ b/tests/e2e/Services/Sites/SitesCustomServerTest.php @@ -104,14 +104,17 @@ class SitesCustomServerTest extends Scope $this->assertEquals('./', $site['body']['outputDirectory']); $variable = $this->createVariable($siteId, [ + 'variableId' => ID::unique(), 'key' => 'siteKey1', 'value' => 'siteValue1', ]); $variable2 = $this->createVariable($siteId, [ + 'variableId' => ID::unique(), 'key' => 'siteKey2', 'value' => 'siteValue2', ]); $variable3 = $this->createVariable($siteId, [ + 'variableId' => ID::unique(), 'key' => 'siteKey3', 'value' => 'siteValue3', ]); @@ -211,6 +214,7 @@ class SitesCustomServerTest extends Scope $this->assertEquals('Test Site', $site['body']['name']); $variable = $this->createVariable($siteId, [ + 'variableId' => ID::unique(), 'key' => 'siteKey1', 'value' => 'siteValue1', 'secret' => false, @@ -223,6 +227,7 @@ class SitesCustomServerTest extends Scope $this->assertEquals(false, $variable['body']['secret']); $variable2 = $this->createVariable($siteId, [ + 'variableId' => ID::unique(), 'key' => 'siteKey2', 'value' => 'siteValue2', 'secret' => false, @@ -235,6 +240,7 @@ class SitesCustomServerTest extends Scope $this->assertEquals(false, $variable2['body']['secret']); $secretVariable = $this->createVariable($siteId, [ + 'variableId' => ID::unique(), 'key' => 'siteKey3', 'value' => 'siteValue3', 'secret' => true, @@ -330,6 +336,316 @@ class SitesCustomServerTest extends Scope $this->cleanupSite($siteId); } + public function testListVariablesWithLimit(): void + { + $site = $this->createSite([ + 'buildRuntime' => 'node-22', + 'fallbackFile' => '', + 'framework' => 'other', + 'name' => 'Test List Variables Limit', + 'outputDirectory' => './', + 'siteId' => ID::unique() + ]); + $siteId = $site['body']['$id'] ?? ''; + $this->assertEquals(201, $site['headers']['status-code']); + + $variable1 = $this->createVariable($siteId, [ + 'variableId' => ID::unique(), + 'key' => 'LIMIT_KEY_1', + 'value' => 'limit-value-1', + ]); + $this->assertEquals(201, $variable1['headers']['status-code']); + + $variable2 = $this->createVariable($siteId, [ + 'variableId' => ID::unique(), + 'key' => 'LIMIT_KEY_2', + 'value' => 'limit-value-2', + ]); + $this->assertEquals(201, $variable2['headers']['status-code']); + + // List with limit of 1 + $response = $this->listVariables($siteId, [ + 'queries' => [ + Query::limit(1)->toString(), + ], + 'total' => true, + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertCount(1, $response['body']['variables']); + $this->assertGreaterThanOrEqual(2, $response['body']['total']); + + $this->cleanupSite($siteId); + } + + public function testListVariablesWithoutTotal(): void + { + $site = $this->createSite([ + 'buildRuntime' => 'node-22', + 'fallbackFile' => '', + 'framework' => 'other', + 'name' => 'Test List Variables No Total', + 'outputDirectory' => './', + 'siteId' => ID::unique() + ]); + $siteId = $site['body']['$id'] ?? ''; + $this->assertEquals(201, $site['headers']['status-code']); + + $variable = $this->createVariable($siteId, [ + 'variableId' => ID::unique(), + 'key' => 'NO_TOTAL_KEY', + 'value' => 'no-total-value', + ]); + $this->assertEquals(201, $variable['headers']['status-code']); + + // List with total=false + $response = $this->listVariables($siteId, [ + 'total' => false, + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(0, $response['body']['total']); + $this->assertGreaterThanOrEqual(1, \count($response['body']['variables'])); + + $this->cleanupSite($siteId); + } + + public function testListVariablesCursorPagination(): void + { + $site = $this->createSite([ + 'buildRuntime' => 'node-22', + 'fallbackFile' => '', + 'framework' => 'other', + 'name' => 'Test List Variables Cursor', + 'outputDirectory' => './', + 'siteId' => ID::unique() + ]); + $siteId = $site['body']['$id'] ?? ''; + $this->assertEquals(201, $site['headers']['status-code']); + + $variable1 = $this->createVariable($siteId, [ + 'variableId' => ID::unique(), + 'key' => 'CURSOR_KEY_1', + 'value' => 'cursor-value-1', + ]); + $this->assertEquals(201, $variable1['headers']['status-code']); + + $variable2 = $this->createVariable($siteId, [ + 'variableId' => ID::unique(), + 'key' => 'CURSOR_KEY_2', + 'value' => 'cursor-value-2', + ]); + $this->assertEquals(201, $variable2['headers']['status-code']); + + // Get first page with limit 1 + $page1 = $this->listVariables($siteId, [ + 'queries' => [ + Query::limit(1)->toString(), + ], + 'total' => true, + ]); + + $this->assertEquals(200, $page1['headers']['status-code']); + $this->assertCount(1, $page1['body']['variables']); + $cursorId = $page1['body']['variables'][0]['$id']; + + // Get next page using cursor + $page2 = $this->listVariables($siteId, [ + 'queries' => [ + Query::limit(1)->toString(), + Query::cursorAfter(new Document(['$id' => $cursorId]))->toString(), + ], + 'total' => true, + ]); + + $this->assertEquals(200, $page2['headers']['status-code']); + $this->assertCount(1, $page2['body']['variables']); + $this->assertNotEquals($cursorId, $page2['body']['variables'][0]['$id']); + + $this->cleanupSite($siteId); + } + + public function testUpdateVariableKey(): void + { + $site = $this->createSite([ + 'buildRuntime' => 'node-22', + 'fallbackFile' => '', + 'framework' => 'other', + 'name' => 'Test Update Variable Key', + 'outputDirectory' => './', + 'siteId' => ID::unique() + ]); + $siteId = $site['body']['$id'] ?? ''; + $this->assertEquals(201, $site['headers']['status-code']); + + $variable = $this->createVariable($siteId, [ + 'variableId' => ID::unique(), + 'key' => 'KEY_BEFORE', + 'value' => 'unchanged-value', + 'secret' => false + ]); + $this->assertEquals(201, $variable['headers']['status-code']); + $variableId = $variable['body']['$id']; + + // Update only key + $response = $this->updateVariable($siteId, $variableId, [ + 'key' => 'KEY_AFTER', + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals('KEY_AFTER', $response['body']['key']); + $this->assertEquals('unchanged-value', $response['body']['value']); + + $this->cleanupSite($siteId); + } + + public function testUpdateVariableValueOnly(): void + { + $site = $this->createSite([ + 'buildRuntime' => 'node-22', + 'fallbackFile' => '', + 'framework' => 'other', + 'name' => 'Test Update Variable Value', + 'outputDirectory' => './', + 'siteId' => ID::unique() + ]); + $siteId = $site['body']['$id'] ?? ''; + $this->assertEquals(201, $site['headers']['status-code']); + + $variable = $this->createVariable($siteId, [ + 'variableId' => ID::unique(), + 'key' => 'UNCHANGED_KEY', + 'value' => 'value-before', + 'secret' => false + ]); + $this->assertEquals(201, $variable['headers']['status-code']); + $variableId = $variable['body']['$id']; + + // Update only value + $response = $this->updateVariable($siteId, $variableId, [ + 'value' => 'value-after', + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals('UNCHANGED_KEY', $response['body']['key']); + $this->assertEquals('value-after', $response['body']['value']); + + $this->cleanupSite($siteId); + } + + public function testUpdateVariableNoOp(): void + { + $site = $this->createSite([ + 'buildRuntime' => 'node-22', + 'fallbackFile' => '', + 'framework' => 'other', + 'name' => 'Test Update Variable NoOp', + 'outputDirectory' => './', + 'siteId' => ID::unique() + ]); + $siteId = $site['body']['$id'] ?? ''; + $this->assertEquals(201, $site['headers']['status-code']); + + $variable = $this->createVariable($siteId, [ + 'variableId' => ID::unique(), + 'key' => 'NOOP_KEY', + 'value' => 'noop-value', + 'secret' => false + ]); + $this->assertEquals(201, $variable['headers']['status-code']); + $variableId = $variable['body']['$id']; + + // Update with no parameters should fail with 400 + $response = $this->updateVariable($siteId, $variableId, []); + + $this->assertEquals(400, $response['headers']['status-code']); + + $this->cleanupSite($siteId); + } + + public function testUpdateVariableNotFound(): void + { + $site = $this->createSite([ + 'buildRuntime' => 'node-22', + 'fallbackFile' => '', + 'framework' => 'other', + 'name' => 'Test Update Variable Not Found', + 'outputDirectory' => './', + 'siteId' => ID::unique() + ]); + $siteId = $site['body']['$id'] ?? ''; + $this->assertEquals(201, $site['headers']['status-code']); + + $response = $this->updateVariable($siteId, 'non-existent-id', [ + 'key' => 'NEW_KEY', + 'value' => 'new-value', + ]); + + $this->assertEquals(404, $response['headers']['status-code']); + $this->assertEquals('variable_not_found', $response['body']['type']); + + $this->cleanupSite($siteId); + } + + public function testCreateVariableInvalidId(): void + { + $site = $this->createSite([ + 'buildRuntime' => 'node-22', + 'fallbackFile' => '', + 'framework' => 'other', + 'name' => 'Test Invalid Variable ID', + 'outputDirectory' => './', + 'siteId' => ID::unique() + ]); + $siteId = $site['body']['$id'] ?? ''; + $this->assertEquals(201, $site['headers']['status-code']); + + $variable = $this->createVariable($siteId, [ + 'variableId' => '!invalid-id!', + 'key' => 'INVALID_ID_KEY', + 'value' => 'value', + ]); + + $this->assertEquals(400, $variable['headers']['status-code']); + + $this->cleanupSite($siteId); + } + + public function testCreateVariableDuplicateId(): void + { + $site = $this->createSite([ + 'buildRuntime' => 'node-22', + 'fallbackFile' => '', + 'framework' => 'other', + 'name' => 'Test Duplicate Variable ID', + 'outputDirectory' => './', + 'siteId' => ID::unique() + ]); + $siteId = $site['body']['$id'] ?? ''; + $this->assertEquals(201, $site['headers']['status-code']); + + $variableId = ID::unique(); + + $variable = $this->createVariable($siteId, [ + 'variableId' => $variableId, + 'key' => 'DUP_ID_KEY_1', + 'value' => 'value1', + ]); + $this->assertEquals(201, $variable['headers']['status-code']); + + // Attempt to create with same ID + $duplicate = $this->createVariable($siteId, [ + 'variableId' => $variableId, + 'key' => 'DUP_ID_KEY_2', + 'value' => 'value2', + ]); + + $this->assertEquals(409, $duplicate['headers']['status-code']); + $this->assertEquals('variable_already_exists', $duplicate['body']['type']); + + $this->cleanupSite($siteId); + } + // This is first Sites test with Proxy // If this fails, it may not be related to variables; but Router flow failing public function testVariablesE2E(): void @@ -351,6 +667,7 @@ class SitesCustomServerTest extends Scope $domain = $this->setupSiteDomain($siteId); $secretVariable = $this->createVariable($siteId, [ + 'variableId' => ID::unique(), 'key' => 'name', 'value' => 'Appwrite', ]);