mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Merge branch '1.9.x' into presence-api
This commit is contained in:
@@ -380,6 +380,7 @@ function computeFlow(ctx) {
|
||||
api('GET', '/functions/runtimes', null, ctx.sessionHeaders, [200], 'functions.runtimes.list');
|
||||
api('GET', '/functions/specifications', null, ctx.apiHeaders, [200], 'functions.specifications.list');
|
||||
const functionVariable = api('POST', `/functions/${functionId}/variables`, {
|
||||
variableId: 'unique()',
|
||||
key: 'BENCHMARK',
|
||||
value: 'true',
|
||||
secret: false,
|
||||
|
||||
@@ -173,8 +173,8 @@ trait ProjectCustom
|
||||
'oauth2.write',
|
||||
'mocks.read',
|
||||
'mocks.write',
|
||||
'policies.read',
|
||||
'policies.write',
|
||||
'project.policies.read',
|
||||
'project.policies.write',
|
||||
'templates.read',
|
||||
'templates.write',
|
||||
],
|
||||
|
||||
@@ -4163,4 +4163,72 @@ class AccountCustomClientTest extends Scope
|
||||
|
||||
$this->assertEquals(401, $verification3['headers']['status-code']);
|
||||
}
|
||||
|
||||
public function testRefreshEmailPasswordSession(): void
|
||||
{
|
||||
$email = uniqid() . 'user@localhost.test';
|
||||
|
||||
$account = $this->client->call(Client::METHOD_POST, '/account', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'userId' => ID::unique(),
|
||||
'email' => $email,
|
||||
'password' => 'password',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $account['headers']['status-code']);
|
||||
|
||||
$session = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => $email,
|
||||
'password' => 'password',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $session['headers']['status-code']);
|
||||
$this->assertNotEmpty($session['body']['$id']);
|
||||
|
||||
$sessionId = $session['body']['$id'];
|
||||
$cookie = 'a_session_' . $this->getProject()['$id'] . '=' .$session['cookies']['a_session_' . $this->getProject()['$id']];
|
||||
|
||||
$session = $this->client->call(Client::METHOD_GET, '/account/sessions/current', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => $cookie,
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $session['headers']['status-code']);
|
||||
$this->assertNotEmpty($session['body']['expire']);
|
||||
$expiryBefore = $session['body']['expire'];
|
||||
|
||||
\sleep(3); // Small delay to ensure expiry an expand
|
||||
|
||||
$session = $this->client->call(Client::METHOD_PATCH, '/account/sessions/' . $sessionId, array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => $cookie,
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $session['headers']['status-code']);
|
||||
$this->assertNotEmpty($session['body']['expire']);
|
||||
$expiryAfter = $session['body']['expire'];
|
||||
|
||||
$this->assertGreaterThan(\strtotime($expiryBefore), \strtotime($expiryAfter));
|
||||
|
||||
$session = $this->client->call(Client::METHOD_GET, '/account/sessions/current', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => $cookie,
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $session['headers']['status-code']);
|
||||
$this->assertEquals(\strtotime($expiryAfter), \strtotime($session['body']['expire']));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,7 @@ class FunctionsConsoleClientTest extends Scope
|
||||
'value' => 'TESTINGVALUEUPDATED_2'
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
|
||||
$longKey = str_repeat("A", 256);
|
||||
$response = $this->client->call(Client::METHOD_PUT, '/functions/' . $functionId . '/variables/' . $variableId, array_merge([
|
||||
@@ -496,6 +689,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 +809,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 +818,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 +884,7 @@ class FunctionsConsoleClientTest extends Scope
|
||||
|
||||
// create variable
|
||||
$variable = $this->createVariable($functionId, [
|
||||
'variableId' => ID::unique(),
|
||||
'key' => 'CUSTOM_VARIABLE',
|
||||
'value' => 'a_secret_value',
|
||||
'secret' => true,
|
||||
|
||||
@@ -53,14 +53,17 @@ class FunctionsCustomServerTest extends Scope
|
||||
$functionId = $function['body']['$id'] ?? '';
|
||||
|
||||
$variable = $this->createVariable($functionId, [
|
||||
'variableId' => 'unique()',
|
||||
'key' => 'funcKey1',
|
||||
'value' => 'funcValue1',
|
||||
]);
|
||||
$variable2 = $this->createVariable($functionId, [
|
||||
'variableId' => 'unique()',
|
||||
'key' => 'funcKey2',
|
||||
'value' => 'funcValue2',
|
||||
]);
|
||||
$variable3 = $this->createVariable($functionId, [
|
||||
'variableId' => 'unique()',
|
||||
'key' => 'funcKey3',
|
||||
'value' => 'funcValue3',
|
||||
]);
|
||||
@@ -109,6 +112,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
|
||||
// Create a variable for later tests
|
||||
$variable = $this->createVariable($functionId, [
|
||||
'variableId' => 'unique()',
|
||||
'key' => 'GLOBAL_VARIABLE',
|
||||
'value' => 'Global Variable Value',
|
||||
]);
|
||||
@@ -278,14 +282,17 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertEquals(10, $function['body']['timeout']);
|
||||
|
||||
$variable = $this->createVariable($functionId, [
|
||||
'variableId' => 'unique()',
|
||||
'key' => 'funcKey1',
|
||||
'value' => 'funcValue1',
|
||||
]);
|
||||
$variable2 = $this->createVariable($functionId, [
|
||||
'variableId' => 'unique()',
|
||||
'key' => 'funcKey2',
|
||||
'value' => 'funcValue2',
|
||||
]);
|
||||
$variable3 = $this->createVariable($functionId, [
|
||||
'variableId' => 'unique()',
|
||||
'key' => 'funcKey3',
|
||||
'value' => 'funcValue3',
|
||||
]);
|
||||
@@ -521,6 +528,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
|
||||
// Create a variable for later tests
|
||||
$variable = $this->createVariable($functionId, [
|
||||
'variableId' => 'unique()',
|
||||
'key' => 'GLOBAL_VARIABLE',
|
||||
'value' => 'Global Variable Value',
|
||||
]);
|
||||
@@ -2011,6 +2019,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
]);
|
||||
|
||||
$variable = $this->createVariable($functionId, [
|
||||
'variableId' => 'unique()',
|
||||
'key' => 'CUSTOM_VARIABLE',
|
||||
'value' => 'variable'
|
||||
]);
|
||||
|
||||
@@ -55,10 +55,10 @@ class FunctionsClientTest extends Scope
|
||||
|
||||
$query = '
|
||||
mutation createVariables($functionId: String!) {
|
||||
var1: functionsCreateVariable(functionId: $functionId, key: "name", value: "John Doe") {
|
||||
var1: functionsCreateVariable(functionId: $functionId, variableId: "unique()", key: "name", value: "John Doe") {
|
||||
_id
|
||||
}
|
||||
var2: functionsCreateVariable(functionId: $functionId, key: "age", value: "42") {
|
||||
var2: functionsCreateVariable(functionId: $functionId, variableId: "unique()", key: "age", value: "42") {
|
||||
_id
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,10 +55,10 @@ class FunctionsServerTest extends Scope
|
||||
|
||||
$query = '
|
||||
mutation createVariables($functionId: String!) {
|
||||
var1: functionsCreateVariable(functionId: $functionId, key: "name", value: "John Doe") {
|
||||
var1: functionsCreateVariable(functionId: $functionId, variableId: "unique()", key: "name", value: "John Doe") {
|
||||
_id
|
||||
}
|
||||
var2: functionsCreateVariable(functionId: $functionId, key: "age", value: "42") {
|
||||
var2: functionsCreateVariable(functionId: $functionId, variableId: "unique()", key: "age", value: "42") {
|
||||
_id
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1096,6 +1096,7 @@ trait MigrationsBase
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
'x-appwrite-response-format' => '1.9.3'
|
||||
], [
|
||||
'key' => 'TEST_VAR',
|
||||
'value' => 'test_value',
|
||||
@@ -1256,7 +1257,6 @@ trait MigrationsBase
|
||||
'max' => 65,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals(202, $response['headers']['status-code']);
|
||||
$this->assertEquals($response['body']['key'], 'age');
|
||||
$this->assertEquals($response['body']['type'], 'integer');
|
||||
@@ -1573,6 +1573,19 @@ trait MigrationsBase
|
||||
|
||||
$this->assertEquals(202, $varchar['headers']['status-code']);
|
||||
|
||||
$bigint = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/bigint', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'key' => 'bigint',
|
||||
'min' => 2147483648,
|
||||
'max' => 9223372036854775807,
|
||||
'required' => false,
|
||||
]);
|
||||
|
||||
$this->assertEquals(202, $bigint['headers']['status-code']);
|
||||
|
||||
$mediumtext = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/mediumtext', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
@@ -1623,6 +1636,7 @@ trait MigrationsBase
|
||||
'mediumtext' => 'mediumText',
|
||||
'longtext' => 'longText',
|
||||
'varchar' => 'varchar',
|
||||
'bigint' => 2147483648 + $i,
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -1711,6 +1725,8 @@ trait MigrationsBase
|
||||
$this->assertStringContainsString('mediumText', $csvData, 'CSV should contain the medium column header');
|
||||
$this->assertStringContainsString('longText', $csvData, 'CSV should contain the long text column header');
|
||||
$this->assertStringContainsString('varchar', $csvData, 'CSV should contain the varchar column header');
|
||||
$this->assertStringContainsString('bigint', $csvData, 'CSV should contain the bigint column header');
|
||||
$this->assertStringContainsString('2147483649', $csvData, 'CSV should contain bigint test data');
|
||||
|
||||
// Cleanup
|
||||
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, [
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace Tests\E2E\Services\Project;
|
||||
use PHPUnit\Framework\Attributes\Before;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use Tests\E2E\Client;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
trait OAuth2Base
|
||||
{
|
||||
@@ -172,6 +173,40 @@ trait OAuth2Base
|
||||
$this->assertNotContains('mock-unverified', $ids);
|
||||
}
|
||||
|
||||
public function testListOAuth2ProvidersTotalFalse(): void
|
||||
{
|
||||
$response = $this->listOAuth2Providers(total: false);
|
||||
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame(0, $response['body']['total']);
|
||||
$this->assertGreaterThan(0, \count($response['body']['providers']));
|
||||
}
|
||||
|
||||
public function testListOAuth2ProvidersWithLimit(): void
|
||||
{
|
||||
$response = $this->listOAuth2Providers([
|
||||
Query::limit(1)->toString(),
|
||||
]);
|
||||
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertCount(1, $response['body']['providers']);
|
||||
$this->assertGreaterThan(1, $response['body']['total']);
|
||||
}
|
||||
|
||||
public function testListOAuth2ProvidersWithOffset(): void
|
||||
{
|
||||
$listAll = $this->listOAuth2Providers();
|
||||
$this->assertSame(200, $listAll['headers']['status-code']);
|
||||
|
||||
$listOffset = $this->listOAuth2Providers([
|
||||
Query::offset(1)->toString(),
|
||||
]);
|
||||
|
||||
$this->assertSame(200, $listOffset['headers']['status-code']);
|
||||
$this->assertCount(\count($listAll['body']['providers']) - 1, $listOffset['body']['providers']);
|
||||
$this->assertSame($listAll['body']['total'], $listOffset['body']['total']);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Get OAuth2 provider
|
||||
// =========================================================================
|
||||
@@ -188,6 +223,28 @@ trait OAuth2Base
|
||||
$this->assertSame('', $response['body']['clientSecret']);
|
||||
}
|
||||
|
||||
public function testGetOAuth2ProviderWithAlias(): void
|
||||
{
|
||||
// The action declares the canonical param name as `providerId` and
|
||||
// registers `provider` as an alias so that older SDK versions that
|
||||
// send the provider in the query string continue to work.
|
||||
$headers = [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
];
|
||||
$headers = \array_merge($headers, $this->getHeaders());
|
||||
|
||||
// Call with `provider` in query string (legacy behaviour)
|
||||
$response = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/project/oauth2/github?provider=github',
|
||||
$headers,
|
||||
);
|
||||
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame('github', $response['body']['$id']);
|
||||
}
|
||||
|
||||
public function testGetOAuth2ProviderClientSecretWriteOnly(): void
|
||||
{
|
||||
$this->updateOAuth2('amazon', [
|
||||
@@ -221,19 +278,23 @@ trait OAuth2Base
|
||||
|
||||
public function testGetOAuth2ProviderUnsupported(): void
|
||||
{
|
||||
// The `providerId` param is validated by a WhiteList of registered
|
||||
// OAuth2 provider keys, so an unknown value is rejected at validation
|
||||
// time — before the action runs — and surfaces as a generic argument
|
||||
// error rather than `project_provider_unsupported`.
|
||||
$response = $this->getOAuth2Provider('not-a-real-provider');
|
||||
|
||||
$this->assertSame(400, $response['headers']['status-code']);
|
||||
$this->assertSame('project_provider_unsupported', $response['body']['type']);
|
||||
$this->assertSame('general_argument_invalid', $response['body']['type']);
|
||||
}
|
||||
|
||||
public function testGetOAuth2ProviderRegisteredInConfigButNoUpdateClass(): void
|
||||
{
|
||||
// `mock` is present in oAuthProviders config (enabled: true) but is NOT
|
||||
// registered in Base::getProviderActions(). Get::action has two
|
||||
// separate `unsupported` throw branches — testGetOAuth2ProviderUnsupported
|
||||
// covers the first (provider missing from config); this covers the
|
||||
// second (provider in config but missing from the action registry).
|
||||
// `mock` is present in oAuthProviders config (enabled: true) but is
|
||||
// NOT registered in Base::getProviderActions(). It passes the
|
||||
// WhiteList validator (which only checks config membership) and
|
||||
// reaches the action body, where the action-registry check throws
|
||||
// `project_provider_unsupported`.
|
||||
$response = $this->getOAuth2Provider('mock');
|
||||
|
||||
$this->assertSame(400, $response['headers']['status-code']);
|
||||
@@ -1590,8 +1651,8 @@ trait OAuth2Base
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame('https://idp.example.com/.well-known/openid-configuration', $response['body']['wellKnownURL']);
|
||||
$this->assertArrayHasKey('authorizationURL', $response['body']);
|
||||
$this->assertArrayHasKey('tokenUrl', $response['body']);
|
||||
$this->assertArrayHasKey('userInfoUrl', $response['body']);
|
||||
$this->assertArrayHasKey('tokenURL', $response['body']);
|
||||
$this->assertArrayHasKey('userInfoURL', $response['body']);
|
||||
|
||||
// Cleanup
|
||||
$this->updateOAuth2('oidc', [
|
||||
@@ -1599,8 +1660,8 @@ trait OAuth2Base
|
||||
'clientSecret' => '',
|
||||
'wellKnownURL' => '',
|
||||
'authorizationURL' => '',
|
||||
'tokenUrl' => '',
|
||||
'userInfoUrl' => '',
|
||||
'tokenURL' => '',
|
||||
'userInfoURL' => '',
|
||||
'enabled' => false,
|
||||
]);
|
||||
}
|
||||
@@ -1611,15 +1672,15 @@ trait OAuth2Base
|
||||
'clientId' => 'oidc-discovery',
|
||||
'clientSecret' => 'oidc-discovery-secret',
|
||||
'authorizationURL' => 'https://idp.example.com/oauth2/authorize',
|
||||
'tokenUrl' => 'https://idp.example.com/oauth2/token',
|
||||
'userInfoUrl' => 'https://idp.example.com/oauth2/userinfo',
|
||||
'tokenURL' => 'https://idp.example.com/oauth2/token',
|
||||
'userInfoURL' => 'https://idp.example.com/oauth2/userinfo',
|
||||
'enabled' => false,
|
||||
]);
|
||||
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame('https://idp.example.com/oauth2/authorize', $response['body']['authorizationURL']);
|
||||
$this->assertSame('https://idp.example.com/oauth2/token', $response['body']['tokenUrl']);
|
||||
$this->assertSame('https://idp.example.com/oauth2/userinfo', $response['body']['userInfoUrl']);
|
||||
$this->assertSame('https://idp.example.com/oauth2/token', $response['body']['tokenURL']);
|
||||
$this->assertSame('https://idp.example.com/oauth2/userinfo', $response['body']['userInfoURL']);
|
||||
|
||||
// Cleanup
|
||||
$this->updateOAuth2('oidc', [
|
||||
@@ -1627,8 +1688,8 @@ trait OAuth2Base
|
||||
'clientSecret' => '',
|
||||
'wellKnownURL' => '',
|
||||
'authorizationURL' => '',
|
||||
'tokenUrl' => '',
|
||||
'userInfoUrl' => '',
|
||||
'tokenURL' => '',
|
||||
'userInfoURL' => '',
|
||||
'enabled' => false,
|
||||
]);
|
||||
}
|
||||
@@ -1640,8 +1701,8 @@ trait OAuth2Base
|
||||
'clientSecret' => '',
|
||||
'wellKnownURL' => '',
|
||||
'authorizationURL' => '',
|
||||
'tokenUrl' => '',
|
||||
'userInfoUrl' => '',
|
||||
'tokenURL' => '',
|
||||
'userInfoURL' => '',
|
||||
'enabled' => false,
|
||||
]);
|
||||
|
||||
@@ -1670,8 +1731,8 @@ trait OAuth2Base
|
||||
'clientSecret' => '',
|
||||
'wellKnownURL' => '',
|
||||
'authorizationURL' => '',
|
||||
'tokenUrl' => '',
|
||||
'userInfoUrl' => '',
|
||||
'tokenURL' => '',
|
||||
'userInfoURL' => '',
|
||||
'enabled' => false,
|
||||
]);
|
||||
|
||||
@@ -1679,7 +1740,7 @@ trait OAuth2Base
|
||||
'clientId' => 'oidc-partial',
|
||||
'clientSecret' => 'oidc-partial-secret',
|
||||
'authorizationURL' => 'https://idp.example.com/oauth2/authorize',
|
||||
'tokenUrl' => 'https://idp.example.com/oauth2/token',
|
||||
'tokenURL' => 'https://idp.example.com/oauth2/token',
|
||||
'enabled' => true,
|
||||
]);
|
||||
|
||||
@@ -1692,8 +1753,8 @@ trait OAuth2Base
|
||||
'clientSecret' => '',
|
||||
'wellKnownURL' => '',
|
||||
'authorizationURL' => '',
|
||||
'tokenUrl' => '',
|
||||
'userInfoUrl' => '',
|
||||
'tokenURL' => '',
|
||||
'userInfoURL' => '',
|
||||
'enabled' => false,
|
||||
]);
|
||||
}
|
||||
@@ -1724,8 +1785,8 @@ trait OAuth2Base
|
||||
'clientSecret' => '',
|
||||
'wellKnownURL' => '',
|
||||
'authorizationURL' => '',
|
||||
'tokenUrl' => '',
|
||||
'userInfoUrl' => '',
|
||||
'tokenURL' => '',
|
||||
'userInfoURL' => '',
|
||||
'enabled' => false,
|
||||
]);
|
||||
}
|
||||
@@ -1755,8 +1816,8 @@ trait OAuth2Base
|
||||
'clientSecret' => '',
|
||||
'wellKnownURL' => '',
|
||||
'authorizationURL' => '',
|
||||
'tokenUrl' => '',
|
||||
'userInfoUrl' => '',
|
||||
'tokenURL' => '',
|
||||
'userInfoURL' => '',
|
||||
'enabled' => false,
|
||||
]);
|
||||
}
|
||||
@@ -1770,8 +1831,8 @@ trait OAuth2Base
|
||||
'clientSecret' => '',
|
||||
'wellKnownURL' => '',
|
||||
'authorizationURL' => '',
|
||||
'tokenUrl' => '',
|
||||
'userInfoUrl' => '',
|
||||
'tokenURL' => '',
|
||||
'userInfoURL' => '',
|
||||
'enabled' => false,
|
||||
]);
|
||||
|
||||
@@ -1780,7 +1841,7 @@ trait OAuth2Base
|
||||
'clientId' => 'oidc-split-discovery',
|
||||
'clientSecret' => 'oidc-split-discovery-secret',
|
||||
'authorizationURL' => 'https://idp.example.com/oauth2/authorize',
|
||||
'tokenUrl' => 'https://idp.example.com/oauth2/token',
|
||||
'tokenURL' => 'https://idp.example.com/oauth2/token',
|
||||
'enabled' => false,
|
||||
]);
|
||||
|
||||
@@ -1788,19 +1849,19 @@ trait OAuth2Base
|
||||
// state must include the two stored URLs + the new one to satisfy
|
||||
// the all-three-discovery-URLs branch of the enable check.
|
||||
$enable = $this->updateOAuth2('oidc', [
|
||||
'userInfoUrl' => 'https://idp.example.com/oauth2/userinfo',
|
||||
'userInfoURL' => 'https://idp.example.com/oauth2/userinfo',
|
||||
'enabled' => true,
|
||||
]);
|
||||
$this->assertSame(200, $enable['headers']['status-code']);
|
||||
$this->assertTrue($enable['body']['enabled']);
|
||||
|
||||
// Confirm all three URLs ended up persisted (merge wrote the new
|
||||
// userInfoUrl while preserving the previously stored two).
|
||||
// userInfoURL while preserving the previously stored two).
|
||||
$get = $this->getOAuth2Provider('oidc');
|
||||
$this->assertSame(200, $get['headers']['status-code']);
|
||||
$this->assertSame('https://idp.example.com/oauth2/authorize', $get['body']['authorizationURL']);
|
||||
$this->assertSame('https://idp.example.com/oauth2/token', $get['body']['tokenUrl']);
|
||||
$this->assertSame('https://idp.example.com/oauth2/userinfo', $get['body']['userInfoUrl']);
|
||||
$this->assertSame('https://idp.example.com/oauth2/token', $get['body']['tokenURL']);
|
||||
$this->assertSame('https://idp.example.com/oauth2/userinfo', $get['body']['userInfoURL']);
|
||||
|
||||
// Cleanup
|
||||
$this->updateOAuth2('oidc', [
|
||||
@@ -1808,8 +1869,8 @@ trait OAuth2Base
|
||||
'clientSecret' => '',
|
||||
'wellKnownURL' => '',
|
||||
'authorizationURL' => '',
|
||||
'tokenUrl' => '',
|
||||
'userInfoUrl' => '',
|
||||
'tokenURL' => '',
|
||||
'userInfoURL' => '',
|
||||
'enabled' => false,
|
||||
]);
|
||||
}
|
||||
@@ -1822,8 +1883,8 @@ trait OAuth2Base
|
||||
'clientSecret' => 'oidc-clear-then-enable-secret',
|
||||
'wellKnownURL' => 'https://idp.example.com/.well-known/openid-configuration',
|
||||
'authorizationURL' => '',
|
||||
'tokenUrl' => '',
|
||||
'userInfoUrl' => '',
|
||||
'tokenURL' => '',
|
||||
'userInfoURL' => '',
|
||||
'enabled' => false,
|
||||
]);
|
||||
|
||||
@@ -1846,8 +1907,8 @@ trait OAuth2Base
|
||||
'clientSecret' => '',
|
||||
'wellKnownURL' => '',
|
||||
'authorizationURL' => '',
|
||||
'tokenUrl' => '',
|
||||
'userInfoUrl' => '',
|
||||
'tokenURL' => '',
|
||||
'userInfoURL' => '',
|
||||
'enabled' => false,
|
||||
]);
|
||||
}
|
||||
@@ -1868,16 +1929,16 @@ trait OAuth2Base
|
||||
$switch = $this->updateOAuth2('oidc', [
|
||||
'wellKnownURL' => '',
|
||||
'authorizationURL' => 'https://idp.example.com/oauth2/authorize',
|
||||
'tokenUrl' => 'https://idp.example.com/oauth2/token',
|
||||
'userInfoUrl' => 'https://idp.example.com/oauth2/userinfo',
|
||||
'tokenURL' => 'https://idp.example.com/oauth2/token',
|
||||
'userInfoURL' => 'https://idp.example.com/oauth2/userinfo',
|
||||
'enabled' => true,
|
||||
]);
|
||||
$this->assertSame(200, $switch['headers']['status-code']);
|
||||
$this->assertTrue($switch['body']['enabled']);
|
||||
$this->assertSame('', $switch['body']['wellKnownURL']);
|
||||
$this->assertSame('https://idp.example.com/oauth2/authorize', $switch['body']['authorizationURL']);
|
||||
$this->assertSame('https://idp.example.com/oauth2/token', $switch['body']['tokenUrl']);
|
||||
$this->assertSame('https://idp.example.com/oauth2/userinfo', $switch['body']['userInfoUrl']);
|
||||
$this->assertSame('https://idp.example.com/oauth2/token', $switch['body']['tokenURL']);
|
||||
$this->assertSame('https://idp.example.com/oauth2/userinfo', $switch['body']['userInfoURL']);
|
||||
|
||||
// Cleanup
|
||||
$this->updateOAuth2('oidc', [
|
||||
@@ -1885,8 +1946,8 @@ trait OAuth2Base
|
||||
'clientSecret' => '',
|
||||
'wellKnownURL' => '',
|
||||
'authorizationURL' => '',
|
||||
'tokenUrl' => '',
|
||||
'userInfoUrl' => '',
|
||||
'tokenURL' => '',
|
||||
'userInfoURL' => '',
|
||||
'enabled' => false,
|
||||
]);
|
||||
}
|
||||
@@ -1900,23 +1961,23 @@ trait OAuth2Base
|
||||
'clientSecret' => 'oidc-clear-secret',
|
||||
'wellKnownURL' => 'https://idp.example.com/.well-known/openid-configuration',
|
||||
'authorizationURL' => 'https://idp.example.com/oauth2/authorize',
|
||||
'tokenUrl' => 'https://idp.example.com/oauth2/token',
|
||||
'userInfoUrl' => 'https://idp.example.com/oauth2/userinfo',
|
||||
'tokenURL' => 'https://idp.example.com/oauth2/token',
|
||||
'userInfoURL' => 'https://idp.example.com/oauth2/userinfo',
|
||||
'enabled' => false,
|
||||
]);
|
||||
|
||||
$response = $this->updateOAuth2('oidc', [
|
||||
'wellKnownURL' => '',
|
||||
'authorizationURL' => '',
|
||||
'tokenUrl' => '',
|
||||
'userInfoUrl' => '',
|
||||
'tokenURL' => '',
|
||||
'userInfoURL' => '',
|
||||
]);
|
||||
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame('', $response['body']['wellKnownURL']);
|
||||
$this->assertSame('', $response['body']['authorizationURL']);
|
||||
$this->assertSame('', $response['body']['tokenUrl']);
|
||||
$this->assertSame('', $response['body']['userInfoUrl']);
|
||||
$this->assertSame('', $response['body']['tokenURL']);
|
||||
$this->assertSame('', $response['body']['userInfoURL']);
|
||||
|
||||
// Cleanup
|
||||
$this->updateOAuth2('oidc', [
|
||||
@@ -1926,6 +1987,96 @@ trait OAuth2Base
|
||||
]);
|
||||
}
|
||||
|
||||
public function testUpdateOAuth2OidcBackwardCompatibleResponseFormat(): void
|
||||
{
|
||||
// Reset to clean state
|
||||
$this->updateOAuth2('oidc', [
|
||||
'clientId' => '',
|
||||
'clientSecret' => '',
|
||||
'wellKnownURL' => '',
|
||||
'authorizationURL' => '',
|
||||
'tokenURL' => '',
|
||||
'userInfoURL' => '',
|
||||
'enabled' => false,
|
||||
]);
|
||||
|
||||
$headers = [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-response-format' => '1.9.3',
|
||||
];
|
||||
$headers = \array_merge($headers, $this->getHeaders());
|
||||
|
||||
// Update using OLD param names (aliases must still work)
|
||||
$response = $this->client->call(
|
||||
Client::METHOD_PATCH,
|
||||
'/project/oauth2/oidc',
|
||||
$headers,
|
||||
[
|
||||
'clientId' => 'oidc-compat-client',
|
||||
'clientSecret' => 'oidc-compat-secret',
|
||||
'tokenUrl' => 'https://idp.example.com/oauth2/token',
|
||||
'userInfoUrl' => 'https://idp.example.com/oauth2/userinfo',
|
||||
'enabled' => false,
|
||||
],
|
||||
);
|
||||
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertArrayHasKey('tokenUrl', $response['body']);
|
||||
$this->assertArrayHasKey('userInfoUrl', $response['body']);
|
||||
$this->assertArrayNotHasKey('tokenURL', $response['body']);
|
||||
$this->assertArrayNotHasKey('userInfoURL', $response['body']);
|
||||
$this->assertSame('https://idp.example.com/oauth2/token', $response['body']['tokenUrl']);
|
||||
$this->assertSame('https://idp.example.com/oauth2/userinfo', $response['body']['userInfoUrl']);
|
||||
|
||||
// GET with 1.9.3 format must also return old param names
|
||||
$get = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/project/oauth2/oidc',
|
||||
$headers,
|
||||
);
|
||||
|
||||
$this->assertSame(200, $get['headers']['status-code']);
|
||||
$this->assertArrayHasKey('tokenUrl', $get['body']);
|
||||
$this->assertArrayHasKey('userInfoUrl', $get['body']);
|
||||
$this->assertArrayNotHasKey('tokenURL', $get['body']);
|
||||
$this->assertArrayNotHasKey('userInfoURL', $get['body']);
|
||||
$this->assertSame('https://idp.example.com/oauth2/token', $get['body']['tokenUrl']);
|
||||
$this->assertSame('https://idp.example.com/oauth2/userinfo', $get['body']['userInfoUrl']);
|
||||
|
||||
// LIST with 1.9.3 format must also return old param names for OIDC
|
||||
$list = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/project/oauth2',
|
||||
$headers,
|
||||
);
|
||||
|
||||
$this->assertSame(200, $list['headers']['status-code']);
|
||||
$oidcEntry = null;
|
||||
foreach ($list['body']['providers'] as $provider) {
|
||||
if ($provider['$id'] === 'oidc') {
|
||||
$oidcEntry = $provider;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->assertNotNull($oidcEntry, 'OIDC provider missing from listOAuth2Providers response');
|
||||
$this->assertArrayHasKey('tokenUrl', $oidcEntry);
|
||||
$this->assertArrayHasKey('userInfoUrl', $oidcEntry);
|
||||
$this->assertArrayNotHasKey('tokenURL', $oidcEntry);
|
||||
$this->assertArrayNotHasKey('userInfoURL', $oidcEntry);
|
||||
$this->assertSame('https://idp.example.com/oauth2/token', $oidcEntry['tokenUrl']);
|
||||
$this->assertSame('https://idp.example.com/oauth2/userinfo', $oidcEntry['userInfoUrl']);
|
||||
|
||||
// Cleanup
|
||||
$this->updateOAuth2('oidc', [
|
||||
'clientId' => '',
|
||||
'clientSecret' => '',
|
||||
'tokenURL' => '',
|
||||
'userInfoURL' => '',
|
||||
'enabled' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Update Okta (clientId + clientSecret + optional domain/authServer)
|
||||
// =========================================================================
|
||||
@@ -2573,7 +2724,7 @@ trait OAuth2Base
|
||||
);
|
||||
}
|
||||
|
||||
protected function getOAuth2Provider(string $provider, bool $authenticated = true): mixed
|
||||
protected function getOAuth2Provider(string $providerId, bool $authenticated = true): mixed
|
||||
{
|
||||
$headers = [
|
||||
'content-type' => 'application/json',
|
||||
@@ -2586,13 +2737,23 @@ trait OAuth2Base
|
||||
|
||||
return $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/project/oauth2/' . $provider,
|
||||
'/project/oauth2/' . $providerId,
|
||||
$headers,
|
||||
);
|
||||
}
|
||||
|
||||
protected function listOAuth2Providers(bool $authenticated = true): mixed
|
||||
protected function listOAuth2Providers(?array $queries = null, ?bool $total = null, bool $authenticated = true): mixed
|
||||
{
|
||||
$params = [];
|
||||
|
||||
if ($queries !== null) {
|
||||
$params['queries'] = $queries;
|
||||
}
|
||||
|
||||
if ($total !== null) {
|
||||
$params['total'] = $total;
|
||||
}
|
||||
|
||||
$headers = [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
@@ -2606,6 +2767,7 @@ trait OAuth2Base
|
||||
Client::METHOD_GET,
|
||||
'/project/oauth2',
|
||||
$headers,
|
||||
$params,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ class WebhooksCustomServerTest extends Scope
|
||||
$this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-response-format' => '1.9.3',
|
||||
], $this->getHeaders()), [
|
||||
'key' => 'key1',
|
||||
'value' => 'value1',
|
||||
@@ -699,6 +700,7 @@ class WebhooksCustomServerTest extends Scope
|
||||
$variable = $this->client->call(Client::METHOD_POST, '/functions/' . $id . '/variables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-response-format' => '1.9.3',
|
||||
], $this->getHeaders()), [
|
||||
'key' => 'key1',
|
||||
'value' => 'value1',
|
||||
|
||||
@@ -6813,6 +6813,7 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'x-appwrite-mode' => 'admin',
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $token,
|
||||
], [
|
||||
'variableId' => $variableId,
|
||||
'key' => 'APP_TEST_' . $variableId,
|
||||
'value' => 'TESTINGVALUE',
|
||||
'secret' => false
|
||||
@@ -6832,6 +6833,7 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'x-appwrite-mode' => 'admin',
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $token,
|
||||
], [
|
||||
'variableId' => $variableId,
|
||||
'key' => 'APP_TEST_' . $variableId,
|
||||
'value' => 'TESTINGVALUE',
|
||||
'secret' => false
|
||||
|
||||
@@ -2,298 +2,753 @@
|
||||
|
||||
namespace Tests\E2E\Services\Proxy;
|
||||
|
||||
use Appwrite\ID;
|
||||
use Appwrite\Tests\Async;
|
||||
use CURLFile;
|
||||
use Tests\E2E\Client;
|
||||
use Utopia\Console;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\System\System;
|
||||
|
||||
trait ProxyBase
|
||||
{
|
||||
use Async;
|
||||
use ProxyHelpers;
|
||||
|
||||
protected function listRules(array $params = []): mixed
|
||||
protected function tearDown(): void
|
||||
{
|
||||
$rule = $this->client->call(Client::METHOD_GET, '/proxy/rules', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), $params);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
protected function createAPIRule(string $domain): mixed
|
||||
{
|
||||
$rule = $this->client->call(Client::METHOD_POST, '/proxy/rules/api', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'domain' => $domain,
|
||||
// Cleanup for testRuleVerification test
|
||||
// Required as it uses static domain name
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::endsWith('domain', 'webapp.com')->toString(),
|
||||
Query::limit(1000)->toString(),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
foreach ($rules['body']['rules'] as $rule) {
|
||||
$ruleId = $rule['$id'];
|
||||
$response = $this->deleteRule($ruleId);
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
}
|
||||
|
||||
return $rule;
|
||||
if ($rules['body']['total'] > 0) {
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::endsWith('domain', 'webapp.com')->toString(),
|
||||
Query::limit(1)->toString()
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(0, count($rules['body']['rules']));
|
||||
$this->assertEquals(0, $rules['body']['total']);
|
||||
}
|
||||
}
|
||||
|
||||
protected function updateRuleVerification(string $ruleId): mixed
|
||||
{
|
||||
$rule = $this->client->call(Client::METHOD_PATCH, '/proxy/rules/' . $ruleId . '/verification', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
protected function createSiteRule(string $domain, string $siteId, string $branch = ''): mixed
|
||||
{
|
||||
$rule = $this->client->call(Client::METHOD_POST, '/proxy/rules/site', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'domain' => $domain,
|
||||
'siteId' => $siteId,
|
||||
'branch' => $branch,
|
||||
]);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
protected function getRule(string $ruleId): mixed
|
||||
{
|
||||
$rule = $this->client->call(Client::METHOD_GET, '/proxy/rules/' . $ruleId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
protected function createRedirectRule(string $domain, string $url, int $statusCode, string $resourceType, string $resourceId): mixed
|
||||
{
|
||||
$rule = $this->client->call(Client::METHOD_POST, '/proxy/rules/redirect', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'domain' => $domain,
|
||||
'url' => $url,
|
||||
'statusCode' => $statusCode,
|
||||
'resourceType' => $resourceType,
|
||||
'resourceId' => $resourceId,
|
||||
]);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
protected function createFunctionRule(string $domain, string $functionId, string $branch = ''): mixed
|
||||
{
|
||||
$rule = $this->client->call(Client::METHOD_POST, '/proxy/rules/function', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'domain' => $domain,
|
||||
'functionId' => $functionId,
|
||||
'branch' => $branch,
|
||||
]);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
protected function deleteRule(string $ruleId): mixed
|
||||
{
|
||||
$rule = $this->client->call(Client::METHOD_DELETE, '/proxy/rules/' . $ruleId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
protected function setupAPIRule(string $domain): string
|
||||
public function testCreateRule(): void
|
||||
{
|
||||
$domain = \uniqid() . '-api.myapp.com';
|
||||
$rule = $this->createAPIRule($domain);
|
||||
|
||||
$this->assertEquals(201, $rule['headers']['status-code'], 'Failed to setup rule: ' . \json_encode($rule));
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals($domain, $rule['body']['domain']);
|
||||
$this->assertEquals('manual', $rule['body']['trigger']);
|
||||
$this->assertArrayHasKey('$id', $rule['body']);
|
||||
$this->assertArrayHasKey('domain', $rule['body']);
|
||||
$this->assertArrayHasKey('type', $rule['body']);
|
||||
$this->assertArrayHasKey('redirectUrl', $rule['body']);
|
||||
$this->assertArrayHasKey('redirectStatusCode', $rule['body']);
|
||||
$this->assertArrayHasKey('deploymentResourceType', $rule['body']);
|
||||
$this->assertArrayHasKey('deploymentId', $rule['body']);
|
||||
$this->assertArrayHasKey('deploymentResourceId', $rule['body']);
|
||||
$this->assertArrayHasKey('deploymentVcsProviderBranch', $rule['body']);
|
||||
$this->assertArrayHasKey('logs', $rule['body']);
|
||||
$this->assertArrayHasKey('renewAt', $rule['body']);
|
||||
|
||||
return $rule['body']['$id'];
|
||||
}
|
||||
$ruleId = $rule['body']['$id'];
|
||||
|
||||
protected function setupRedirectRule(string $domain, string $url, int $statusCode, string $resourceType, string $resourceId): string
|
||||
{
|
||||
$rule = $this->createRedirectRule($domain, $url, $statusCode, $resourceType, $resourceId);
|
||||
$rule = $this->createAPIRule($domain);
|
||||
$this->assertEquals(409, $rule['headers']['status-code']);
|
||||
|
||||
$this->assertEquals(201, $rule['headers']['status-code'], 'Failed to setup rule: ' . \json_encode($rule));
|
||||
|
||||
return $rule['body']['$id'];
|
||||
}
|
||||
|
||||
protected function setupFunctionRule(string $domain, string $functionId, string $branch = ''): string
|
||||
{
|
||||
$rule = $this->createFunctionRule($domain, $functionId, $branch);
|
||||
|
||||
$this->assertEquals(201, $rule['headers']['status-code'], 'Failed to setup rule: ' . \json_encode($rule));
|
||||
|
||||
return $rule['body']['$id'];
|
||||
}
|
||||
|
||||
protected function setupSiteRule(string $domain, string $siteId, string $branch = ''): string
|
||||
{
|
||||
$rule = $this->createSiteRule($domain, $siteId, $branch);
|
||||
|
||||
$this->assertEquals(201, $rule['headers']['status-code'], 'Failed to setup rule: ' . \json_encode($rule));
|
||||
|
||||
return $rule['body']['$id'];
|
||||
}
|
||||
|
||||
protected function cleanupRule(string $ruleId): void
|
||||
{
|
||||
$rule = $this->deleteRule($ruleId);
|
||||
$this->assertEquals(204, $rule['headers']['status-code'], 'Failed to cleanup rule: ' . \json_encode($rule));
|
||||
|
||||
$this->assertEquals(204, $rule['headers']['status-code']);
|
||||
}
|
||||
|
||||
protected function cleanupSite(string $siteId): void
|
||||
public function testCreateRuleSetup(): void
|
||||
{
|
||||
$site = $this->client->call(Client::METHOD_DELETE, '/sites/' . $siteId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
$this->assertEquals(204, $site['headers']['status-code'], 'Failed to cleanup site: ' . \json_encode($site));
|
||||
$ruleId = $this->setupAPIRule(\uniqid() . '-api2.myapp.com');
|
||||
$this->cleanupRule($ruleId);
|
||||
}
|
||||
|
||||
protected function cleanupFunction(string $functionId): void
|
||||
public function testCreateRuleApex(): void
|
||||
{
|
||||
$function = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
$this->assertEquals(204, $function['headers']['status-code'], 'Failed to cleanup function: ' . \json_encode($function));
|
||||
$domain = \uniqid() . '.com';
|
||||
$rule = $this->createAPIRule($domain);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('unverified', $rule['body']['status']);
|
||||
}
|
||||
|
||||
protected function setupSite(): mixed
|
||||
public function testCreateRuleVcs(): void
|
||||
{
|
||||
// Site
|
||||
$site = $this->client->call(Client::METHOD_POST, '/sites', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), [
|
||||
'siteId' => ID::unique(),
|
||||
'name' => 'Proxy site',
|
||||
'framework' => 'other',
|
||||
'adapter' => 'static',
|
||||
'buildRuntime' => 'static-1',
|
||||
'outputDirectory' => './',
|
||||
'buildCommand' => '',
|
||||
'installCommand' => '',
|
||||
'fallbackFile' => '',
|
||||
]);
|
||||
$domain = \uniqid() . '-vcs.myapp.com';
|
||||
|
||||
$this->assertEquals($site['headers']['status-code'], 201, 'Setup site failed with status code: ' . $site['headers']['status-code'] . ' and response: ' . json_encode($site['body'], JSON_PRETTY_PRINT));
|
||||
$setup = $this->setupSite();
|
||||
$siteId = $setup['siteId'];
|
||||
$deploymentId = $setup['deploymentId'];
|
||||
|
||||
$siteId = $site['body']['$id'];
|
||||
$this->assertNotEmpty($siteId);
|
||||
$this->assertNotEmpty($deploymentId);
|
||||
|
||||
// Deployment
|
||||
$deployment = $this->client->call(Client::METHOD_POST, '/sites/' . $siteId . '/deployments', array_merge([
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), [
|
||||
'code' => $this->packageSite('static'),
|
||||
'activate' => 'true'
|
||||
]);
|
||||
$rule = $this->createSiteRule('commit-' . $domain, $siteId);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
|
||||
$this->assertEquals($deployment['headers']['status-code'], 202, 'Setup deployment failed with status code: ' . $deployment['headers']['status-code'] . ' and response: ' . json_encode($deployment['body'], JSON_PRETTY_PRINT));
|
||||
$deploymentId = $deployment['body']['$id'] ?? '';
|
||||
$rule = $this->createSiteRule('branch-' . $domain, $siteId);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
|
||||
$this->assertEventually(function () use ($siteId, $deploymentId) {
|
||||
$site = $this->client->call(Client::METHOD_GET, '/sites/' . $siteId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]));
|
||||
$this->assertEquals($deploymentId, $site['body']['deploymentId'], 'Deployment is not activated, deployment: ' . json_encode($site['body'], JSON_PRETTY_PRINT));
|
||||
}, 120000, 500);
|
||||
$rule = $this->createSiteRule('anything-' . $domain, $siteId);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
|
||||
return ['siteId' => $siteId, 'deploymentId' => $deploymentId];
|
||||
$sitesDomain = \explode(',', System::getEnv('_APP_DOMAIN_SITES', ''))[0];
|
||||
$domain = \uniqid() . '-vcs.' . $sitesDomain;
|
||||
|
||||
$rule = $this->createSiteRule('commit-' . $domain, $siteId);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
|
||||
$rule = $this->createSiteRule('branch-' . $domain, $siteId);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
|
||||
$rule = $this->createSiteRule('subdomain.anything-' . $domain, $siteId);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
|
||||
$rule = $this->createSiteRule('anything-' . $domain, $siteId);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
}
|
||||
|
||||
protected function setupFunction(): mixed
|
||||
public function testCreateAPIRule(): void
|
||||
{
|
||||
// Function
|
||||
$function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), [
|
||||
'functionId' => ID::unique(),
|
||||
'runtime' => 'node-22',
|
||||
'name' => 'Proxy Function',
|
||||
'entrypoint' => 'index.js',
|
||||
'commands' => '',
|
||||
'execute' => ['any']
|
||||
$domain = \uniqid() . '-api.custom.localhost';
|
||||
|
||||
$proxyClient = new Client();
|
||||
$proxyClient->setEndpoint('http://appwrite.test');
|
||||
$proxyClient->addHeader('x-appwrite-hostname', $domain);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/versions');
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
|
||||
$ruleId = $this->setupAPIRule($domain);
|
||||
|
||||
$this->assertNotEmpty($ruleId);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/versions');
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(APP_VERSION_STABLE, $response['body']['server']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
|
||||
$rule = $this->createAPIRule('http://' . $domain);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
|
||||
$rule = $this->createAPIRule('https://' . $domain);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
|
||||
$rule = $this->createAPIRule('wss://' . $domain);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
|
||||
$rule = $this->createAPIRule($domain . '/some-path');
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
}
|
||||
|
||||
public function testCreateRedirectRule(): void
|
||||
{
|
||||
$domain = \uniqid() . '-redirect.custom.localhost';
|
||||
|
||||
$proxyClient = new Client();
|
||||
$proxyClient->setEndpoint('http://appwrite.test');
|
||||
$proxyClient->addHeader('x-appwrite-hostname', $domain);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/todos/1');
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
|
||||
$siteId = $this->setupSite()['siteId'];
|
||||
|
||||
$ruleId = $this->setupRedirectRule($domain, 'https://jsonplaceholder.typicode.com/todos/1', 301, 'site', $siteId);
|
||||
$this->assertNotEmpty($ruleId);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/todos/1');
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(1, $response['body']['id']);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/');
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(1, $response['body']['id']);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/', followRedirects: false);
|
||||
$this->assertEquals(301, $response['headers']['status-code']);
|
||||
$this->assertEquals('https://jsonplaceholder.typicode.com/todos/1', $response['headers']['location']);
|
||||
|
||||
$domain = \uniqid() . '-redirect-307.custom.localhost';
|
||||
$ruleId = $this->setupRedirectRule($domain, 'https://jsonplaceholder.typicode.com/todos/1', 307, 'site', $siteId);
|
||||
$this->assertNotEmpty($ruleId);
|
||||
|
||||
$proxyClient = new Client();
|
||||
$proxyClient->setEndpoint('http://appwrite.test');
|
||||
$proxyClient->addHeader('x-appwrite-hostname', $domain);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/', followRedirects: false);
|
||||
$this->assertEquals(307, $response['headers']['status-code']);
|
||||
$this->assertEquals('https://jsonplaceholder.typicode.com/todos/1', $response['headers']['location']);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::equal('type', ['redirect'])->toString(),
|
||||
Query::equal('trigger', ['manual'])->toString(),
|
||||
Query::equal('deploymentResourceType', ['site'])->toString(),
|
||||
Query::equal('deploymentResourceId', [$siteId])->toString(),
|
||||
],
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(2, $rules['body']['total']);
|
||||
|
||||
$this->assertEquals($function['headers']['status-code'], 201, 'Setup function failed with status code: ' . $function['headers']['status-code'] . ' and response: ' . json_encode($function['body'], JSON_PRETTY_PRINT));
|
||||
$this->cleanupSite($siteId);
|
||||
$this->cleanupRule($ruleId);
|
||||
}
|
||||
|
||||
$functionId = $function['body']['$id'];
|
||||
public function testCreateFunctionRule(): void
|
||||
{
|
||||
$domain = \uniqid() . '-function.custom.localhost';
|
||||
|
||||
// Deployment
|
||||
$deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), [
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => 'true'
|
||||
]);
|
||||
$proxyClient = new Client();
|
||||
$proxyClient->setEndpoint('http://appwrite.test');
|
||||
$proxyClient->addHeader('x-appwrite-hostname', $domain);
|
||||
|
||||
$this->assertEquals($deployment['headers']['status-code'], 202, 'Setup deployment failed with status code: ' . $deployment['headers']['status-code'] . ' and response: ' . json_encode($deployment['body'], JSON_PRETTY_PRINT));
|
||||
$deploymentId = $deployment['body']['$id'] ?? '';
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/ping');
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
|
||||
$setup = $this->setupFunction();
|
||||
$functionId = $setup['functionId'];
|
||||
$deploymentId = $setup['deploymentId'];
|
||||
|
||||
$this->assertNotEmpty($functionId);
|
||||
$this->assertNotEmpty($deploymentId);
|
||||
|
||||
$ruleId = $this->setupFunctionRule($domain, $functionId);
|
||||
$this->assertNotEmpty($ruleId);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/ping');
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals($functionId, $response['body']['APPWRITE_FUNCTION_ID']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
|
||||
$this->cleanupFunction($functionId);
|
||||
|
||||
$this->assertEventually(function () use ($functionId, $deploymentId) {
|
||||
$function = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]));
|
||||
$this->assertEquals($deploymentId, $function['body']['deploymentId'], 'Deployment is not activated, deployment: ' . json_encode($function['body'], JSON_PRETTY_PRINT));
|
||||
}, 100000, 500);
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::limit(1)->toString(),
|
||||
Query::equal('type', ['deployment'])->toString(),
|
||||
Query::equal('deploymentResourceType', ['function'])->toString(),
|
||||
Query::equal('deploymentResourceId', [$functionId])->toString(),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(0, $rules['body']['total']);
|
||||
$this->assertCount(0, $rules['body']['rules']);
|
||||
|
||||
return ['functionId' => $functionId, 'deploymentId' => $deploymentId];
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::limit(1)->toString(),
|
||||
Query::equal('type', ['deployment'])->toString(),
|
||||
Query::equal('deploymentId', [$deploymentId])->toString()
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(0, $rules['body']['total']);
|
||||
$this->assertCount(0, $rules['body']['rules']);
|
||||
});
|
||||
}
|
||||
|
||||
private function packageSite(string $site): CURLFile
|
||||
public function testCreateSiteRule(): void
|
||||
{
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
$domain = \uniqid() . '-site.custom.localhost';
|
||||
|
||||
$folderPath = realpath(__DIR__ . '/../../../resources/sites') . "/$site";
|
||||
$tarPath = "$folderPath/code.tar.gz";
|
||||
$proxyClient = new Client();
|
||||
$proxyClient->setEndpoint('http://appwrite.test');
|
||||
$proxyClient->addHeader('x-appwrite-hostname', $domain);
|
||||
|
||||
Console::execute("cd $folderPath && tar --exclude code.tar.gz --exclude node_modules -czf code.tar.gz .", '', $stdout, $stderr);
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/contact');
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
|
||||
if (filesize($tarPath) > 1024 * 1024 * 5) {
|
||||
throw new \Exception('Code package is too large. Use the chunked upload method instead.');
|
||||
$setup = $this->setupSite();
|
||||
$siteId = $setup['siteId'];
|
||||
$deploymentId = $setup['deploymentId'];
|
||||
|
||||
$this->assertNotEmpty($siteId);
|
||||
$this->assertNotEmpty($deploymentId);
|
||||
|
||||
$ruleId = $this->setupSiteRule($domain, $siteId);
|
||||
$this->assertNotEmpty($ruleId);
|
||||
$rule = $this->getRule($ruleId);
|
||||
$this->assertSame(200, $rule['headers']['status-code']);
|
||||
$this->assertSame('unverified', $rule['body']['status']);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/contact');
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString('Contact page', $response['body']);
|
||||
|
||||
// Wildcard domains automatically get verified status
|
||||
$domains = [
|
||||
\uniqid() . '.sites.localhost',
|
||||
\uniqid() . '.rebranded.localhost',
|
||||
];
|
||||
foreach ($domains as $domain) {
|
||||
$wildcardRuleId = $this->setupSiteRule($domain, $siteId);
|
||||
$this->assertNotEmpty($wildcardRuleId);
|
||||
$rule = $this->getRule($wildcardRuleId);
|
||||
$this->assertSame(200, $rule['headers']['status-code']);
|
||||
$this->assertSame('verified', $rule['body']['status']);
|
||||
$this->cleanupRule($wildcardRuleId);
|
||||
}
|
||||
|
||||
return new CURLFile($tarPath, 'application/x-gzip', \basename($tarPath));
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::limit(1)->toString(),
|
||||
Query::equal('trigger', ['deployment'])->toString(),
|
||||
Query::equal('type', ['deployment'])->toString(),
|
||||
Query::equal('deploymentResourceType', ['site'])->toString(),
|
||||
Query::equal('deploymentResourceId', [$siteId])->toString(),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertGreaterThan(0, $rules['body']['total']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
|
||||
$this->cleanupSite($siteId);
|
||||
|
||||
$this->assertEventually(function () use ($siteId, $deploymentId) {
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::limit(1)->toString(),
|
||||
Query::equal('type', ['deployment'])->toString(),
|
||||
Query::equal('deploymentResourceType', ['site'])->toString(),
|
||||
Query::equal('deploymentResourceId', [$siteId])->toString(),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(0, $rules['body']['total']);
|
||||
$this->assertCount(0, $rules['body']['rules']);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::limit(1)->toString(),
|
||||
Query::equal('type', ['deployment'])->toString(),
|
||||
Query::equal('deploymentId', [$deploymentId])->toString()
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(0, $rules['body']['total']);
|
||||
$this->assertCount(0, $rules['body']['rules']);
|
||||
});
|
||||
}
|
||||
|
||||
private function packageFunction(string $function): CURLFile
|
||||
public function testCreateSiteBranchRule(): void
|
||||
{
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
$domain = \uniqid() . '-site-branch.custom.localhost';
|
||||
|
||||
$folderPath = realpath(__DIR__ . '/../../../resources/functions') . "/$function";
|
||||
$tarPath = "$folderPath/code.tar.gz";
|
||||
$setup = $this->setupSite();
|
||||
$siteId = $setup['siteId'];
|
||||
$deploymentId = $setup['deploymentId'];
|
||||
|
||||
Console::execute("cd $folderPath && tar --exclude code.tar.gz --exclude node_modules -czf code.tar.gz .", '', $stdout, $stderr);
|
||||
$this->assertNotEmpty($siteId);
|
||||
$this->assertNotEmpty($deploymentId);
|
||||
|
||||
if (filesize($tarPath) > 1024 * 1024 * 5) {
|
||||
throw new \Exception('Code package is too large. Use the chunked upload method instead.');
|
||||
$ruleId = $this->setupSiteRule($domain, $siteId, 'dev');
|
||||
$this->assertNotEmpty($ruleId);
|
||||
|
||||
$rule = $this->getRule($ruleId);
|
||||
$this->assertEquals(200, $rule['headers']['status-code']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
}
|
||||
|
||||
public function testCreateFunctionBranchRule(): void
|
||||
{
|
||||
$domain = \uniqid() . '-function-branch.custom.localhost';
|
||||
|
||||
$setup = $this->setupFunction();
|
||||
$functionId = $setup['functionId'];
|
||||
$deploymentId = $setup['deploymentId'];
|
||||
|
||||
$this->assertNotEmpty($functionId);
|
||||
$this->assertNotEmpty($deploymentId);
|
||||
|
||||
$ruleId = $this->setupFunctionRule($domain, $functionId, 'dev');
|
||||
$this->assertNotEmpty($ruleId);
|
||||
|
||||
$rule = $this->getRule($ruleId);
|
||||
$this->assertEquals(200, $rule['headers']['status-code']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
|
||||
$this->cleanupFunction($functionId);
|
||||
}
|
||||
|
||||
public function testUpdateRule(): void
|
||||
{
|
||||
// Create function appwrite-network domain
|
||||
$functionsDomain = \explode(',', System::getEnv('_APP_DOMAIN_FUNCTIONS', ''))[0];
|
||||
$domain = \uniqid() . '-cname-api.' . $functionsDomain;
|
||||
|
||||
$rule = $this->createAPIRule($domain);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('verified', $rule['body']['status']);
|
||||
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
|
||||
// Create site appwrite-network domain
|
||||
$sitesDomain = \explode(',', System::getEnv('_APP_DOMAIN_SITES', ''))[0];
|
||||
$domain = \uniqid() . '-cname-api.' . $sitesDomain;
|
||||
|
||||
$rule = $this->createAPIRule($domain);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('verified', $rule['body']['status']);
|
||||
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
|
||||
// Create + update
|
||||
$domain = \uniqid() . '-cname-api.custom.com';
|
||||
|
||||
$rule = $this->createAPIRule($domain);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('unverified', $rule['body']['status']);
|
||||
|
||||
$ruleId = $rule['body']['$id'];
|
||||
|
||||
$rule = $this->updateRuleStatus($ruleId);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
}
|
||||
|
||||
public function testGetRule()
|
||||
{
|
||||
$domain = \uniqid() . '-get.custom.localhost';
|
||||
$ruleId = $this->setupAPIRule($domain);
|
||||
|
||||
$this->assertNotEmpty($ruleId);
|
||||
|
||||
$rule = $this->getRule($ruleId);
|
||||
$this->assertEquals(200, $rule['headers']['status-code']);
|
||||
$this->assertEquals($domain, $rule['body']['domain']);
|
||||
$this->assertEquals('manual', $rule['body']['trigger']);
|
||||
$this->assertArrayHasKey('$id', $rule['body']);
|
||||
$this->assertArrayHasKey('domain', $rule['body']);
|
||||
$this->assertArrayHasKey('type', $rule['body']);
|
||||
$this->assertArrayHasKey('redirectUrl', $rule['body']);
|
||||
$this->assertArrayHasKey('redirectStatusCode', $rule['body']);
|
||||
$this->assertArrayHasKey('deploymentResourceType', $rule['body']);
|
||||
$this->assertArrayHasKey('deploymentId', $rule['body']);
|
||||
$this->assertArrayHasKey('deploymentResourceId', $rule['body']);
|
||||
$this->assertArrayHasKey('deploymentVcsProviderBranch', $rule['body']);
|
||||
$this->assertArrayHasKey('logs', $rule['body']);
|
||||
$this->assertArrayHasKey('renewAt', $rule['body']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
}
|
||||
|
||||
public function testListRules()
|
||||
{
|
||||
$rules = $this->listRules();
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
foreach ($rules['body']['rules'] as $rule) {
|
||||
$rule = $this->deleteRule($rule['$id']);
|
||||
$this->assertEquals(204, $rule['headers']['status-code']);
|
||||
}
|
||||
|
||||
return new CURLFile($tarPath, 'application/x-gzip', \basename($tarPath));
|
||||
$rules = $this->listRules();
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(0, $rules['body']['total']);
|
||||
$this->assertCount(0, $rules['body']['rules']);
|
||||
|
||||
$rule1Domain = \uniqid() . '-list1.custom.localhost';
|
||||
$rule1Id = $this->setupAPIRule($rule1Domain);
|
||||
$this->assertNotEmpty($rule1Id);
|
||||
|
||||
$rules = $this->listRules();
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(1, $rules['body']['total']);
|
||||
$this->assertCount(1, $rules['body']['rules']);
|
||||
$this->assertEquals($rule1Domain, $rules['body']['rules'][0]['domain']);
|
||||
|
||||
$this->assertEquals('manual', $rules['body']['rules'][0]['trigger']);
|
||||
$this->assertArrayHasKey('$id', $rules['body']['rules'][0]);
|
||||
$this->assertArrayHasKey('domain', $rules['body']['rules'][0]);
|
||||
$this->assertArrayHasKey('type', $rules['body']['rules'][0]);
|
||||
$this->assertArrayHasKey('redirectUrl', $rules['body']['rules'][0]);
|
||||
$this->assertArrayHasKey('redirectStatusCode', $rules['body']['rules'][0]);
|
||||
$this->assertArrayHasKey('deploymentResourceType', $rules['body']['rules'][0]);
|
||||
$this->assertArrayHasKey('deploymentId', $rules['body']['rules'][0]);
|
||||
$this->assertArrayHasKey('deploymentResourceId', $rules['body']['rules'][0]);
|
||||
$this->assertArrayHasKey('deploymentVcsProviderBranch', $rules['body']['rules'][0]);
|
||||
$this->assertArrayHasKey('logs', $rules['body']['rules'][0]);
|
||||
$this->assertArrayHasKey('renewAt', $rules['body']['rules'][0]);
|
||||
|
||||
$rule2Domain = \uniqid() . '-list1.custom.localhost';
|
||||
$rule2Id = $this->setupAPIRule($rule2Domain);
|
||||
$this->assertNotEmpty($rule2Id);
|
||||
|
||||
$rules = $this->listRules();
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(2, $rules['body']['total']);
|
||||
$this->assertCount(2, $rules['body']['rules']);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::limit(1)->toString()
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(2, $rules['body']['total']);
|
||||
$this->assertCount(1, $rules['body']['rules']);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::equal('$id', [$rule1Id])->toString()
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertCount(1, $rules['body']['rules']);
|
||||
$this->assertEquals($rule1Domain, $rules['body']['rules'][0]['domain']);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::orderDesc('$id')->toString()
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertCount(2, $rules['body']['rules']);
|
||||
$this->assertEquals($rule2Id, $rules['body']['rules'][0]['$id']);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::equal('domain', [$rule2Domain])->toString()
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertCount(1, $rules['body']['rules']);
|
||||
$this->assertEquals($rule2Id, $rules['body']['rules'][0]['$id']);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'search' => $rule1Domain,
|
||||
'queries' => [ Query::orderDesc('$createdAt')->toString() ]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$ruleIds = \array_column($rules['body']['rules'], '$id');
|
||||
$this->assertContains($rule1Id, $ruleIds);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'search' => $rule2Domain,
|
||||
'queries' => [ Query::orderDesc('$createdAt')->toString() ]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$ruleIds = \array_column($rules['body']['rules'], '$id');
|
||||
$this->assertContains($rule2Id, $ruleIds);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'search' => $rule1Id,
|
||||
'queries' => [ Query::orderDesc('$createdAt')->toString() ]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$ruleDomains = \array_column($rules['body']['rules'], 'domain');
|
||||
$this->assertContains($rule1Domain, $ruleDomains);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'search' => $rule2Id,
|
||||
'queries' => [ Query::orderDesc('$createdAt')->toString() ]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$ruleDomains = \array_column($rules['body']['rules'], 'domain');
|
||||
$this->assertContains($rule2Domain, $ruleDomains);
|
||||
|
||||
$rules = $this->listRules();
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
foreach ($rules['body']['rules'] as $rule) {
|
||||
$rule = $this->deleteRule($rule['$id']);
|
||||
$this->assertEquals(204, $rule['headers']['status-code']);
|
||||
}
|
||||
|
||||
$rules = $this->listRules();
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(0, $rules['body']['total']);
|
||||
$this->assertCount(0, $rules['body']['rules']);
|
||||
}
|
||||
|
||||
public function testRuleVerification(): void
|
||||
{
|
||||
|
||||
// 1. Site rule can verify
|
||||
$site = $this->setupSite();
|
||||
$siteId = $site['siteId'];
|
||||
|
||||
$rule = $this->createSiteRule('stage-site.webapp.com', $siteId);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('verifying', $rule['body']['status']);
|
||||
$this->assertEmpty($rule['body']['logs']);
|
||||
$this->assertNotEmpty($rule['body']['$id']);
|
||||
$ruleId = $rule['body']['$id'];
|
||||
|
||||
$rule = $this->updateRuleStatus($ruleId);
|
||||
$this->assertEquals(200, $rule['headers']['status-code']);
|
||||
$this->assertEquals($ruleId, $rule['body']['$id']);
|
||||
$this->assertEquals('verifying', $rule['body']['status']);
|
||||
$this->assertEmpty($rule['body']['logs']);
|
||||
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
$this->cleanupSite($siteId);
|
||||
|
||||
// 2. Function rule can verify
|
||||
$function = $this->setupFunction();
|
||||
$functionId = $function['functionId'];
|
||||
|
||||
$rule = $this->createFunctionRule('stage-function.webapp.com', $functionId);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('verifying', $rule['body']['status']);
|
||||
$this->assertEmpty($rule['body']['logs']);
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
|
||||
$rule = $this->createAPIRule('stage-site.webapp.com');
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('unverified', $rule['body']['status']);
|
||||
$this->assertStringContainsString('has incorrect CNAME value', $rule['body']['logs']);
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
|
||||
$this->cleanupFunction($functionId);
|
||||
|
||||
// 3. Wrong A record fails to verify
|
||||
$rule = $this->createAPIRule('wrong-a-webapp.com');
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('unverified', $rule['body']['status']);
|
||||
$this->assertStringContainsString('is missing CNAME record', $rule['body']['logs']);
|
||||
|
||||
$ruleId = $rule['body']['$id'];
|
||||
$rule = $this->updateRuleStatus($ruleId);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
$this->assertStringContainsString('is missing CNAME record', $rule['body']['message']);
|
||||
|
||||
$rule = $this->getRule($ruleId);
|
||||
$this->assertEquals(200, $rule['headers']['status-code']);
|
||||
$this->assertEquals('unverified', $rule['body']['status']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
|
||||
// 4. Correct A record can verify
|
||||
$rule = $this->createAPIRule('webapp.com');
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('verifying', $rule['body']['status']);
|
||||
$this->assertEmpty($rule['body']['logs']);
|
||||
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
|
||||
// 5. Correct CNAME record can verify (no CAA record)
|
||||
$rule = $this->createAPIRule('stage.webapp.com');
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('verifying', $rule['body']['status']);
|
||||
$this->assertEmpty($rule['body']['logs']);
|
||||
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
|
||||
// 6. Missing CNAME record fails to verify
|
||||
$rule = $this->createAPIRule('stage-missing-cname.webapp.com');
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('unverified', $rule['body']['status']);
|
||||
$this->assertStringContainsString('is missing CNAME record', $rule['body']['logs']);
|
||||
|
||||
$ruleId = $rule['body']['$id'];
|
||||
$rule = $this->updateRuleStatus($ruleId);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
$this->assertStringContainsString('is missing CNAME record', $rule['body']['message']);
|
||||
|
||||
$rule = $this->getRule($ruleId);
|
||||
$this->assertEquals(200, $rule['headers']['status-code']);
|
||||
$this->assertEquals('unverified', $rule['body']['status']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
|
||||
// 7. Wrong CNAME record fails to verify
|
||||
$rule = $this->createAPIRule('stage-wrong-cname.webapp.com');
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('unverified', $rule['body']['status']);
|
||||
$this->assertStringContainsString('has incorrect CNAME value', $rule['body']['logs']);
|
||||
|
||||
$ruleId = $rule['body']['$id'];
|
||||
$rule = $this->updateRuleStatus($ruleId);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
$this->assertStringContainsString('has incorrect CNAME value', $rule['body']['message']);
|
||||
|
||||
$rule = $this->getRule($ruleId);
|
||||
$this->assertEquals(200, $rule['headers']['status-code']);
|
||||
$this->assertEquals('unverified', $rule['body']['status']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
|
||||
// 8. Wrong CAA record fails to verify
|
||||
$rule = $this->createAPIRule('stage-wrong-caa.webapp.com');
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('unverified', $rule['body']['status']);
|
||||
$this->assertStringContainsString('has incorrect CAA value', $rule['body']['logs']);
|
||||
|
||||
$ruleId = $rule['body']['$id'];
|
||||
$rule = $this->updateRuleStatus($ruleId);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
$this->assertStringContainsString('has incorrect CAA value', $rule['body']['message']);
|
||||
|
||||
$rule = $this->getRule($ruleId);
|
||||
$this->assertEquals(200, $rule['headers']['status-code']);
|
||||
$this->assertEquals('unverified', $rule['body']['status']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
|
||||
// 9. Correct CAA record can verify
|
||||
$rule = $this->createAPIRule('stage-correct-caa.webapp.com');
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('verifying', $rule['body']['status']);
|
||||
$this->assertEmpty($rule['body']['logs']);
|
||||
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
}
|
||||
|
||||
public function testUpdateRuleVerificationWithSameDataUpdatesTimestamp(): void
|
||||
{
|
||||
$domain = \uniqid() . '-timestamp-test.webapp.com';
|
||||
$rule = $this->createAPIRule($domain);
|
||||
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('unverified', $rule['body']['status']);
|
||||
$this->assertNotEmpty($rule['body']['logs']);
|
||||
|
||||
$ruleId = $rule['body']['$id'];
|
||||
$initialUpdatedAt = $rule['body']['$updatedAt'];
|
||||
$initiallogs = $rule['body']['logs'];
|
||||
|
||||
sleep(1);
|
||||
|
||||
$updatedRule = $this->updateRuleStatus($ruleId);
|
||||
|
||||
$this->assertEquals(400, $updatedRule['headers']['status-code']);
|
||||
$this->assertStringContainsString($initiallogs, $updatedRule['body']['message']);
|
||||
|
||||
$ruleAfterUpdate = $this->getRule($ruleId);
|
||||
$this->assertEquals(200, $ruleAfterUpdate['headers']['status-code']);
|
||||
$this->assertEquals('unverified', $ruleAfterUpdate['body']['status']);
|
||||
$this->assertEquals($initiallogs, $ruleAfterUpdate['body']['logs']);
|
||||
$this->assertNotEquals($initialUpdatedAt, $ruleAfterUpdate['body']['$updatedAt']);
|
||||
|
||||
$initialTime = new \DateTime($initialUpdatedAt);
|
||||
$updatedTime = new \DateTime($ruleAfterUpdate['body']['$updatedAt']);
|
||||
$this->assertGreaterThan($initialTime, $updatedTime);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Proxy;
|
||||
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideConsole;
|
||||
|
||||
class ProxyConsoleClientTest extends Scope
|
||||
{
|
||||
use ProxyBase;
|
||||
use ProjectCustom;
|
||||
use SideConsole;
|
||||
}
|
||||
@@ -2,758 +2,13 @@
|
||||
|
||||
namespace Tests\E2E\Services\Proxy;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideServer;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\System\System;
|
||||
|
||||
class ProxyCustomServerTest extends Scope
|
||||
{
|
||||
use ProxyBase;
|
||||
use ProjectCustom;
|
||||
use SideServer;
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
// Cleanup for testRuleVerification test
|
||||
// Required as it uses static domain name
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::endsWith('domain', 'webapp.com')->toString(),
|
||||
Query::limit(1000)->toString(),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
foreach ($rules['body']['rules'] as $rule) {
|
||||
$ruleId = $rule['$id'];
|
||||
$response = $this->deleteRule($ruleId);
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
}
|
||||
|
||||
if ($rules['body']['total'] > 0) {
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::endsWith('domain', 'webapp.com')->toString(),
|
||||
Query::limit(1)->toString()
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(0, count($rules['body']['rules']));
|
||||
$this->assertEquals(0, $rules['body']['total']);
|
||||
}
|
||||
}
|
||||
|
||||
public function testCreateRule(): void
|
||||
{
|
||||
$domain = \uniqid() . '-api.myapp.com';
|
||||
$rule = $this->createAPIRule($domain);
|
||||
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals($domain, $rule['body']['domain']);
|
||||
$this->assertEquals('manual', $rule['body']['trigger']);
|
||||
$this->assertArrayHasKey('$id', $rule['body']);
|
||||
$this->assertArrayHasKey('domain', $rule['body']);
|
||||
$this->assertArrayHasKey('type', $rule['body']);
|
||||
$this->assertArrayHasKey('redirectUrl', $rule['body']);
|
||||
$this->assertArrayHasKey('redirectStatusCode', $rule['body']);
|
||||
$this->assertArrayHasKey('deploymentResourceType', $rule['body']);
|
||||
$this->assertArrayHasKey('deploymentId', $rule['body']);
|
||||
$this->assertArrayHasKey('deploymentResourceId', $rule['body']);
|
||||
$this->assertArrayHasKey('deploymentVcsProviderBranch', $rule['body']);
|
||||
$this->assertArrayHasKey('logs', $rule['body']);
|
||||
$this->assertArrayHasKey('renewAt', $rule['body']);
|
||||
|
||||
$ruleId = $rule['body']['$id'];
|
||||
|
||||
$rule = $this->createAPIRule($domain);
|
||||
$this->assertEquals(409, $rule['headers']['status-code']);
|
||||
|
||||
$rule = $this->deleteRule($ruleId);
|
||||
|
||||
$this->assertEquals(204, $rule['headers']['status-code']);
|
||||
}
|
||||
|
||||
public function testCreateRuleSetup(): void
|
||||
{
|
||||
$ruleId = $this->setupAPIRule(\uniqid() . '-api2.myapp.com');
|
||||
$this->cleanupRule($ruleId);
|
||||
}
|
||||
|
||||
public function testCreateRuleApex(): void
|
||||
{
|
||||
$domain = \uniqid() . '.com';
|
||||
$rule = $this->createAPIRule($domain);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('created', $rule['body']['status']);
|
||||
}
|
||||
|
||||
public function testCreateRuleVcs(): void
|
||||
{
|
||||
$domain = \uniqid() . '-vcs.myapp.com';
|
||||
|
||||
$setup = $this->setupSite();
|
||||
$siteId = $setup['siteId'];
|
||||
$deploymentId = $setup['deploymentId'];
|
||||
|
||||
$this->assertNotEmpty($siteId);
|
||||
$this->assertNotEmpty($deploymentId);
|
||||
|
||||
$rule = $this->createSiteRule('commit-' . $domain, $siteId);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
|
||||
$rule = $this->createSiteRule('branch-' . $domain, $siteId);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
|
||||
$rule = $this->createSiteRule('anything-' . $domain, $siteId);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
|
||||
$sitesDomain = \explode(',', System::getEnv('_APP_DOMAIN_SITES', ''))[0];
|
||||
$domain = \uniqid() . '-vcs.' . $sitesDomain;
|
||||
|
||||
$rule = $this->createSiteRule('commit-' . $domain, $siteId);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
|
||||
$rule = $this->createSiteRule('branch-' . $domain, $siteId);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
|
||||
$rule = $this->createSiteRule('subdomain.anything-' . $domain, $siteId);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
|
||||
$rule = $this->createSiteRule('anything-' . $domain, $siteId);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
}
|
||||
|
||||
public function testCreateAPIRule(): void
|
||||
{
|
||||
$domain = \uniqid() . '-api.custom.localhost';
|
||||
|
||||
$proxyClient = new Client();
|
||||
$proxyClient->setEndpoint('http://appwrite.test');
|
||||
$proxyClient->addHeader('x-appwrite-hostname', $domain);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/versions');
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
|
||||
$ruleId = $this->setupAPIRule($domain);
|
||||
|
||||
$this->assertNotEmpty($ruleId);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/versions');
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(APP_VERSION_STABLE, $response['body']['server']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
|
||||
$rule = $this->createAPIRule('http://' . $domain);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
|
||||
$rule = $this->createAPIRule('https://' . $domain);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
|
||||
$rule = $this->createAPIRule('wss://' . $domain);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
|
||||
$rule = $this->createAPIRule($domain . '/some-path');
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
}
|
||||
|
||||
public function testCreateRedirectRule(): void
|
||||
{
|
||||
$domain = \uniqid() . '-redirect.custom.localhost';
|
||||
|
||||
$proxyClient = new Client();
|
||||
$proxyClient->setEndpoint('http://appwrite.test');
|
||||
$proxyClient->addHeader('x-appwrite-hostname', $domain);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/todos/1');
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
|
||||
$siteId = $this->setupSite()['siteId'];
|
||||
|
||||
$ruleId = $this->setupRedirectRule($domain, 'https://jsonplaceholder.typicode.com/todos/1', 301, 'site', $siteId);
|
||||
$this->assertNotEmpty($ruleId);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/todos/1');
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(1, $response['body']['id']);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/');
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(1, $response['body']['id']);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/', followRedirects: false);
|
||||
$this->assertEquals(301, $response['headers']['status-code']);
|
||||
$this->assertEquals('https://jsonplaceholder.typicode.com/todos/1', $response['headers']['location']);
|
||||
|
||||
$domain = \uniqid() . '-redirect-307.custom.localhost';
|
||||
$ruleId = $this->setupRedirectRule($domain, 'https://jsonplaceholder.typicode.com/todos/1', 307, 'site', $siteId);
|
||||
$this->assertNotEmpty($ruleId);
|
||||
|
||||
$proxyClient = new Client();
|
||||
$proxyClient->setEndpoint('http://appwrite.test');
|
||||
$proxyClient->addHeader('x-appwrite-hostname', $domain);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/', followRedirects: false);
|
||||
$this->assertEquals(307, $response['headers']['status-code']);
|
||||
$this->assertEquals('https://jsonplaceholder.typicode.com/todos/1', $response['headers']['location']);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::equal('type', ['redirect'])->toString(),
|
||||
Query::equal('trigger', ['manual'])->toString(),
|
||||
Query::equal('deploymentResourceType', ['site'])->toString(),
|
||||
Query::equal('deploymentResourceId', [$siteId])->toString(),
|
||||
],
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(2, $rules['body']['total']);
|
||||
|
||||
$this->cleanupSite($siteId);
|
||||
$this->cleanupRule($ruleId);
|
||||
}
|
||||
|
||||
public function testCreateFunctionRule(): void
|
||||
{
|
||||
$domain = \uniqid() . '-function.custom.localhost';
|
||||
|
||||
$proxyClient = new Client();
|
||||
$proxyClient->setEndpoint('http://appwrite.test');
|
||||
$proxyClient->addHeader('x-appwrite-hostname', $domain);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/ping');
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
|
||||
$setup = $this->setupFunction();
|
||||
$functionId = $setup['functionId'];
|
||||
$deploymentId = $setup['deploymentId'];
|
||||
|
||||
$this->assertNotEmpty($functionId);
|
||||
$this->assertNotEmpty($deploymentId);
|
||||
|
||||
$ruleId = $this->setupFunctionRule($domain, $functionId);
|
||||
$this->assertNotEmpty($ruleId);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/ping');
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals($functionId, $response['body']['APPWRITE_FUNCTION_ID']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
|
||||
$this->cleanupFunction($functionId);
|
||||
|
||||
$this->assertEventually(function () use ($functionId, $deploymentId) {
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::limit(1)->toString(),
|
||||
Query::equal('type', ['deployment'])->toString(),
|
||||
Query::equal('deploymentResourceType', ['function'])->toString(),
|
||||
Query::equal('deploymentResourceId', [$functionId])->toString(),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(0, $rules['body']['total']);
|
||||
$this->assertCount(0, $rules['body']['rules']);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::limit(1)->toString(),
|
||||
Query::equal('type', ['deployment'])->toString(),
|
||||
Query::equal('deploymentId', [$deploymentId])->toString()
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(0, $rules['body']['total']);
|
||||
$this->assertCount(0, $rules['body']['rules']);
|
||||
});
|
||||
}
|
||||
|
||||
public function testCreateSiteRule(): void
|
||||
{
|
||||
$domain = \uniqid() . '-site.custom.localhost';
|
||||
|
||||
$proxyClient = new Client();
|
||||
$proxyClient->setEndpoint('http://appwrite.test');
|
||||
$proxyClient->addHeader('x-appwrite-hostname', $domain);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/contact');
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
|
||||
$setup = $this->setupSite();
|
||||
$siteId = $setup['siteId'];
|
||||
$deploymentId = $setup['deploymentId'];
|
||||
|
||||
$this->assertNotEmpty($siteId);
|
||||
$this->assertNotEmpty($deploymentId);
|
||||
|
||||
$ruleId = $this->setupSiteRule($domain, $siteId);
|
||||
$this->assertNotEmpty($ruleId);
|
||||
$rule = $this->getRule($ruleId);
|
||||
$this->assertSame(200, $rule['headers']['status-code']);
|
||||
$this->assertSame('created', $rule['body']['status']);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/contact');
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString('Contact page', $response['body']);
|
||||
|
||||
// Wildcard domains automatically get verified status
|
||||
$domains = [
|
||||
\uniqid() . '.sites.localhost',
|
||||
\uniqid() . '.rebranded.localhost',
|
||||
];
|
||||
foreach ($domains as $domain) {
|
||||
$wildcardRuleId = $this->setupSiteRule($domain, $siteId);
|
||||
$this->assertNotEmpty($wildcardRuleId);
|
||||
$rule = $this->getRule($wildcardRuleId);
|
||||
$this->assertSame(200, $rule['headers']['status-code']);
|
||||
$this->assertSame('verified', $rule['body']['status']);
|
||||
$this->cleanupRule($wildcardRuleId);
|
||||
}
|
||||
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::limit(1)->toString(),
|
||||
Query::equal('trigger', ['deployment'])->toString(),
|
||||
Query::equal('type', ['deployment'])->toString(),
|
||||
Query::equal('deploymentResourceType', ['site'])->toString(),
|
||||
Query::equal('deploymentResourceId', [$siteId])->toString(),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertGreaterThan(0, $rules['body']['total']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
|
||||
$this->cleanupSite($siteId);
|
||||
|
||||
$this->assertEventually(function () use ($siteId, $deploymentId) {
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::limit(1)->toString(),
|
||||
Query::equal('type', ['deployment'])->toString(),
|
||||
Query::equal('deploymentResourceType', ['site'])->toString(),
|
||||
Query::equal('deploymentResourceId', [$siteId])->toString(),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(0, $rules['body']['total']);
|
||||
$this->assertCount(0, $rules['body']['rules']);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::limit(1)->toString(),
|
||||
Query::equal('type', ['deployment'])->toString(),
|
||||
Query::equal('deploymentId', [$deploymentId])->toString()
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(0, $rules['body']['total']);
|
||||
$this->assertCount(0, $rules['body']['rules']);
|
||||
});
|
||||
}
|
||||
|
||||
public function testCreateSiteBranchRule(): void
|
||||
{
|
||||
$domain = \uniqid() . '-site-branch.custom.localhost';
|
||||
|
||||
$setup = $this->setupSite();
|
||||
$siteId = $setup['siteId'];
|
||||
$deploymentId = $setup['deploymentId'];
|
||||
|
||||
$this->assertNotEmpty($siteId);
|
||||
$this->assertNotEmpty($deploymentId);
|
||||
|
||||
$ruleId = $this->setupSiteRule($domain, $siteId, 'dev');
|
||||
$this->assertNotEmpty($ruleId);
|
||||
|
||||
$rule = $this->getRule($ruleId);
|
||||
$this->assertEquals(200, $rule['headers']['status-code']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
}
|
||||
|
||||
public function testCreateFunctionBranchRule(): void
|
||||
{
|
||||
$domain = \uniqid() . '-function-branch.custom.localhost';
|
||||
|
||||
$setup = $this->setupFunction();
|
||||
$functionId = $setup['functionId'];
|
||||
$deploymentId = $setup['deploymentId'];
|
||||
|
||||
$this->assertNotEmpty($functionId);
|
||||
$this->assertNotEmpty($deploymentId);
|
||||
|
||||
$ruleId = $this->setupFunctionRule($domain, $functionId, 'dev');
|
||||
$this->assertNotEmpty($ruleId);
|
||||
|
||||
$rule = $this->getRule($ruleId);
|
||||
$this->assertEquals(200, $rule['headers']['status-code']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
|
||||
$this->cleanupFunction($functionId);
|
||||
}
|
||||
|
||||
public function testUpdateRule(): void
|
||||
{
|
||||
// Create function appwrite-network domain
|
||||
$functionsDomain = \explode(',', System::getEnv('_APP_DOMAIN_FUNCTIONS', ''))[0];
|
||||
$domain = \uniqid() . '-cname-api.' . $functionsDomain;
|
||||
|
||||
$rule = $this->createAPIRule($domain);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('verified', $rule['body']['status']);
|
||||
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
|
||||
// Create site appwrite-network domain
|
||||
$sitesDomain = \explode(',', System::getEnv('_APP_DOMAIN_SITES', ''))[0];
|
||||
$domain = \uniqid() . '-cname-api.' . $sitesDomain;
|
||||
|
||||
$rule = $this->createAPIRule($domain);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('verified', $rule['body']['status']);
|
||||
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
|
||||
// Create + update
|
||||
$domain = \uniqid() . '-cname-api.custom.com';
|
||||
|
||||
$rule = $this->createAPIRule($domain);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('created', $rule['body']['status']);
|
||||
|
||||
$ruleId = $rule['body']['$id'];
|
||||
|
||||
$rule = $this->updateRuleVerification($ruleId);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
}
|
||||
|
||||
public function testGetRule()
|
||||
{
|
||||
$domain = \uniqid() . '-get.custom.localhost';
|
||||
$ruleId = $this->setupAPIRule($domain);
|
||||
|
||||
$this->assertNotEmpty($ruleId);
|
||||
|
||||
$rule = $this->getRule($ruleId);
|
||||
$this->assertEquals(200, $rule['headers']['status-code']);
|
||||
$this->assertEquals($domain, $rule['body']['domain']);
|
||||
$this->assertEquals('manual', $rule['body']['trigger']);
|
||||
$this->assertArrayHasKey('$id', $rule['body']);
|
||||
$this->assertArrayHasKey('domain', $rule['body']);
|
||||
$this->assertArrayHasKey('type', $rule['body']);
|
||||
$this->assertArrayHasKey('redirectUrl', $rule['body']);
|
||||
$this->assertArrayHasKey('redirectStatusCode', $rule['body']);
|
||||
$this->assertArrayHasKey('deploymentResourceType', $rule['body']);
|
||||
$this->assertArrayHasKey('deploymentId', $rule['body']);
|
||||
$this->assertArrayHasKey('deploymentResourceId', $rule['body']);
|
||||
$this->assertArrayHasKey('deploymentVcsProviderBranch', $rule['body']);
|
||||
$this->assertArrayHasKey('logs', $rule['body']);
|
||||
$this->assertArrayHasKey('renewAt', $rule['body']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
}
|
||||
|
||||
public function testListRules()
|
||||
{
|
||||
$rules = $this->listRules();
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
foreach ($rules['body']['rules'] as $rule) {
|
||||
$rule = $this->deleteRule($rule['$id']);
|
||||
$this->assertEquals(204, $rule['headers']['status-code']);
|
||||
}
|
||||
|
||||
$rules = $this->listRules();
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(0, $rules['body']['total']);
|
||||
$this->assertCount(0, $rules['body']['rules']);
|
||||
|
||||
$rule1Domain = \uniqid() . '-list1.custom.localhost';
|
||||
$rule1Id = $this->setupAPIRule($rule1Domain);
|
||||
$this->assertNotEmpty($rule1Id);
|
||||
|
||||
$rules = $this->listRules();
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(1, $rules['body']['total']);
|
||||
$this->assertCount(1, $rules['body']['rules']);
|
||||
$this->assertEquals($rule1Domain, $rules['body']['rules'][0]['domain']);
|
||||
|
||||
$this->assertEquals('manual', $rules['body']['rules'][0]['trigger']);
|
||||
$this->assertArrayHasKey('$id', $rules['body']['rules'][0]);
|
||||
$this->assertArrayHasKey('domain', $rules['body']['rules'][0]);
|
||||
$this->assertArrayHasKey('type', $rules['body']['rules'][0]);
|
||||
$this->assertArrayHasKey('redirectUrl', $rules['body']['rules'][0]);
|
||||
$this->assertArrayHasKey('redirectStatusCode', $rules['body']['rules'][0]);
|
||||
$this->assertArrayHasKey('deploymentResourceType', $rules['body']['rules'][0]);
|
||||
$this->assertArrayHasKey('deploymentId', $rules['body']['rules'][0]);
|
||||
$this->assertArrayHasKey('deploymentResourceId', $rules['body']['rules'][0]);
|
||||
$this->assertArrayHasKey('deploymentVcsProviderBranch', $rules['body']['rules'][0]);
|
||||
$this->assertArrayHasKey('logs', $rules['body']['rules'][0]);
|
||||
$this->assertArrayHasKey('renewAt', $rules['body']['rules'][0]);
|
||||
|
||||
$rule2Domain = \uniqid() . '-list1.custom.localhost';
|
||||
$rule2Id = $this->setupAPIRule($rule2Domain);
|
||||
$this->assertNotEmpty($rule2Id);
|
||||
|
||||
$rules = $this->listRules();
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(2, $rules['body']['total']);
|
||||
$this->assertCount(2, $rules['body']['rules']);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::limit(1)->toString()
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(2, $rules['body']['total']);
|
||||
$this->assertCount(1, $rules['body']['rules']);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::equal('$id', [$rule1Id])->toString()
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertCount(1, $rules['body']['rules']);
|
||||
$this->assertEquals($rule1Domain, $rules['body']['rules'][0]['domain']);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::orderDesc('$id')->toString()
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertCount(2, $rules['body']['rules']);
|
||||
$this->assertEquals($rule2Id, $rules['body']['rules'][0]['$id']);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::equal('domain', [$rule2Domain])->toString()
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertCount(1, $rules['body']['rules']);
|
||||
$this->assertEquals($rule2Id, $rules['body']['rules'][0]['$id']);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'search' => $rule1Domain,
|
||||
'queries' => [ Query::orderDesc('$createdAt')->toString() ]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$ruleIds = \array_column($rules['body']['rules'], '$id');
|
||||
$this->assertContains($rule1Id, $ruleIds);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'search' => $rule2Domain,
|
||||
'queries' => [ Query::orderDesc('$createdAt')->toString() ]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$ruleIds = \array_column($rules['body']['rules'], '$id');
|
||||
$this->assertContains($rule2Id, $ruleIds);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'search' => $rule1Id,
|
||||
'queries' => [ Query::orderDesc('$createdAt')->toString() ]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$ruleDomains = \array_column($rules['body']['rules'], 'domain');
|
||||
$this->assertContains($rule1Domain, $ruleDomains);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'search' => $rule2Id,
|
||||
'queries' => [ Query::orderDesc('$createdAt')->toString() ]
|
||||
]);
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$ruleDomains = \array_column($rules['body']['rules'], 'domain');
|
||||
$this->assertContains($rule2Domain, $ruleDomains);
|
||||
|
||||
$rules = $this->listRules();
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
foreach ($rules['body']['rules'] as $rule) {
|
||||
$rule = $this->deleteRule($rule['$id']);
|
||||
$this->assertEquals(204, $rule['headers']['status-code']);
|
||||
}
|
||||
|
||||
$rules = $this->listRules();
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(0, $rules['body']['total']);
|
||||
$this->assertCount(0, $rules['body']['rules']);
|
||||
}
|
||||
|
||||
public function testRuleVerification(): void
|
||||
{
|
||||
|
||||
// 1. Site rule can verify
|
||||
$site = $this->setupSite();
|
||||
$siteId = $site['siteId'];
|
||||
|
||||
$rule = $this->createSiteRule('stage-site.webapp.com', $siteId);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('verifying', $rule['body']['status']);
|
||||
$this->assertEmpty($rule['body']['logs']);
|
||||
$this->assertNotEmpty($rule['body']['$id']);
|
||||
$ruleId = $rule['body']['$id'];
|
||||
|
||||
$rule = $this->updateRuleVerification($ruleId);
|
||||
$this->assertEquals(200, $rule['headers']['status-code']);
|
||||
$this->assertEquals($ruleId, $rule['body']['$id']);
|
||||
$this->assertEquals('verifying', $rule['body']['status']);
|
||||
$this->assertEmpty($rule['body']['logs']);
|
||||
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
$this->cleanupSite($siteId);
|
||||
|
||||
// 2. Function rule can verify
|
||||
$function = $this->setupFunction();
|
||||
$functionId = $function['functionId'];
|
||||
|
||||
$rule = $this->createFunctionRule('stage-function.webapp.com', $functionId);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('verifying', $rule['body']['status']);
|
||||
$this->assertEmpty($rule['body']['logs']);
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
|
||||
$rule = $this->createAPIRule('stage-site.webapp.com');
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('created', $rule['body']['status']);
|
||||
$this->assertStringContainsString('has incorrect CNAME value', $rule['body']['logs']);
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
|
||||
$this->cleanupFunction($functionId);
|
||||
|
||||
// 3. Wrong A record fails to verify
|
||||
$rule = $this->createAPIRule('wrong-a-webapp.com');
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('created', $rule['body']['status']);
|
||||
$this->assertStringContainsString('is missing CNAME record', $rule['body']['logs']);
|
||||
|
||||
$ruleId = $rule['body']['$id'];
|
||||
$rule = $this->updateRuleVerification($ruleId);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
$this->assertStringContainsString('is missing CNAME record', $rule['body']['message']);
|
||||
|
||||
$rule = $this->getRule($ruleId);
|
||||
$this->assertEquals(200, $rule['headers']['status-code']);
|
||||
$this->assertEquals('created', $rule['body']['status']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
|
||||
// 4. Correct A record can verify
|
||||
$rule = $this->createAPIRule('webapp.com');
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('verifying', $rule['body']['status']);
|
||||
$this->assertEmpty($rule['body']['logs']);
|
||||
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
|
||||
// 5. Correct CNAME record can verify (no CAA record)
|
||||
$rule = $this->createAPIRule('stage.webapp.com');
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('verifying', $rule['body']['status']);
|
||||
$this->assertEmpty($rule['body']['logs']);
|
||||
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
|
||||
// 6. Missing CNAME record fails to verify
|
||||
$rule = $this->createAPIRule('stage-missing-cname.webapp.com');
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('created', $rule['body']['status']);
|
||||
$this->assertStringContainsString('is missing CNAME record', $rule['body']['logs']);
|
||||
|
||||
$ruleId = $rule['body']['$id'];
|
||||
$rule = $this->updateRuleVerification($ruleId);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
$this->assertStringContainsString('is missing CNAME record', $rule['body']['message']);
|
||||
|
||||
$rule = $this->getRule($ruleId);
|
||||
$this->assertEquals(200, $rule['headers']['status-code']);
|
||||
$this->assertEquals('created', $rule['body']['status']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
|
||||
// 7. Wrong CNAME record fails to verify
|
||||
$rule = $this->createAPIRule('stage-wrong-cname.webapp.com');
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('created', $rule['body']['status']);
|
||||
$this->assertStringContainsString('has incorrect CNAME value', $rule['body']['logs']);
|
||||
|
||||
$ruleId = $rule['body']['$id'];
|
||||
$rule = $this->updateRuleVerification($ruleId);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
$this->assertStringContainsString('has incorrect CNAME value', $rule['body']['message']);
|
||||
|
||||
$rule = $this->getRule($ruleId);
|
||||
$this->assertEquals(200, $rule['headers']['status-code']);
|
||||
$this->assertEquals('created', $rule['body']['status']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
|
||||
// 8. Wrong CAA record fails to verify
|
||||
$rule = $this->createAPIRule('stage-wrong-caa.webapp.com');
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('created', $rule['body']['status']);
|
||||
$this->assertStringContainsString('has incorrect CAA value', $rule['body']['logs']);
|
||||
|
||||
$ruleId = $rule['body']['$id'];
|
||||
$rule = $this->updateRuleVerification($ruleId);
|
||||
$this->assertEquals(400, $rule['headers']['status-code']);
|
||||
$this->assertStringContainsString('has incorrect CAA value', $rule['body']['message']);
|
||||
|
||||
$rule = $this->getRule($ruleId);
|
||||
$this->assertEquals(200, $rule['headers']['status-code']);
|
||||
$this->assertEquals('created', $rule['body']['status']);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
|
||||
// 9. Correct CAA record can verify
|
||||
$rule = $this->createAPIRule('stage-correct-caa.webapp.com');
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('verifying', $rule['body']['status']);
|
||||
$this->assertEmpty($rule['body']['logs']);
|
||||
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
}
|
||||
|
||||
public function testUpdateRuleVerificationWithSameDataUpdatesTimestamp(): void
|
||||
{
|
||||
$domain = \uniqid() . '-timestamp-test.webapp.com';
|
||||
$rule = $this->createAPIRule($domain);
|
||||
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals('created', $rule['body']['status']);
|
||||
$this->assertNotEmpty($rule['body']['logs']);
|
||||
|
||||
$ruleId = $rule['body']['$id'];
|
||||
$initialUpdatedAt = $rule['body']['$updatedAt'];
|
||||
$initiallogs = $rule['body']['logs'];
|
||||
|
||||
sleep(1);
|
||||
|
||||
$updatedRule = $this->updateRuleVerification($ruleId);
|
||||
|
||||
$this->assertEquals(400, $updatedRule['headers']['status-code']);
|
||||
$this->assertStringContainsString($initiallogs, $updatedRule['body']['message']);
|
||||
|
||||
$ruleAfterUpdate = $this->getRule($ruleId);
|
||||
$this->assertEquals(200, $ruleAfterUpdate['headers']['status-code']);
|
||||
$this->assertEquals('created', $ruleAfterUpdate['body']['status']);
|
||||
$this->assertEquals($initiallogs, $ruleAfterUpdate['body']['logs']);
|
||||
$this->assertNotEquals($initialUpdatedAt, $ruleAfterUpdate['body']['$updatedAt']);
|
||||
|
||||
$initialTime = new \DateTime($initialUpdatedAt);
|
||||
$updatedTime = new \DateTime($ruleAfterUpdate['body']['$updatedAt']);
|
||||
$this->assertGreaterThan($initialTime, $updatedTime);
|
||||
|
||||
$this->cleanupRule($ruleId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Proxy;
|
||||
|
||||
use Appwrite\ID;
|
||||
use Appwrite\Tests\Async;
|
||||
use CURLFile;
|
||||
use Tests\E2E\Client;
|
||||
use Utopia\Console;
|
||||
|
||||
trait ProxyHelpers
|
||||
{
|
||||
use Async;
|
||||
|
||||
protected function listRules(array $params = []): mixed
|
||||
{
|
||||
$rule = $this->client->call(Client::METHOD_GET, '/proxy/rules', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), $params);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
protected function createAPIRule(string $domain): mixed
|
||||
{
|
||||
$rule = $this->client->call(Client::METHOD_POST, '/proxy/rules/api', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'domain' => $domain,
|
||||
]);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
protected function updateRuleStatus(string $ruleId): mixed
|
||||
{
|
||||
$rule = $this->client->call(Client::METHOD_PATCH, '/proxy/rules/' . $ruleId . '/status', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
protected function createSiteRule(string $domain, string $siteId, string $branch = ''): mixed
|
||||
{
|
||||
$rule = $this->client->call(Client::METHOD_POST, '/proxy/rules/site', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'domain' => $domain,
|
||||
'siteId' => $siteId,
|
||||
'branch' => $branch,
|
||||
]);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
protected function getRule(string $ruleId): mixed
|
||||
{
|
||||
$rule = $this->client->call(Client::METHOD_GET, '/proxy/rules/' . $ruleId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
protected function createRedirectRule(string $domain, string $url, int $statusCode, string $resourceType, string $resourceId): mixed
|
||||
{
|
||||
$rule = $this->client->call(Client::METHOD_POST, '/proxy/rules/redirect', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'domain' => $domain,
|
||||
'url' => $url,
|
||||
'statusCode' => $statusCode,
|
||||
'resourceType' => $resourceType,
|
||||
'resourceId' => $resourceId,
|
||||
]);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
protected function createFunctionRule(string $domain, string $functionId, string $branch = ''): mixed
|
||||
{
|
||||
$rule = $this->client->call(Client::METHOD_POST, '/proxy/rules/function', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'domain' => $domain,
|
||||
'functionId' => $functionId,
|
||||
'branch' => $branch,
|
||||
]);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
protected function deleteRule(string $ruleId): mixed
|
||||
{
|
||||
$rule = $this->client->call(Client::METHOD_DELETE, '/proxy/rules/' . $ruleId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
protected function setupAPIRule(string $domain): string
|
||||
{
|
||||
$rule = $this->createAPIRule($domain);
|
||||
|
||||
$this->assertEquals(201, $rule['headers']['status-code'], 'Failed to setup rule: ' . \json_encode($rule));
|
||||
|
||||
return $rule['body']['$id'];
|
||||
}
|
||||
|
||||
protected function setupRedirectRule(string $domain, string $url, int $statusCode, string $resourceType, string $resourceId): string
|
||||
{
|
||||
$rule = $this->createRedirectRule($domain, $url, $statusCode, $resourceType, $resourceId);
|
||||
|
||||
$this->assertEquals(201, $rule['headers']['status-code'], 'Failed to setup rule: ' . \json_encode($rule));
|
||||
|
||||
return $rule['body']['$id'];
|
||||
}
|
||||
|
||||
protected function setupFunctionRule(string $domain, string $functionId, string $branch = ''): string
|
||||
{
|
||||
$rule = $this->createFunctionRule($domain, $functionId, $branch);
|
||||
|
||||
$this->assertEquals(201, $rule['headers']['status-code'], 'Failed to setup rule: ' . \json_encode($rule));
|
||||
|
||||
return $rule['body']['$id'];
|
||||
}
|
||||
|
||||
protected function setupSiteRule(string $domain, string $siteId, string $branch = ''): string
|
||||
{
|
||||
$rule = $this->createSiteRule($domain, $siteId, $branch);
|
||||
|
||||
$this->assertEquals(201, $rule['headers']['status-code'], 'Failed to setup rule: ' . \json_encode($rule));
|
||||
|
||||
return $rule['body']['$id'];
|
||||
}
|
||||
|
||||
protected function cleanupRule(string $ruleId): void
|
||||
{
|
||||
$rule = $this->deleteRule($ruleId);
|
||||
$this->assertEquals(204, $rule['headers']['status-code'], 'Failed to cleanup rule: ' . \json_encode($rule));
|
||||
}
|
||||
|
||||
protected function cleanupSite(string $siteId): void
|
||||
{
|
||||
$site = $this->client->call(Client::METHOD_DELETE, '/sites/' . $siteId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
$this->assertEquals(204, $site['headers']['status-code'], 'Failed to cleanup site: ' . \json_encode($site));
|
||||
}
|
||||
|
||||
protected function cleanupFunction(string $functionId): void
|
||||
{
|
||||
$function = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
$this->assertEquals(204, $function['headers']['status-code'], 'Failed to cleanup function: ' . \json_encode($function));
|
||||
}
|
||||
|
||||
protected function setupSite(): mixed
|
||||
{
|
||||
// Site
|
||||
$site = $this->client->call(Client::METHOD_POST, '/sites', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'siteId' => ID::unique(),
|
||||
'name' => 'Proxy site',
|
||||
'framework' => 'other',
|
||||
'adapter' => 'static',
|
||||
'buildRuntime' => 'static-1',
|
||||
'outputDirectory' => './',
|
||||
'buildCommand' => '',
|
||||
'installCommand' => '',
|
||||
'fallbackFile' => '',
|
||||
]);
|
||||
|
||||
$this->assertEquals($site['headers']['status-code'], 201, 'Setup site failed with status code: ' . $site['headers']['status-code'] . ' and response: ' . json_encode($site['body'], JSON_PRETTY_PRINT));
|
||||
|
||||
$siteId = $site['body']['$id'];
|
||||
|
||||
// Deployment
|
||||
$deployment = $this->client->call(Client::METHOD_POST, '/sites/' . $siteId . '/deployments', array_merge([
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'code' => $this->packageSite('static'),
|
||||
'activate' => 'true'
|
||||
]);
|
||||
|
||||
$this->assertEquals($deployment['headers']['status-code'], 202, 'Setup deployment failed with status code: ' . $deployment['headers']['status-code'] . ' and response: ' . json_encode($deployment['body'], JSON_PRETTY_PRINT));
|
||||
$deploymentId = $deployment['body']['$id'] ?? '';
|
||||
|
||||
$this->assertEventually(function () use ($siteId, $deploymentId) {
|
||||
$site = $this->client->call(Client::METHOD_GET, '/sites/' . $siteId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
$this->assertEquals($deploymentId, $site['body']['deploymentId'], 'Deployment is not activated, deployment: ' . json_encode($site['body'], JSON_PRETTY_PRINT));
|
||||
}, 120000, 500);
|
||||
|
||||
return ['siteId' => $siteId, 'deploymentId' => $deploymentId];
|
||||
}
|
||||
|
||||
protected function setupFunction(): mixed
|
||||
{
|
||||
// Function
|
||||
$function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'functionId' => ID::unique(),
|
||||
'runtime' => 'node-22',
|
||||
'name' => 'Proxy Function',
|
||||
'entrypoint' => 'index.js',
|
||||
'commands' => '',
|
||||
'execute' => ['any']
|
||||
]);
|
||||
|
||||
$this->assertEquals($function['headers']['status-code'], 201, 'Setup function failed with status code: ' . $function['headers']['status-code'] . ' and response: ' . json_encode($function['body'], JSON_PRETTY_PRINT));
|
||||
|
||||
$functionId = $function['body']['$id'];
|
||||
|
||||
// Deployment
|
||||
$deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => 'true'
|
||||
]);
|
||||
|
||||
$this->assertEquals($deployment['headers']['status-code'], 202, 'Setup deployment failed with status code: ' . $deployment['headers']['status-code'] . ' and response: ' . json_encode($deployment['body'], JSON_PRETTY_PRINT));
|
||||
$deploymentId = $deployment['body']['$id'] ?? '';
|
||||
|
||||
$this->assertEventually(function () use ($functionId, $deploymentId) {
|
||||
$function = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
$this->assertEquals($deploymentId, $function['body']['deploymentId'], 'Deployment is not activated, deployment: ' . json_encode($function['body'], JSON_PRETTY_PRINT));
|
||||
}, 100000, 500);
|
||||
|
||||
return ['functionId' => $functionId, 'deploymentId' => $deploymentId];
|
||||
}
|
||||
|
||||
private function packageSite(string $site): CURLFile
|
||||
{
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
|
||||
$folderPath = realpath(__DIR__ . '/../../../resources/sites') . "/$site";
|
||||
$tarPath = "$folderPath/code.tar.gz";
|
||||
|
||||
Console::execute("cd $folderPath && tar --exclude code.tar.gz --exclude node_modules -czf code.tar.gz .", '', $stdout, $stderr);
|
||||
|
||||
if (filesize($tarPath) > 1024 * 1024 * 5) {
|
||||
throw new \Exception('Code package is too large. Use the chunked upload method instead.');
|
||||
}
|
||||
|
||||
return new CURLFile($tarPath, 'application/x-gzip', \basename($tarPath));
|
||||
}
|
||||
|
||||
private function packageFunction(string $function): CURLFile
|
||||
{
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
|
||||
$folderPath = realpath(__DIR__ . '/../../../resources/functions') . "/$function";
|
||||
$tarPath = "$folderPath/code.tar.gz";
|
||||
|
||||
Console::execute("cd $folderPath && tar --exclude code.tar.gz --exclude node_modules -czf code.tar.gz .", '', $stdout, $stderr);
|
||||
|
||||
if (filesize($tarPath) > 1024 * 1024 * 5) {
|
||||
throw new \Exception('Code package is too large. Use the chunked upload method instead.');
|
||||
}
|
||||
|
||||
return new CURLFile($tarPath, 'application/x-gzip', \basename($tarPath));
|
||||
}
|
||||
}
|
||||
@@ -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',
|
||||
]);
|
||||
|
||||
@@ -0,0 +1,482 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\TablesDB;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ApiTablesDB;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\SchemaPolling;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideServer;
|
||||
use Tests\E2E\Traits\DatabasesUrlHelpers;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
|
||||
class DatabasesNumericTypesTest extends Scope
|
||||
{
|
||||
use ProjectCustom;
|
||||
use SideServer;
|
||||
use ApiTablesDB;
|
||||
use DatabasesUrlHelpers;
|
||||
use SchemaPolling;
|
||||
|
||||
private static array $setupCache = [];
|
||||
|
||||
/**
|
||||
* Setup database, table, and numeric columns for parallel-safe tests.
|
||||
*/
|
||||
protected function setupDatabaseAndTable(): array
|
||||
{
|
||||
$cacheKey = $this->getProject()['$id'] ?? 'default';
|
||||
if (!empty(self::$setupCache[$cacheKey])) {
|
||||
return self::$setupCache[$cacheKey];
|
||||
}
|
||||
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$apiKey = $this->getProject()['apiKey'];
|
||||
$headers = [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-key' => $apiKey,
|
||||
];
|
||||
|
||||
$database = $this->client->call(Client::METHOD_POST, '/tablesdb', $headers, [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Numeric Types Test Database',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
$table = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables', $headers, [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'Numeric Types Table',
|
||||
'rowSecurity' => true,
|
||||
'permissions' => [
|
||||
Permission::create(Role::any()),
|
||||
Permission::read(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $table['headers']['status-code']);
|
||||
$tableId = $table['body']['$id'];
|
||||
|
||||
// Create integer column
|
||||
$this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/integer', $headers, [
|
||||
'key' => 'integer_field',
|
||||
'required' => false,
|
||||
'min' => -10,
|
||||
'max' => 10,
|
||||
'default' => 0,
|
||||
]);
|
||||
|
||||
// Create bigint column
|
||||
$this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/bigint', $headers, [
|
||||
'key' => 'bigint_field',
|
||||
'required' => false,
|
||||
'min' => -9007199254740991,
|
||||
'max' => 9007199254740991,
|
||||
'default' => 9007199254740000,
|
||||
]);
|
||||
|
||||
// Create unsigned integer column
|
||||
$this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/integer', $headers, [
|
||||
'key' => 'unsigned_int_field',
|
||||
'required' => false,
|
||||
'min' => 0,
|
||||
'max' => 100,
|
||||
'default' => 0,
|
||||
'signed' => false,
|
||||
]);
|
||||
|
||||
// Create unsigned bigint column
|
||||
$this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/bigint', $headers, [
|
||||
'key' => 'unsigned_bigint_field',
|
||||
'required' => false,
|
||||
'min' => 0,
|
||||
'max' => 9223372036854775807,
|
||||
'default' => 0,
|
||||
'signed' => false,
|
||||
]);
|
||||
|
||||
// Cache before waiting so that if waitForAllAttributes times out,
|
||||
// subsequent calls don't try to re-create the same columns (causing 409)
|
||||
self::$setupCache[$cacheKey] = [
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => $tableId,
|
||||
];
|
||||
|
||||
// Wait for all columns to be available
|
||||
$this->waitForAllAttributes($databaseId, $tableId);
|
||||
|
||||
return self::$setupCache[$cacheKey];
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup database/table without caching so mutations (update/delete) don't
|
||||
* affect other tests that might be executed in a different order.
|
||||
*/
|
||||
protected function setupFreshDatabaseAndTable(): array
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$apiKey = $this->getProject()['apiKey'];
|
||||
$headers = [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-key' => $apiKey,
|
||||
];
|
||||
|
||||
$database = $this->client->call(Client::METHOD_POST, '/tablesdb', $headers, [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Numeric Types Test Database',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
$table = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables', $headers, [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'Numeric Types Table',
|
||||
'rowSecurity' => true,
|
||||
'permissions' => [
|
||||
Permission::create(Role::any()),
|
||||
Permission::read(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $table['headers']['status-code']);
|
||||
$tableId = $table['body']['$id'];
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/integer', $headers, [
|
||||
'key' => 'integer_field',
|
||||
'required' => false,
|
||||
'min' => -10,
|
||||
'max' => 10,
|
||||
'default' => 0,
|
||||
]);
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/bigint', $headers, [
|
||||
'key' => 'bigint_field',
|
||||
'required' => false,
|
||||
'min' => -9007199254740991,
|
||||
'max' => 9007199254740991,
|
||||
'default' => 9007199254740000,
|
||||
]);
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/integer', $headers, [
|
||||
'key' => 'unsigned_int_field',
|
||||
'required' => false,
|
||||
'max' => 100,
|
||||
'default' => 0,
|
||||
'signed' => false,
|
||||
]);
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/bigint', $headers, [
|
||||
'key' => 'unsigned_bigint_field',
|
||||
'required' => false,
|
||||
'max' => 9223372036854775807,
|
||||
'default' => 0,
|
||||
'signed' => false,
|
||||
]);
|
||||
|
||||
$this->waitForAllAttributes($databaseId, $tableId);
|
||||
|
||||
return [
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => $tableId,
|
||||
];
|
||||
}
|
||||
|
||||
public function testCreateDatabase(): void
|
||||
{
|
||||
$database = $this->client->call(Client::METHOD_POST, '/tablesdb', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Numeric Types Test Database',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
}
|
||||
|
||||
public function testCreateTable(): void
|
||||
{
|
||||
$data = $this->setupDatabaseAndTable();
|
||||
|
||||
$table = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $data['databaseId'] . '/tables/' . $data['tableId'], [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $table['headers']['status-code']);
|
||||
$this->assertEquals($data['tableId'], $table['body']['$id']);
|
||||
}
|
||||
|
||||
public function testGetIntegerAndBigIntColumns(): void
|
||||
{
|
||||
$data = $this->setupDatabaseAndTable();
|
||||
$databaseId = $data['databaseId'];
|
||||
$tableId = $data['tableId'];
|
||||
|
||||
$integerColumn = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/integer_field', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $integerColumn['headers']['status-code']);
|
||||
$this->assertEquals('integer_field', $integerColumn['body']['key']);
|
||||
$this->assertEquals('integer', $integerColumn['body']['type']);
|
||||
$this->assertEquals(false, $integerColumn['body']['required']);
|
||||
$this->assertEquals(false, $integerColumn['body']['array']);
|
||||
$this->assertEquals(-10, $integerColumn['body']['min']);
|
||||
$this->assertEquals(10, $integerColumn['body']['max']);
|
||||
$this->assertEquals(0, $integerColumn['body']['default']);
|
||||
|
||||
$bigintColumn = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/bigint_field', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $bigintColumn['headers']['status-code']);
|
||||
$this->assertEquals('bigint_field', $bigintColumn['body']['key']);
|
||||
|
||||
$this->assertEquals('bigint', $bigintColumn['body']['type']);
|
||||
$this->assertEquals(false, $bigintColumn['body']['required']);
|
||||
$this->assertEquals(false, $bigintColumn['body']['array']);
|
||||
$this->assertEquals(-9007199254740991, $bigintColumn['body']['min']);
|
||||
$this->assertEquals(9007199254740991, $bigintColumn['body']['max']);
|
||||
$this->assertEquals(9007199254740000, $bigintColumn['body']['default']);
|
||||
}
|
||||
|
||||
public function testGetUnsignedIntegerAndBigIntColumns(): void
|
||||
{
|
||||
$data = $this->setupDatabaseAndTable();
|
||||
$databaseId = $data['databaseId'];
|
||||
$tableId = $data['tableId'];
|
||||
|
||||
$unsignedIntColumn = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/unsigned_int_field', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $unsignedIntColumn['headers']['status-code']);
|
||||
$this->assertEquals('unsigned_int_field', $unsignedIntColumn['body']['key']);
|
||||
$this->assertEquals('integer', $unsignedIntColumn['body']['type']);
|
||||
$this->assertEquals(false, $unsignedIntColumn['body']['required']);
|
||||
$this->assertEquals(false, $unsignedIntColumn['body']['array']);
|
||||
$this->assertEquals(false, $unsignedIntColumn['body']['signed']);
|
||||
$this->assertEquals(0, $unsignedIntColumn['body']['min']);
|
||||
$this->assertEquals(100, $unsignedIntColumn['body']['max']);
|
||||
$this->assertEquals(0, $unsignedIntColumn['body']['default']);
|
||||
|
||||
$unsignedBigintColumn = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/unsigned_bigint_field', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $unsignedBigintColumn['headers']['status-code']);
|
||||
$this->assertEquals('unsigned_bigint_field', $unsignedBigintColumn['body']['key']);
|
||||
$this->assertEquals('bigint', $unsignedBigintColumn['body']['type']);
|
||||
$this->assertEquals(false, $unsignedBigintColumn['body']['required']);
|
||||
$this->assertEquals(false, $unsignedBigintColumn['body']['array']);
|
||||
$this->assertEquals(false, $unsignedBigintColumn['body']['signed']);
|
||||
$this->assertEquals(0, $unsignedBigintColumn['body']['min']);
|
||||
$this->assertEquals(9223372036854775807, $unsignedBigintColumn['body']['max']);
|
||||
$this->assertEquals(0, $unsignedBigintColumn['body']['default']);
|
||||
}
|
||||
|
||||
public function testListColumnsWithNumericTypes(): void
|
||||
{
|
||||
$data = $this->setupDatabaseAndTable();
|
||||
$databaseId = $data['databaseId'];
|
||||
$tableId = $data['tableId'];
|
||||
|
||||
$columns = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $columns['headers']['status-code']);
|
||||
$this->assertIsArray($columns['body']['columns']);
|
||||
$this->assertGreaterThan(0, $columns['body']['total']);
|
||||
|
||||
$columnKeys = array_map(fn ($col) => $col['key'], $columns['body']['columns']);
|
||||
$this->assertContains('integer_field', $columnKeys);
|
||||
$this->assertContains('bigint_field', $columnKeys);
|
||||
$this->assertContains('unsigned_int_field', $columnKeys);
|
||||
$this->assertContains('unsigned_bigint_field', $columnKeys);
|
||||
|
||||
$columnTypeByKey = [];
|
||||
foreach ($columns['body']['columns'] as $col) {
|
||||
$columnTypeByKey[$col['key']] = $col['type'];
|
||||
}
|
||||
|
||||
$this->assertEquals('integer', $columnTypeByKey['integer_field']);
|
||||
$this->assertEquals('bigint', $columnTypeByKey['bigint_field']);
|
||||
$this->assertEquals('integer', $columnTypeByKey['unsigned_int_field']);
|
||||
$this->assertEquals('bigint', $columnTypeByKey['unsigned_bigint_field']);
|
||||
}
|
||||
|
||||
public function testCreateRowWithIntegerAndBigIntTypes(): void
|
||||
{
|
||||
$data = $this->setupDatabaseAndTable();
|
||||
$databaseId = $data['databaseId'];
|
||||
$tableId = $data['tableId'];
|
||||
|
||||
$row = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'integer_field' => 5,
|
||||
'bigint_field' => 456,
|
||||
'unsigned_int_field' => 50,
|
||||
'unsigned_bigint_field' => 9007199254740000,
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $row['headers']['status-code']);
|
||||
$this->assertEquals(5, $row['body']['integer_field']);
|
||||
$this->assertEquals(456, $row['body']['bigint_field']);
|
||||
$this->assertEquals(50, $row['body']['unsigned_int_field']);
|
||||
$this->assertEquals(9007199254740000, $row['body']['unsigned_bigint_field']);
|
||||
}
|
||||
|
||||
public function testUpdateIntegerAndBigIntColumns(): void
|
||||
{
|
||||
$data = $this->setupFreshDatabaseAndTable();
|
||||
$databaseId = $data['databaseId'];
|
||||
$tableId = $data['tableId'];
|
||||
|
||||
// Update integer column
|
||||
$updateInteger = $this->client->call(
|
||||
Client::METHOD_PATCH,
|
||||
'/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/integer/integer_field',
|
||||
[
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
],
|
||||
[
|
||||
'required' => false,
|
||||
'min' => -20,
|
||||
'max' => 20,
|
||||
'default' => 3,
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $updateInteger['headers']['status-code']);
|
||||
|
||||
$this->assertEventually(function () use ($databaseId, $tableId) {
|
||||
$column = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/integer_field', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $column['headers']['status-code']);
|
||||
$this->assertEquals(-20, $column['body']['min']);
|
||||
$this->assertEquals(20, $column['body']['max']);
|
||||
$this->assertEquals(3, $column['body']['default']);
|
||||
}, 30000, 250);
|
||||
|
||||
// Update bigint column
|
||||
$updateBigint = $this->client->call(
|
||||
Client::METHOD_PATCH,
|
||||
'/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/bigint/bigint_field',
|
||||
[
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
],
|
||||
[
|
||||
'required' => false,
|
||||
'min' => -999,
|
||||
'max' => 999,
|
||||
'default' => 10,
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $updateBigint['headers']['status-code']);
|
||||
|
||||
$this->assertEventually(function () use ($databaseId, $tableId) {
|
||||
$column = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/bigint_field', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $column['headers']['status-code']);
|
||||
$this->assertEquals(-999, $column['body']['min']);
|
||||
$this->assertEquals(999, $column['body']['max']);
|
||||
$this->assertEquals(10, $column['body']['default']);
|
||||
}, 30000, 250);
|
||||
}
|
||||
|
||||
public function testDeleteIntegerAndBigIntColumns(): void
|
||||
{
|
||||
$data = $this->setupFreshDatabaseAndTable();
|
||||
$databaseId = $data['databaseId'];
|
||||
$tableId = $data['tableId'];
|
||||
|
||||
// Delete integer column
|
||||
$deleteInteger = $this->client->call(
|
||||
Client::METHOD_DELETE,
|
||||
'/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/integer_field',
|
||||
[
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(204, $deleteInteger['headers']['status-code']);
|
||||
|
||||
$this->assertEventually(function () use ($databaseId, $tableId) {
|
||||
$column = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/integer_field', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(404, $column['headers']['status-code']);
|
||||
}, 30000, 250);
|
||||
|
||||
// Delete bigint column
|
||||
$deleteBigint = $this->client->call(
|
||||
Client::METHOD_DELETE,
|
||||
'/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/bigint_field',
|
||||
[
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(204, $deleteBigint['headers']['status-code']);
|
||||
|
||||
$this->assertEventually(function () use ($databaseId, $tableId) {
|
||||
$column = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/bigint_field', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(404, $column['headers']['status-code']);
|
||||
}, 30000, 250);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user