From f6674f07e4338f253bb371fbf90cf2de2138a909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 5 Mar 2025 12:29:27 +0100 Subject: [PATCH] Add redeploy tests --- .../Http/Deployments/Duplicate/Create.php | 8 ++-- .../Http/Deployments/Duplicate/Create.php | 8 ++-- .../e2e/Services/Functions/FunctionsBase.php | 43 +++++++++++++++++ .../Functions/FunctionsCustomServerTest.php | 40 ++++++++++++++++ tests/e2e/Services/Sites/SitesBase.php | 33 +++++++++++++ .../Services/Sites/SitesCustomServerTest.php | 46 +++++++++++++++++++ tests/resources/functions/node/maintenance.js | 3 ++ 7 files changed, 175 insertions(+), 6 deletions(-) create mode 100644 tests/resources/functions/node/maintenance.js diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Duplicate/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Duplicate/Create.php index 970f79c9fd..624a410dcd 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Duplicate/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Duplicate/Create.php @@ -48,8 +48,8 @@ class Create extends Action auth: [AuthType::KEY], responses: [ new SDKResponse( - code: Response::STATUS_CODE_NOCONTENT, - model: Response::MODEL_NONE, + code: Response::STATUS_CODE_ACCEPTED, + model: Response::MODEL_DEPLOYMENT, ) ] )) @@ -108,6 +108,8 @@ class Create extends Action ->setParam('functionId', $function->getId()) ->setParam('deploymentId', $deployment->getId()); - $response->noContent(); + $response + ->setStatusCode(Response::STATUS_CODE_ACCEPTED) + ->dynamic($deployment, Response::MODEL_DEPLOYMENT); } } diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php index 7c06c5f175..b30c07838f 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Duplicate/Create.php @@ -48,8 +48,8 @@ class Create extends Action auth: [AuthType::KEY], responses: [ new SDKResponse( - code: Response::STATUS_CODE_NOCONTENT, - model: Response::MODEL_NONE, + code: Response::STATUS_CODE_ACCEPTED, + model: Response::MODEL_DEPLOYMENT, ) ] )) @@ -130,6 +130,8 @@ class Create extends Action ->setParam('siteId', $site->getId()) ->setParam('deploymentId', $deployment->getId()); - $response->noContent(); + $response + ->setStatusCode(Response::STATUS_CODE_ACCEPTED) + ->dynamic($deployment, Response::MODEL_DEPLOYMENT); } } diff --git a/tests/e2e/Services/Functions/FunctionsBase.php b/tests/e2e/Services/Functions/FunctionsBase.php index f97245b0af..25dfc0bcb6 100644 --- a/tests/e2e/Services/Functions/FunctionsBase.php +++ b/tests/e2e/Services/Functions/FunctionsBase.php @@ -87,6 +87,16 @@ trait FunctionsBase return $function; } + protected function updateFunction(string $functionId, mixed $params): mixed + { + $function = $this->client->call(Client::METHOD_PUT, '/functions/' . $functionId, array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), $params); + + return $function; + } + protected function createVariable(string $functionId, mixed $params): mixed { $variable = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([ @@ -324,4 +334,37 @@ trait FunctionsBase return $response; } + + protected function setupDuplicateDeployment(string $functionId, string $deploymentId): string + { + $deployment = $this->createDuplicateDeployment($functionId, $deploymentId); + $this->assertEquals(202, $deployment['headers']['status-code']); + + $deploymentId = $deployment['body']['$id']; + $this->assertNotEmpty($deploymentId); + + $this->assertEventually(function () use ($functionId, $deploymentId) { + $deployment = $this->getDeployment($functionId, $deploymentId); + $this->assertEquals('ready', $deployment['body']['status'], 'Deployment status is not ready, deployment: ' . json_encode($deployment['body'], JSON_PRETTY_PRINT)); + }, 100000, 500); + + $this->assertEventually(function () use ($functionId, $deploymentId) { + $function = $this->getFunction($functionId); + $this->assertEquals($deploymentId, $function['body']['deployment'], 'Deployment is not activated, deployment: ' . json_encode($function['body'], JSON_PRETTY_PRINT)); + }, 100000, 500); + + return $deploymentId; + } + + protected function createDuplicateDeployment(string $functionId, string $deploymentId): mixed + { + $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments/duplicate', array_merge([ + 'content-type' => 'multipart/form-data', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'deploymentId' => $deploymentId, + ]); + + return $deployment; + } } diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index f4cd9ca493..ad033a5124 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -1989,4 +1989,44 @@ class FunctionsCustomServerTest extends Scope $this->cleanupFunction($functionId); } + + public function testDuplicateDeployment(): void + { + $functionId = $this->setupFunction([ + 'functionId' => ID::unique(), + 'runtime' => 'node-18.0', + 'name' => 'Duplicate Deployment Test', + 'entrypoint' => 'index.js', + 'commands' => '' + ]); + $this->assertNotEmpty($functionId); + + $deploymentId1 = $this->setupDeployment($functionId, [ + 'code' => $this->packageFunction('node'), + 'activate' => true + ]); + $this->assertNotEmpty($deploymentId1); + + $execution = $this->createExecution($functionId); + $this->assertEquals(201, $execution['headers']['status-code']); + $this->assertStringContainsString('APPWRITE_FUNCTION_ID', $execution['body']['responseBody']); + + $site = $this->updateFunction($functionId, [ + 'runtime' => 'node-18.0', + 'name' => 'Duplicate Deployment Test', + 'entrypoint' => 'index.js', + 'commands' => 'rm index.js && mv maintenance.js index.js' + ]); + $this->assertEquals(200, $site['headers']['status-code']); + $this->assertStringContainsString('maintenance.js', $site['body']['commands']); + + $deploymentId2 = $this->setupDuplicateDeployment($functionId, $deploymentId1); + $this->assertNotEmpty($deploymentId2); + + $execution = $this->createExecution($functionId); + $this->assertEquals(201, $execution['headers']['status-code']); + $this->assertStringContainsString('Maintenance', $execution['body']['responseBody']); + + $this->cleanupFunction($functionId); + } } diff --git a/tests/e2e/Services/Sites/SitesBase.php b/tests/e2e/Services/Sites/SitesBase.php index 6e597b31ec..fe271e18e2 100644 --- a/tests/e2e/Services/Sites/SitesBase.php +++ b/tests/e2e/Services/Sites/SitesBase.php @@ -244,6 +244,39 @@ trait SitesBase return $deployment; } + protected function setupDuplicateDeployment(string $siteId, string $deploymentId): string + { + $deployment = $this->createDuplicateDeployment($siteId, $deploymentId); + $this->assertEquals(202, $deployment['headers']['status-code']); + + $deploymentId = $deployment['body']['$id']; + $this->assertNotEmpty($deploymentId); + + $this->assertEventually(function () use ($siteId, $deploymentId) { + $deployment = $this->getDeployment($siteId, $deploymentId); + $this->assertEquals('ready', $deployment['body']['status'], 'Deployment status is not ready, deployment: ' . json_encode($deployment['body'], JSON_PRETTY_PRINT)); + }, 100000, 500); + + $this->assertEventually(function () use ($siteId, $deploymentId) { + $site = $this->getSite($siteId); + $this->assertEquals($deploymentId, $site['body']['deploymentId'], 'Deployment is not activated, deployment: ' . json_encode($site['body'], JSON_PRETTY_PRINT)); + }, 100000, 500); + + return $deploymentId; + } + + protected function createDuplicateDeployment(string $siteId, string $deploymentId): mixed + { + $deployment = $this->client->call(Client::METHOD_POST, '/sites/' . $siteId . '/deployments/duplicate', array_merge([ + 'content-type' => 'multipart/form-data', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'deploymentId' => $deploymentId, + ]); + + return $deployment; + } + protected function createTemplateDeployment(string $siteId, mixed $params = []): mixed { $deployment = $this->client->call(Client::METHOD_POST, '/sites/' . $siteId . '/deployments/template', array_merge([ diff --git a/tests/e2e/Services/Sites/SitesCustomServerTest.php b/tests/e2e/Services/Sites/SitesCustomServerTest.php index 3e6132c845..e2c8e6a6a3 100644 --- a/tests/e2e/Services/Sites/SitesCustomServerTest.php +++ b/tests/e2e/Services/Sites/SitesCustomServerTest.php @@ -1747,4 +1747,50 @@ class SitesCustomServerTest extends Scope $this->cleanupSite($siteId); } + + public function testDuplicateDeployment(): void + { + $siteId = $this->setupSite([ + 'buildRuntime' => 'ssr-22', + 'framework' => 'other', + 'name' => 'Duplicate deployment Site', + 'adapter' => 'static', + 'fallbackFile' => '404.html', + 'siteId' => ID::unique() + ]); + $this->assertNotEmpty($siteId); + + $domain = $this->setupSiteDomain($siteId); + $this->assertNotEmpty($domain); + $proxyClient = new Client(); + $proxyClient->setEndpoint('http://' . $domain); + + $deploymentId1 = $this->setupDeployment($siteId, [ + 'code' => $this->packageSite('static-spa'), + 'activate' => true + ]); + $this->assertNotEmpty($deploymentId1); + + $response = $proxyClient->call(Client::METHOD_GET, '/not-found'); + $this->assertStringContainsString("Customized 404 page", $response['body']); + + $site = $this->updateSite([ + '$id' => $siteId, + 'buildRuntime' => 'ssr-22', + 'framework' => 'other', + 'name' => 'Duplicate deployment Site', + 'adapter' => 'static', + 'fallbackFile' => 'index.html', + ]); + $this->assertEquals(200, $site['headers']['status-code']); + $this->assertEquals('index.html', $site['body']['fallbackFile']); + + $deploymentId2 = $this->setupDuplicateDeployment($siteId, $deploymentId1); + $this->assertNotEmpty($deploymentId2); + + $response = $proxyClient->call(Client::METHOD_GET, '/not-found'); + $this->assertStringContainsString("Index page", $response['body']); + + $this->cleanupSite($siteId); + } } diff --git a/tests/resources/functions/node/maintenance.js b/tests/resources/functions/node/maintenance.js new file mode 100644 index 0000000000..0885f11041 --- /dev/null +++ b/tests/resources/functions/node/maintenance.js @@ -0,0 +1,3 @@ +module.exports = async(context) => { + return context.res.send('Maintenance'); +} \ No newline at end of file