Files
appwrite/tests/unit/Network/Validators/AppwriteDomainTest.php
T

189 lines
11 KiB
PHP

<?php
namespace Tests\Unit\Network\Validators;
use Appwrite\Network\Validator\AppwriteDomain;
use PHPUnit\Framework\TestCase;
class AppwriteDomainTest extends TestCase
{
protected ?AppwriteDomain $validator = null;
public function setUp(): void
{
$this->validator = new AppwriteDomain();
}
public function tearDown(): void
{
$this->validator = null;
}
public function testIsValid(): void
{
// Get the actual configured suffix from environment (in Docker it's sites.localhost)
// But test both the environment value and the default value
$envSuffix = \Utopia\System\System::getEnv('_APP_DOMAIN_SITES', defined('APP_DOMAIN_SITES_SUFFIX') ? APP_DOMAIN_SITES_SUFFIX : 'appwrite.network');
$functionsDomain = \Utopia\System\System::getEnv('_APP_DOMAIN_FUNCTIONS', 'functions.localhost');
// Valid domains for sites.localhost and functions.localhost (single-level subdomains only)
$this->assertEquals(true, $this->validator->isValid('api.' . $envSuffix));
$this->assertEquals(true, $this->validator->isValid('test.' . $envSuffix));
$this->assertEquals(true, $this->validator->isValid('myapp.' . $envSuffix));
$this->assertEquals(true, $this->validator->isValid('staging.' . $envSuffix));
$this->assertEquals(true, $this->validator->isValid('prod.' . $envSuffix));
$this->assertEquals(true, $this->validator->isValid('app123.' . $envSuffix));
$this->assertEquals(true, $this->validator->isValid('test-app.' . $envSuffix));
$this->assertEquals(true, $this->validator->isValid('my-awesome-app.' . $envSuffix));
$this->assertEquals(true, $this->validator->isValid('a.' . $envSuffix));
$this->assertEquals(true, $this->validator->isValid('x1.' . $envSuffix));
// Valid domains for functions domain (single-level subdomains only)
$this->assertEquals(true, $this->validator->isValid('api.' . $functionsDomain));
$this->assertEquals(true, $this->validator->isValid('test.' . $functionsDomain));
$this->assertEquals(true, $this->validator->isValid('myapp.' . $functionsDomain));
// Case insensitive validation
$this->assertEquals(true, $this->validator->isValid('API.' . strtoupper($envSuffix)));
$this->assertEquals(true, $this->validator->isValid('Test.' . ucfirst($envSuffix)));
$this->assertEquals(true, $this->validator->isValid('MyApp.' . $envSuffix));
// Invalid sub-subdomains for sites.localhost and functions.localhost (multiple levels not allowed)
$this->assertEquals(false, $this->validator->isValid('api.dev.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('foo.bar.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('app.staging.test.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('sub.domain.example.' . $envSuffix));
// Invalid sub-subdomains for functions domain (multiple levels not allowed)
$this->assertEquals(false, $this->validator->isValid('api.dev.' . $functionsDomain));
$this->assertEquals(false, $this->validator->isValid('foo.bar.' . $functionsDomain));
// Valid appwrite.network domains (one-level subdomains) - using environment variable
$appwriteDomain = \Utopia\System\System::getEnv('_APP_DOMAIN_SITES', defined('APP_DOMAIN_SITES_SUFFIX') ? APP_DOMAIN_SITES_SUFFIX : 'appwrite.network');
$this->assertEquals(true, $this->validator->isValid('api.' . $appwriteDomain));
$this->assertEquals(true, $this->validator->isValid('test.' . $appwriteDomain));
$this->assertEquals(true, $this->validator->isValid('myapp.' . $appwriteDomain));
// Invalid sub-subdomains for appwrite.network
$this->assertEquals(false, $this->validator->isValid('api.dev.' . $appwriteDomain));
$this->assertEquals(false, $this->validator->isValid('foo.bar.' . $appwriteDomain));
// Other domains should be valid (no multilevel restrictions)
$this->assertEquals(true, $this->validator->isValid('example.com'));
$this->assertEquals(true, $this->validator->isValid('api.example.com'));
$this->assertEquals(true, $this->validator->isValid('test.google.com'));
$this->assertEquals(true, $this->validator->isValid('app.github.io'));
$this->assertEquals(true, $this->validator->isValid('myapp.herokuapp.com'));
$this->assertEquals(true, $this->validator->isValid('sub.domain.example.com'));
// Domains with spaces and invalid characters
$this->assertEquals(false, $this->validator->isValid('my app.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('test .' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid(' api.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('api.' . $envSuffix . ' '));
$this->assertEquals(false, $this->validator->isValid('app@test.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('app#test.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('app$test.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('app%test.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('app_test.' . $envSuffix));
// Invalid formatting
$this->assertEquals(false, $this->validator->isValid('.api.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('api.' . $envSuffix . '.'));
$this->assertEquals(false, $this->validator->isValid('api..' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid($envSuffix));
$this->assertEquals(false, $this->validator->isValid('.' . $envSuffix . '.'));
$this->assertEquals(false, $this->validator->isValid('..' . $envSuffix));
// Forbidden prefixes
$this->assertEquals(false, $this->validator->isValid('commit-api.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('commit-test.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('commit-123.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('branch-api.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('branch-test.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('branch-123.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('COMMIT-api.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('BRANCH-test.' . $envSuffix));
// Valid domains that should not be confused with forbidden prefixes
$this->assertEquals(true, $this->validator->isValid('commitment.' . $envSuffix));
$this->assertEquals(true, $this->validator->isValid('branching.' . $envSuffix));
$this->assertEquals(true, $this->validator->isValid('my-commit.' . $envSuffix));
$this->assertEquals(true, $this->validator->isValid('my-branch.' . $envSuffix));
$this->assertEquals(true, $this->validator->isValid('pre-commit.' . $envSuffix));
$this->assertEquals(true, $this->validator->isValid('post-branch.' . $envSuffix));
// Edge cases with dots
$this->assertEquals(false, $this->validator->isValid('.api.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('api..' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('api.' . $envSuffix . '.'));
$this->assertEquals(false, $this->validator->isValid('.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('..' . $envSuffix));
// Just the suffix without subdomain
$this->assertEquals(false, $this->validator->isValid($envSuffix));
$this->assertEquals(false, $this->validator->isValid('.' . $envSuffix));
// Empty and null values
$this->assertEquals(false, $this->validator->isValid(''));
$this->assertEquals(false, $this->validator->isValid(' '));
$this->assertEquals(false, $this->validator->isValid(null));
$this->assertEquals(false, $this->validator->isValid(false));
// Non-string types
$this->assertEquals(false, $this->validator->isValid(123));
$this->assertEquals(false, $this->validator->isValid(12.34));
$this->assertEquals(false, $this->validator->isValid(['api.appwrite.network']));
$this->assertEquals(false, $this->validator->isValid((object)['domain' => 'api.appwrite.network']));
$this->assertEquals(false, $this->validator->isValid(true));
// Invalid subdomain formats
$this->assertEquals(false, $this->validator->isValid('-api.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('api-.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('-test-.' . $envSuffix));
$this->assertEquals(false, $this->validator->isValid('-.' . $envSuffix));
// Too long subdomain (over 63 characters)
$longSubdomain = str_repeat('a', 64) . '.' . $envSuffix;
$this->assertEquals(false, $this->validator->isValid($longSubdomain));
// Exactly 63 characters should be valid
$maxLengthSubdomain = str_repeat('a', 63) . '.' . $envSuffix;
$this->assertEquals(true, $this->validator->isValid($maxLengthSubdomain));
// Single character subdomain should be valid
$this->assertEquals(true, $this->validator->isValid('a.' . $envSuffix));
// Numbers in subdomain
$this->assertEquals(true, $this->validator->isValid('123.' . $envSuffix));
$this->assertEquals(true, $this->validator->isValid('api123.' . $envSuffix));
$this->assertEquals(true, $this->validator->isValid('123api.' . $envSuffix));
// Mixed case with hyphens
$this->assertEquals(true, $this->validator->isValid('My-Test-App.' . $envSuffix));
$this->assertEquals(true, $this->validator->isValid('app-v2.' . $envSuffix));
}
public function testGetType(): void
{
$this->assertEquals('string', $this->validator->getType());
}
public function testIsArray(): void
{
$this->assertEquals(false, $this->validator->isArray());
}
public function testGetDescription(): void
{
$description = $this->validator->getDescription();
$this->assertIsString($description);
// Get the environment suffix to check it's in the description
$envSuffix = \Utopia\System\System::getEnv('_APP_DOMAIN_SITES', defined('APP_DOMAIN_SITES_SUFFIX') ? APP_DOMAIN_SITES_SUFFIX : 'appwrite.network');
$this->assertStringContainsString($envSuffix, $description);
$this->assertStringContainsString('one-level subdomain', $description);
}
}