functions and more tests

This commit is contained in:
Hemachandar 2025-11-17 14:53:26 +05:30
parent d36e42377b
commit ba542554ce
13 changed files with 107 additions and 30 deletions

View file

@ -13,8 +13,8 @@ use Utopia\Database\Exception\Duplicate;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Swoole\Request;
use Utopia\System\System;
use Utopia\VCS\Adapter\Git\GitHub;
@ -53,7 +53,7 @@ class Base extends Action
return $allowedSpecifications[0] ?? APP_COMPUTE_SPECIFICATION_DEFAULT;
}
public function redeployVcsFunction(Request $request, Document $function, Document $project, Document $installation, Database $dbForProject, Build $queueForBuilds, Document $template, GitHub $github, bool $activate, string $referenceType = 'branch', string $reference = ''): Document
public function redeployVcsFunction(Request $request, Document $function, Document $project, Document $installation, Database $dbForProject, Database $dbForPlatform, Build $queueForBuilds, Document $template, GitHub $github, bool $activate, string $referenceType = 'branch', string $reference = ''): Document
{
$deploymentId = ID::unique();
$entrypoint = $function->getAttribute('entrypoint', '');
@ -134,6 +134,8 @@ class Base extends Action
->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', ''));
$dbForProject->updateDocument('functions', $function->getId(), $function);
$this->updateEmptyManualRule($project, $function, $deployment, $dbForPlatform);
$queueForBuilds
->setType(BUILD_TYPE_DEPLOYMENT)
->setResource($function)
@ -328,7 +330,7 @@ class Base extends Action
}
}
$this->updateManualRuleForNewSiteDeployment($project, $site, $deployment, $dbForPlatform);
$this->updateEmptyManualRule($project, $site, $deployment, $dbForPlatform);
$queueForBuilds
->setType(BUILD_TYPE_DEPLOYMENT)
@ -340,8 +342,8 @@ class Base extends Action
}
/**
* Update manual rule for new site deployment.
* In case of fresh site, deployment ID will be empty in the rules, so we need to update it here.
* Update empty manual rule for deployment.
* In case of first deployment, deployment ID will be empty in the rules, so we need to update it here.
*
* @param \Utopia\Database\Document $project
* @param \Utopia\Database\Document $site
@ -349,22 +351,20 @@ class Base extends Action
* @param \Utopia\Database\Database $dbForPlatform
* @return void
*/
public function updateManualRuleForNewSiteDeployment(Document $project, Document $site, Document $deployment, Database $dbForPlatform)
public function updateEmptyManualRule(Document $project, Document $resource, Document $deployment, Database $dbForPlatform)
{
$queries = [
Query::equal('projectInternalId', [$project->getSequence()]),
Query::equal('deploymentResourceInternalId', [$resource->getSequence()]),
Query::equal('deploymentId', ['']),
Query::equal('type', ['deployment']),
Query::equal('deploymentResourceInternalId', [$site->getSequence()]),
Query::equal('deploymentResourceType', ['site']),
Query::equal('trigger', ['manual']),
];
$dbForPlatform->forEach('rules', function (Document $rule) use ($deployment, $dbForPlatform) {
if (empty($rule->getAttribute('deploymentId', ''))) {
Authorization::skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), new Document([
'deploymentId' => $deployment->getId(),
'deploymentInternalId' => $deployment->getSequence(),
])));
}
Authorization::skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), new Document([
'deploymentId' => $deployment->getId(),
'deploymentInternalId' => $deployment->getSequence(),
])));
}, $queries);
}
}

View file

@ -5,6 +5,7 @@ namespace Appwrite\Platform\Modules\Functions\Http\Deployments;
use Appwrite\Event\Build;
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Modules\Compute\Base;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
@ -30,7 +31,7 @@ use Utopia\System\System;
use Utopia\Validator\Boolean;
use Utopia\Validator\Text;
class Create extends Action
class Create extends Base
{
use HTTP;
@ -81,6 +82,7 @@ class Create extends Action
->inject('request')
->inject('response')
->inject('dbForProject')
->inject('dbForPlatform')
->inject('queueForEvents')
->inject('project')
->inject('deviceForFunctions')
@ -99,6 +101,7 @@ class Create extends Action
Request $request,
Response $response,
Database $dbForProject,
Database $dbForPlatform,
Event $queueForEvents,
Document $project,
Device $deviceForFunctions,
@ -300,6 +303,8 @@ class Create extends Action
}
}
$this->updateEmptyManualRule($project, $function, $deployment, $dbForPlatform);
$metadata = null;
$queueForEvents

View file

@ -116,6 +116,7 @@ class Create extends Base
project: $project,
installation: $installation,
dbForProject: $dbForProject,
dbForPlatform: $dbForPlatform,
queueForBuilds: $queueForBuilds,
template: $template,
github: $github,
@ -157,6 +158,9 @@ class Create extends Base
->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', ''));
$dbForProject->updateDocument('functions', $function->getId(), $function);
$this->updateEmptyManualRule($project, $function, $deployment, $dbForPlatform);
$queueForBuilds
->setType(BUILD_TYPE_DEPLOYMENT)
->setResource($function)

View file

@ -105,6 +105,7 @@ class Create extends Base
project: $project,
installation: $installation,
dbForProject: $dbForProject,
dbForPlatform: $dbForPlatform,
queueForBuilds: $queueForBuilds,
template: $template,
github: $github,

View file

@ -311,6 +311,7 @@ class Create extends Base
project: $project,
installation: $installation,
dbForProject: $dbForProject,
dbForPlatform: $dbForPlatform,
queueForBuilds: $queueForBuilds,
template: $template,
github: $github,

View file

@ -273,7 +273,7 @@ class Update extends Base
// Redeploy logic
if (!$isConnected && !empty($providerRepositoryId)) {
$this->redeployVcsFunction($request, $function, $project, $installation, $dbForProject, $queueForBuilds, new Document(), $github, true);
$this->redeployVcsFunction($request, $function, $project, $installation, $dbForProject, $dbForPlatform, $queueForBuilds, new Document(), $github, true);
}
// Inform scheduler if function is still active

View file

@ -365,7 +365,7 @@ class Create extends Base
}
}
$this->updateManualRuleForNewSiteDeployment($project, $site, $deployment, $dbForPlatform);
$this->updateEmptyManualRule($project, $site, $deployment, $dbForPlatform);
$metadata = null;

View file

@ -196,7 +196,7 @@ class Create extends Base
]))
);
$this->updateManualRuleForNewSiteDeployment($project, $site, $deployment, $dbForPlatform);
$this->updateEmptyManualRule($project, $site, $deployment, $dbForPlatform);
$queueForBuilds
->setType(BUILD_TYPE_DEPLOYMENT)

View file

@ -272,7 +272,7 @@ class Update extends Base
// Redeploy logic
if (!$isConnected && !empty($providerRepositoryId)) {
$this->redeployVcsFunction($request, $site, $project, $installation, $dbForProject, $queueForBuilds, new Document(), $github, true);
$this->redeployVcsFunction($request, $site, $project, $installation, $dbForProject, $dbForPlatform, $queueForBuilds, new Document(), $github, true);
}
$queueForEvents->setParam('siteId', $site->getId());

View file

@ -409,4 +409,27 @@ trait FunctionsBase
return $specifications;
}
protected function createFunctionRule(string $functionId, string $domain): 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()), [
'functionId' => $functionId,
'domain' => $domain,
]);
return $rule;
}
protected function getFunctionRule(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;
}
}

View file

@ -14,6 +14,7 @@ use Utopia\Database\Helpers\ID;
use Utopia\Database\Helpers\Role;
use Utopia\Database\Query;
use Utopia\Database\Validator\Datetime as DatetimeValidator;
use Utopia\System\System;
class FunctionsCustomServerTest extends Scope
{
@ -392,6 +393,10 @@ class FunctionsCustomServerTest extends Scope
$functionId = $function['body']['$id'] ?? '';
$domain = ID::unique() . '.' . System::getEnv('_APP_DOMAIN_FUNCTIONS', '');
$rule = $this->createFunctionRule($functionId, $domain);
$this->assertEquals(201, $rule['headers']['status-code']);
$deployment = $this->createTemplateDeployment(
$functionId,
[
@ -407,6 +412,17 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(202, $deployment['headers']['status-code']);
$this->assertNotEmpty($deployment['body']['$id']);
$rule = $this->getFunctionRule($rule['body']['$id']);
$this->assertEquals(200, $rule['headers']['status-code']);
$this->assertEquals($deployment['body']['$id'], $rule['body']['deploymentId']);
$proxyClient = new Client();
$proxyClient->setEndpoint('http://' . $domain);
$response = $proxyClient->call(Client::METHOD_GET, '/');
$this->assertEquals(400, $response['headers']['status-code']);
$this->assertStringContainsString("Deployment is still building", $response['body']);
$deployment = $this->getDeployment($functionId, $deployment['body']['$id']);
$this->assertEquals(200, $deployment['headers']['status-code']);
$this->assertEquals(0, $deployment['body']['sourceSize']);
@ -524,6 +540,10 @@ class FunctionsCustomServerTest extends Scope
*/
$functionId = $data['functionId'];
$domain = ID::unique() . '.' . System::getEnv('_APP_DOMAIN_FUNCTIONS', '');
$rule = $this->createFunctionRule($functionId, $domain);
$this->assertEquals(201, $rule['headers']['status-code']);
$deployment = $this->createDeployment($functionId, [
'code' => $this->packageFunction('basic'),
'activate' => true
@ -535,6 +555,17 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(true, (new DatetimeValidator())->isValid($deployment['body']['$createdAt']));
$this->assertEquals('index.js', $deployment['body']['entrypoint']);
$rule = $this->getFunctionRule($rule['body']['$id']);
$this->assertEquals(200, $rule['headers']['status-code']);
$this->assertEquals($deployment['body']['$id'], $rule['body']['deploymentId']);
$proxyClient = new Client();
$proxyClient->setEndpoint('http://' . $domain);
$response = $proxyClient->call(Client::METHOD_GET, '/');
$this->assertEquals(400, $response['headers']['status-code']);
$this->assertStringContainsString("Deployment is still building", $response['body']);
$deploymentIdActive = $deployment['body']['$id'] ?? '';
$this->assertEventually(function () use ($functionId, $deploymentIdActive) {

View file

@ -451,7 +451,7 @@ trait SitesBase
return $specifications;
}
protected function createRule(string $siteId, string $domain): mixed
protected function createSiteRule(string $siteId, string $domain): mixed
{
$rule = $this->client->call(Client::METHOD_POST, '/proxy/rules/site', array_merge([
'content-type' => 'application/json',
@ -464,7 +464,7 @@ trait SitesBase
return $rule;
}
protected function getRule(string $ruleId): mixed
protected function getSiteRule(string $ruleId): mixed
{
$rule = $this->client->call(Client::METHOD_GET, '/proxy/rules/' . $ruleId, array_merge([
'content-type' => 'application/json',

View file

@ -861,7 +861,8 @@ class SitesCustomServerTest extends Scope
$this->assertNotNull($siteId);
$rule = $this->createRule($siteId, \uniqid() . '.myapp.com');
$domain = ID::unique() . '.' . System::getEnv('_APP_DOMAIN_SITES', '');
$rule = $this->createSiteRule($siteId, $domain);
$this->assertEquals(201, $rule['headers']['status-code']);
$deployment = $this->createDeployment($siteId, [
@ -875,10 +876,17 @@ class SitesCustomServerTest extends Scope
$this->assertEquals('waiting', $deployment['body']['status']);
$this->assertEquals(true, (new DatetimeValidator())->isValid($deployment['body']['$createdAt']));
$rule = $this->getRule($rule['body']['$id']);
$rule = $this->getSiteRule($rule['body']['$id']);
$this->assertEquals(200, $rule['headers']['status-code']);
$this->assertEquals($deployment['body']['$id'], $rule['body']['deploymentId']);
$proxyClient = new Client();
$proxyClient->setEndpoint('http://' . $domain);
$response = $proxyClient->call(Client::METHOD_GET, '/');
$this->assertEquals(400, $response['headers']['status-code']);
$this->assertStringContainsString("Deployment is still building", $response['body']);
$deploymentIdActive = $deployment['body']['$id'] ?? '';
$this->assertEventually(function () use ($siteId, $deploymentIdActive) {
@ -1548,7 +1556,7 @@ class SitesCustomServerTest extends Scope
$this->cleanupSite($siteId);
}
#[Retry(count: 3)]
// #[Retry(count: 3)]
public function testSiteTemplate(): void
{
$template = $this->getTemplate('playground-for-astro');
@ -1570,7 +1578,8 @@ class SitesCustomServerTest extends Scope
$this->assertNotEmpty($siteId);
$rule = $this->createRule($siteId, \uniqid() . '.myapp.com');
$domain = ID::unique() . '.' . System::getEnv('_APP_DOMAIN_SITES', '');
$rule = $this->createSiteRule($siteId, $domain);
$this->assertEquals(201, $rule['headers']['status-code']);
$deployment = $this->createTemplateDeployment($siteId, [
@ -1584,10 +1593,17 @@ class SitesCustomServerTest extends Scope
$this->assertEquals(202, $deployment['headers']['status-code']);
$this->assertNotEmpty($deployment['body']['$id']);
$rule = $this->getRule($rule['body']['$id']);
$rule = $this->getSiteRule($rule['body']['$id']);
$this->assertEquals(200, $rule['headers']['status-code']);
$this->assertEquals($deployment['body']['$id'], $rule['body']['deploymentId']);
$proxyClient = new Client();
$proxyClient->setEndpoint('http://' . $domain);
$response = $proxyClient->call(Client::METHOD_GET, '/');
$this->assertEquals(400, $response['headers']['status-code']);
$this->assertStringContainsString("Deployment is still building", $response['body']);
$deployment = $this->getDeployment($siteId, $deployment['body']['$id']);
$this->assertEquals(200, $deployment['headers']['status-code']);
$this->assertEquals(0, $deployment['body']['sourceSize']);
@ -1599,10 +1615,6 @@ class SitesCustomServerTest extends Scope
$this->assertNotEmpty($site['body']['deploymentId']);
}, 50000, 500);
$domain = $this->setupSiteDomain($siteId);
$proxyClient = new Client();
$proxyClient->setEndpoint('http://' . $domain);
$response = $proxyClient->call(Client::METHOD_GET, '/');
$this->assertEquals(200, $response['headers']['status-code']);