mirror of
https://github.com/appwrite/appwrite
synced 2026-05-22 16:38:32 +00:00
Merge pull request #8682 from appwrite/fix-flaky-tests
fix: flaky functions tests
This commit is contained in:
commit
a6ceda3543
14 changed files with 1139 additions and 2469 deletions
35
.github/workflows/tests.yml
vendored
35
.github/workflows/tests.yml
vendored
|
|
@ -16,22 +16,22 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build Appwrite
|
||||
uses: docker/build-push-action@v3
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: false
|
||||
tags: ${{ env.IMAGE }}
|
||||
load: true
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
cache-from: type=gha,scope=appwrite
|
||||
cache-to: type=gha,mode=max,scope=appwrite
|
||||
outputs: type=docker,dest=/tmp/${{ env.IMAGE }}.tar
|
||||
build-args: |
|
||||
DEBUG=false
|
||||
|
|
@ -39,9 +39,11 @@ jobs:
|
|||
VERSION=dev
|
||||
|
||||
- name: Cache Docker Image
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
key: ${{ env.CACHE_KEY }}
|
||||
restore-keys: |
|
||||
appwrite-dev-
|
||||
path: /tmp/${{ env.IMAGE }}.tar
|
||||
|
||||
unit_test:
|
||||
|
|
@ -51,10 +53,10 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Load Cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
key: ${{ env.CACHE_KEY }}
|
||||
path: /tmp/${{ env.IMAGE }}.tar
|
||||
|
|
@ -81,10 +83,10 @@ jobs:
|
|||
needs: setup
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Load Cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
key: ${{ env.CACHE_KEY }}
|
||||
path: /tmp/${{ env.IMAGE }}.tar
|
||||
|
|
@ -113,6 +115,7 @@ jobs:
|
|||
Console,
|
||||
Databases,
|
||||
Functions,
|
||||
FunctionsSchedule,
|
||||
GraphQL,
|
||||
Health,
|
||||
Locale,
|
||||
|
|
@ -128,10 +131,10 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Load Cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
key: ${{ env.CACHE_KEY }}
|
||||
path: /tmp/${{ env.IMAGE }}.tar
|
||||
|
|
@ -141,7 +144,7 @@ jobs:
|
|||
run: |
|
||||
docker load --input /tmp/${{ env.IMAGE }}.tar
|
||||
docker compose up -d
|
||||
sleep 25
|
||||
sleep 30
|
||||
|
||||
- name: Run ${{matrix.service}} Tests
|
||||
run: docker compose exec -T appwrite test /usr/src/code/tests/e2e/Services/${{matrix.service}} --debug
|
||||
|
|
@ -149,15 +152,15 @@ jobs:
|
|||
- name: Run ${{matrix.service}} Shared Tables Tests
|
||||
run: _APP_DATABASE_SHARED_TABLES=database_db_main docker compose exec -T appwrite test /usr/src/code/tests/e2e/Services/${{matrix.service}} --debug
|
||||
|
||||
benchamrking:
|
||||
benchmarking:
|
||||
name: Benchmark
|
||||
runs-on: ubuntu-latest
|
||||
needs: setup
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Load Cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
key: ${{ env.CACHE_KEY }}
|
||||
path: /tmp/${{ env.IMAGE }}.tar
|
||||
|
|
|
|||
|
|
@ -883,9 +883,6 @@ class UsageTest extends Scope
|
|||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
|
||||
$code = realpath(__DIR__ . '/../../resources/functions') . "/php/code.tar.gz";
|
||||
$this->packageCode('php');
|
||||
|
||||
$response = $this->client->call(
|
||||
Client::METHOD_POST,
|
||||
'/functions/' . $functionId . '/deployments',
|
||||
|
|
@ -895,8 +892,8 @@ class UsageTest extends Scope
|
|||
], $this->getHeaders()),
|
||||
[
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => new CURLFile($code, 'application/x-gzip', \basename($code)),
|
||||
'activate' => true
|
||||
'code' => $this->packageFunction('php'),
|
||||
'activate' => true,
|
||||
]
|
||||
);
|
||||
|
||||
|
|
@ -934,7 +931,7 @@ class UsageTest extends Scope
|
|||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()),
|
||||
[
|
||||
'async' => false,
|
||||
'async' => 'false',
|
||||
]
|
||||
);
|
||||
|
||||
|
|
@ -958,7 +955,7 @@ class UsageTest extends Scope
|
|||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()),
|
||||
[
|
||||
'async' => false,
|
||||
'async' => 'false',
|
||||
]
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,234 +2,207 @@
|
|||
|
||||
namespace Tests\E2E\Services\Functions;
|
||||
|
||||
use Appwrite\Tests\Async;
|
||||
use CURLFile;
|
||||
use Tests\E2E\Client;
|
||||
use Utopia\CLI\Console;
|
||||
|
||||
trait FunctionsBase
|
||||
{
|
||||
use Async;
|
||||
|
||||
protected string $stdout = '';
|
||||
protected string $stderr = '';
|
||||
|
||||
protected function packageCode($folder)
|
||||
protected function setupFunction(mixed $params): string
|
||||
{
|
||||
Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/$folder && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr);
|
||||
$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'],
|
||||
]), $params);
|
||||
|
||||
$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'];
|
||||
|
||||
return $functionId;
|
||||
}
|
||||
|
||||
protected function awaitDeploymentIsBuilt($functionId, $deploymentId, $checkForSuccess = true): void
|
||||
protected function setupDeployment(string $functionId, mixed $params): string
|
||||
{
|
||||
while (true) {
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/deployments/' . $deploymentId, [
|
||||
$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'],
|
||||
]), $params);
|
||||
$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) {
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
]));
|
||||
$this->assertEquals('ready', $deployment['body']['status'], 'Deployment status is not ready, deployment: ' . json_encode($deployment['body'], JSON_PRETTY_PRINT));
|
||||
}, 50000, 500);
|
||||
|
||||
if (
|
||||
$deployment['headers']['status-code'] >= 400
|
||||
|| \in_array($deployment['body']['status'], ['ready', 'failed'])
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
|
||||
if ($checkForSuccess) {
|
||||
$this->assertEquals(200, $deployment['headers']['status-code']);
|
||||
$this->assertEquals('ready', $deployment['body']['status'], \json_encode($deployment['body']));
|
||||
}
|
||||
return $deploymentId;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @depends testCreateTeam
|
||||
// */
|
||||
// public function testGetTeam($data):array
|
||||
// {
|
||||
// $id = $data['teamUid'] ?? '';
|
||||
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'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]));
|
||||
|
||||
// /**
|
||||
// * Test for SUCCESS
|
||||
// */
|
||||
// $response = $this->client->call(Client::METHOD_GET, '/teams/'.$id, array_merge([
|
||||
// 'content-type' => 'application/json',
|
||||
// 'x-appwrite-project' => $this->getProject()['$id'],
|
||||
// ], $this->getHeaders()));
|
||||
$this->assertEquals($function['headers']['status-code'], 204);
|
||||
}
|
||||
|
||||
// $this->assertEquals(200, $response['headers']['status-code']);
|
||||
// $this->assertNotEmpty($response['body']['$id']);
|
||||
// $this->assertEquals('Arsenal', $response['body']['name']);
|
||||
// $this->assertGreaterThan(-1, $response['body']['total']);
|
||||
// $this->assertIsInt($response['body']['total']);
|
||||
// $this->assertIsInt($response['body']['dateCreated']);
|
||||
protected function createFunction(mixed $params): mixed
|
||||
{
|
||||
$function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), $params);
|
||||
|
||||
// /**
|
||||
// * Test for FAILURE
|
||||
// */
|
||||
return $function;
|
||||
}
|
||||
|
||||
// return [];
|
||||
// }
|
||||
protected function createVariable(string $functionId, mixed $params): mixed
|
||||
{
|
||||
$variable = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), $params);
|
||||
|
||||
// /**
|
||||
// * @depends testCreateTeam
|
||||
// */
|
||||
// public function testListTeams($data):array
|
||||
// {
|
||||
// /**
|
||||
// * Test for SUCCESS
|
||||
// */
|
||||
// $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([
|
||||
// 'content-type' => 'application/json',
|
||||
// 'x-appwrite-project' => $this->getProject()['$id'],
|
||||
// ], $this->getHeaders()));
|
||||
return $variable;
|
||||
}
|
||||
|
||||
// $this->assertEquals(200, $response['headers']['status-code']);
|
||||
// $this->assertGreaterThan(0, $response['body']['total']);
|
||||
// $this->assertIsInt($response['body']['total']);
|
||||
// $this->assertCount(3, $response['body']['teams']);
|
||||
protected function getFunction(string $functionId): mixed
|
||||
{
|
||||
$function = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
// $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([
|
||||
// 'content-type' => 'application/json',
|
||||
// 'x-appwrite-project' => $this->getProject()['$id'],
|
||||
// ], $this->getHeaders()), [
|
||||
// 'limit' => 2,
|
||||
// ]);
|
||||
return $function;
|
||||
}
|
||||
|
||||
// $this->assertEquals(200, $response['headers']['status-code']);
|
||||
// $this->assertGreaterThan(0, $response['body']['total']);
|
||||
// $this->assertIsInt($response['body']['total']);
|
||||
// $this->assertCount(2, $response['body']['teams']);
|
||||
protected function getDeployment(string $functionId, string $deploymentId): mixed
|
||||
{
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
// $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([
|
||||
// 'content-type' => 'application/json',
|
||||
// 'x-appwrite-project' => $this->getProject()['$id'],
|
||||
// ], $this->getHeaders()), [
|
||||
// 'offset' => 1,
|
||||
// ]);
|
||||
return $deployment;
|
||||
}
|
||||
|
||||
// $this->assertEquals(200, $response['headers']['status-code']);
|
||||
// $this->assertGreaterThan(0, $response['body']['total']);
|
||||
// $this->assertIsInt($response['body']['total']);
|
||||
// $this->assertCount(2, $response['body']['teams']);
|
||||
protected function getExecution(string $functionId, $executionId): mixed
|
||||
{
|
||||
$execution = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
// $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([
|
||||
// 'content-type' => 'application/json',
|
||||
// 'x-appwrite-project' => $this->getProject()['$id'],
|
||||
// ], $this->getHeaders()), [
|
||||
// 'search' => 'Manchester',
|
||||
// ]);
|
||||
return $execution;
|
||||
}
|
||||
|
||||
// $this->assertEquals(200, $response['headers']['status-code']);
|
||||
// $this->assertGreaterThan(0, $response['body']['total']);
|
||||
// $this->assertIsInt($response['body']['total']);
|
||||
// $this->assertCount(1, $response['body']['teams']);
|
||||
// $this->assertEquals('Manchester United', $response['body']['teams'][0]['name']);
|
||||
protected function listFunctions(mixed $params = []): mixed
|
||||
{
|
||||
$functions = $this->client->call(Client::METHOD_GET, '/functions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), $params);
|
||||
|
||||
// $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([
|
||||
// 'content-type' => 'application/json',
|
||||
// 'x-appwrite-project' => $this->getProject()['$id'],
|
||||
// ], $this->getHeaders()), [
|
||||
// 'search' => 'United',
|
||||
// ]);
|
||||
return $functions;
|
||||
}
|
||||
|
||||
// $this->assertEquals(200, $response['headers']['status-code']);
|
||||
// $this->assertGreaterThan(0, $response['body']['total']);
|
||||
// $this->assertIsInt($response['body']['total']);
|
||||
// $this->assertCount(1, $response['body']['teams']);
|
||||
// $this->assertEquals('Manchester United', $response['body']['teams'][0]['name']);
|
||||
protected function listDeployments(string $functionId, $params = []): mixed
|
||||
{
|
||||
$deployments = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/deployments', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), $params);
|
||||
|
||||
// /**
|
||||
// * Test for FAILURE
|
||||
// */
|
||||
return $deployments;
|
||||
}
|
||||
|
||||
// return [];
|
||||
// }
|
||||
protected function listExecutions(string $functionId, mixed $params = []): mixed
|
||||
{
|
||||
$executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), $params);
|
||||
|
||||
// public function testUpdateTeam():array
|
||||
// {
|
||||
// /**
|
||||
// * Test for SUCCESS
|
||||
// */
|
||||
// $response = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
|
||||
// 'content-type' => 'application/json',
|
||||
// 'x-appwrite-project' => $this->getProject()['$id'],
|
||||
// ], $this->getHeaders()), [
|
||||
// 'name' => 'Demo'
|
||||
// ]);
|
||||
return $executions;
|
||||
}
|
||||
|
||||
// $this->assertEquals(201, $response['headers']['status-code']);
|
||||
// $this->assertNotEmpty($response['body']['$id']);
|
||||
// $this->assertEquals('Demo', $response['body']['name']);
|
||||
// $this->assertGreaterThan(-1, $response['body']['total']);
|
||||
// $this->assertIsInt($response['body']['total']);
|
||||
// $this->assertIsInt($response['body']['dateCreated']);
|
||||
protected function packageFunction(string $function): CURLFile
|
||||
{
|
||||
$folderPath = realpath(__DIR__ . '/../../../resources/functions') . "/$function";
|
||||
$tarPath = "$folderPath/code.tar.gz";
|
||||
|
||||
// $response = $this->client->call(Client::METHOD_PUT, '/teams/'.$response['body']['$id'], array_merge([
|
||||
// 'content-type' => 'application/json',
|
||||
// 'x-appwrite-project' => $this->getProject()['$id'],
|
||||
// ], $this->getHeaders()), [
|
||||
// 'name' => 'Demo New'
|
||||
// ]);
|
||||
Console::execute("cd $folderPath && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr);
|
||||
|
||||
// $this->assertEquals(200, $response['headers']['status-code']);
|
||||
// $this->assertNotEmpty($response['body']['$id']);
|
||||
// $this->assertEquals('Demo New', $response['body']['name']);
|
||||
// $this->assertGreaterThan(-1, $response['body']['total']);
|
||||
// $this->assertIsInt($response['body']['total']);
|
||||
// $this->assertIsInt($response['body']['dateCreated']);
|
||||
if (filesize($tarPath) > 1024 * 1024 * 5) {
|
||||
throw new \Exception('Code package is too large. Use the chunked upload method instead.');
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Test for FAILURE
|
||||
// */
|
||||
// $response = $this->client->call(Client::METHOD_PUT, '/teams/'.$response['body']['$id'], array_merge([
|
||||
// 'content-type' => 'application/json',
|
||||
// 'x-appwrite-project' => $this->getProject()['$id'],
|
||||
// ], $this->getHeaders()), [
|
||||
// ]);
|
||||
return new CURLFile($tarPath, 'application/x-gzip', \basename($tarPath));
|
||||
}
|
||||
|
||||
// $this->assertEquals(400, $response['headers']['status-code']);
|
||||
protected function createDeployment(string $functionId, mixed $params = []): mixed
|
||||
{
|
||||
$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()), $params);
|
||||
|
||||
// return [];
|
||||
// }
|
||||
return $deployment;
|
||||
}
|
||||
|
||||
// public function testDeleteTeam():array
|
||||
// {
|
||||
// /**
|
||||
// * Test for SUCCESS
|
||||
// */
|
||||
// $response = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
|
||||
// 'content-type' => 'application/json',
|
||||
// 'x-appwrite-project' => $this->getProject()['$id'],
|
||||
// ], $this->getHeaders()), [
|
||||
// 'name' => 'Demo'
|
||||
// ]);
|
||||
protected function getFunctionUsage(string $functionId, mixed $params): mixed
|
||||
{
|
||||
$usage = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/usage', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), $params);
|
||||
|
||||
// $teamUid = $response['body']['$id'];
|
||||
return $usage;
|
||||
}
|
||||
|
||||
// $this->assertEquals(201, $response['headers']['status-code']);
|
||||
// $this->assertNotEmpty($response['body']['$id']);
|
||||
// $this->assertEquals('Demo', $response['body']['name']);
|
||||
// $this->assertGreaterThan(-1, $response['body']['total']);
|
||||
// $this->assertIsInt($response['body']['total']);
|
||||
// $this->assertIsInt($response['body']['dateCreated']);
|
||||
protected function getTemplate(string $templateId)
|
||||
{
|
||||
$template = $this->client->call(Client::METHOD_GET, '/functions/templates/' . $templateId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
// $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid, array_merge([
|
||||
// 'content-type' => 'application/json',
|
||||
// 'x-appwrite-project' => $this->getProject()['$id'],
|
||||
// ], $this->getHeaders()));
|
||||
return $template;
|
||||
}
|
||||
|
||||
// $this->assertEquals(204, $response['headers']['status-code']);
|
||||
// $this->assertEmpty($response['body']);
|
||||
protected function createExecution(string $functionId, mixed $params = []): mixed
|
||||
{
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), $params);
|
||||
|
||||
// /**
|
||||
// * Test for FAILURE
|
||||
// */
|
||||
// $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid, array_merge([
|
||||
// 'content-type' => 'application/json',
|
||||
// 'x-appwrite-project' => $this->getProject()['$id'],
|
||||
// ], $this->getHeaders()));
|
||||
return $execution;
|
||||
}
|
||||
|
||||
// $this->assertEquals(404, $response['headers']['status-code']);
|
||||
protected function deleteFunction(string $functionId): mixed
|
||||
{
|
||||
$function = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
// return [];
|
||||
// }
|
||||
return $function;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,13 +13,11 @@ class FunctionsConsoleClientTest extends Scope
|
|||
{
|
||||
use ProjectCustom;
|
||||
use SideConsole;
|
||||
use FunctionsBase;
|
||||
|
||||
public function testCreateFunction(): array
|
||||
{
|
||||
$function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
$function = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::user($this->getUser()['$id'])->toString()],
|
||||
|
|
@ -35,10 +33,9 @@ class FunctionsConsoleClientTest extends Scope
|
|||
|
||||
$this->assertEquals(201, $function['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
$functionId = $function['body']['$id'];
|
||||
|
||||
$function2 = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test Failure',
|
||||
'execute' => ['some-random-string'],
|
||||
|
|
@ -46,73 +43,59 @@ class FunctionsConsoleClientTest extends Scope
|
|||
'entrypoint' => 'index.php',
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
$this->assertEquals(400, $function2['headers']['status-code']);
|
||||
|
||||
return [
|
||||
'functionId' => $function['body']['$id']
|
||||
'functionId' => $functionId,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateFunction
|
||||
*/
|
||||
public function testGetCollectionUsage(array $data)
|
||||
public function testFunctionUsage(array $data)
|
||||
{
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/usage', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()), [
|
||||
'range' => '232h'
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/functions/randomFunctionId/usage', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()), [
|
||||
'range' => '24h'
|
||||
]);
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/usage', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()), [
|
||||
$usage = $this->getFunctionUsage($data['functionId'], [
|
||||
'range' => '24h'
|
||||
]);
|
||||
$this->assertEquals(200, $usage['headers']['status-code']);
|
||||
$this->assertEquals(19, count($usage['body']));
|
||||
$this->assertEquals('24h', $usage['body']['range']);
|
||||
$this->assertIsNumeric($usage['body']['deploymentsTotal']);
|
||||
$this->assertIsNumeric($usage['body']['deploymentsStorageTotal']);
|
||||
$this->assertIsNumeric($usage['body']['buildsTotal']);
|
||||
$this->assertIsNumeric($usage['body']['buildsStorageTotal']);
|
||||
$this->assertIsNumeric($usage['body']['buildsTimeTotal']);
|
||||
$this->assertIsNumeric($usage['body']['buildsMbSecondsTotal']);
|
||||
$this->assertIsNumeric($usage['body']['executionsTotal']);
|
||||
$this->assertIsNumeric($usage['body']['executionsTimeTotal']);
|
||||
$this->assertIsNumeric($usage['body']['executionsMbSecondsTotal']);
|
||||
$this->assertIsArray($usage['body']['deployments']);
|
||||
$this->assertIsArray($usage['body']['deploymentsStorage']);
|
||||
$this->assertIsArray($usage['body']['builds']);
|
||||
$this->assertIsArray($usage['body']['buildsTime']);
|
||||
$this->assertIsArray($usage['body']['buildsStorage']);
|
||||
$this->assertIsArray($usage['body']['buildsTime']);
|
||||
$this->assertIsArray($usage['body']['buildsMbSeconds']);
|
||||
$this->assertIsArray($usage['body']['executions']);
|
||||
$this->assertIsArray($usage['body']['executionsTime']);
|
||||
$this->assertIsArray($usage['body']['executionsMbSeconds']);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(19, count($response['body']));
|
||||
$this->assertEquals('24h', $response['body']['range']);
|
||||
$this->assertIsNumeric($response['body']['deploymentsTotal']);
|
||||
$this->assertIsNumeric($response['body']['deploymentsStorageTotal']);
|
||||
$this->assertIsNumeric($response['body']['buildsTotal']);
|
||||
$this->assertIsNumeric($response['body']['buildsStorageTotal']);
|
||||
$this->assertIsNumeric($response['body']['buildsTimeTotal']);
|
||||
$this->assertIsNumeric($response['body']['buildsMbSecondsTotal']);
|
||||
$this->assertIsNumeric($response['body']['executionsTotal']);
|
||||
$this->assertIsNumeric($response['body']['executionsTimeTotal']);
|
||||
$this->assertIsNumeric($response['body']['executionsMbSecondsTotal']);
|
||||
$this->assertIsArray($response['body']['deployments']);
|
||||
$this->assertIsArray($response['body']['deploymentsStorage']);
|
||||
$this->assertIsArray($response['body']['builds']);
|
||||
$this->assertIsArray($response['body']['buildsTime']);
|
||||
$this->assertIsArray($response['body']['buildsStorage']);
|
||||
$this->assertIsArray($response['body']['buildsTime']);
|
||||
$this->assertIsArray($response['body']['buildsMbSeconds']);
|
||||
$this->assertIsArray($response['body']['executions']);
|
||||
$this->assertIsArray($response['body']['executionsTime']);
|
||||
$this->assertIsArray($response['body']['executionsMbSeconds']);
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
$usage = $this->getFunctionUsage($data['functionId'], [
|
||||
'range' => '232h'
|
||||
]);
|
||||
$this->assertEquals(400, $usage['headers']['status-code']);
|
||||
|
||||
$usage = $this->getFunctionUsage('randomFunctionId', [
|
||||
'range' => '24h'
|
||||
]);
|
||||
$this->assertEquals(404, $usage['headers']['status-code']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -123,31 +106,53 @@ class FunctionsConsoleClientTest extends Scope
|
|||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$variable = $this->createVariable(
|
||||
$data['functionId'],
|
||||
[
|
||||
'key' => 'APP_TEST',
|
||||
'value' => 'TESTINGVALUE'
|
||||
]
|
||||
);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/variables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'key' => 'APP_TEST',
|
||||
'value' => 'TESTINGVALUE'
|
||||
]);
|
||||
$this->assertEquals(201, $variable['headers']['status-code']);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
$variableId = $response['body']['$id'];
|
||||
$variableId = $variable['body']['$id'];
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
// Test for duplicate key
|
||||
$variable = $this->createVariable(
|
||||
$data['functionId'],
|
||||
[
|
||||
'key' => 'APP_TEST',
|
||||
'value' => 'ANOTHERTESTINGVALUE'
|
||||
]
|
||||
);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/variables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'key' => 'APP_TEST',
|
||||
'value' => 'ANOTHER_TESTINGVALUE'
|
||||
]);
|
||||
$this->assertEquals(409, $variable['headers']['status-code']);
|
||||
|
||||
$this->assertEquals(409, $response['headers']['status-code']);
|
||||
// Test for invalid key
|
||||
$variable = $this->createVariable(
|
||||
$data['functionId'],
|
||||
[
|
||||
'key' => str_repeat("A", 256),
|
||||
'value' => 'TESTINGVALUE'
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(400, $variable['headers']['status-code']);
|
||||
|
||||
// Test for invalid value
|
||||
$variable = $this->createVariable(
|
||||
$data['functionId'],
|
||||
[
|
||||
'key' => 'LONGKEY',
|
||||
'value' => str_repeat("#", 8193),
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(400, $variable['headers']['status-code']);
|
||||
|
||||
return array_merge(
|
||||
$data,
|
||||
|
|
@ -155,28 +160,6 @@ class FunctionsConsoleClientTest extends Scope
|
|||
'variableId' => $variableId
|
||||
]
|
||||
);
|
||||
|
||||
$longKey = str_repeat("A", 256);
|
||||
$response = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/variables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'key' => $longKey,
|
||||
'value' => 'TESTINGVALUE'
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
$longValue = str_repeat("#", 8193);
|
||||
$response = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/variables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'key' => 'LONGKEY',
|
||||
'value' => $longValue
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
214
tests/e2e/Services/FunctionsSchedule/FunctionsScheduleTest.php
Normal file
214
tests/e2e/Services/FunctionsSchedule/FunctionsScheduleTest.php
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Functions;
|
||||
|
||||
use Appwrite\ID;
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideServer;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
|
||||
class FunctionsScheduleTest extends Scope
|
||||
{
|
||||
use FunctionsBase;
|
||||
use ProjectCustom;
|
||||
use SideServer;
|
||||
|
||||
public function testCreateScheduledExecution()
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::user($this->getUser()['$id'])->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'events' => [
|
||||
'users.*.create',
|
||||
'users.*.delete',
|
||||
],
|
||||
'schedule' => '* * * * *', // Execute every 60 seconds
|
||||
'timeout' => 10,
|
||||
]);
|
||||
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
// Wait for scheduled execution
|
||||
\sleep(60);
|
||||
|
||||
$this->assertEventually(function () use ($functionId) {
|
||||
$executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $executions['headers']['status-code']);
|
||||
$this->assertCount(1, $executions['body']['executions']);
|
||||
|
||||
$asyncExecution = $executions['body']['executions'][0];
|
||||
|
||||
$this->assertEquals('schedule', $asyncExecution['trigger']);
|
||||
$this->assertEquals('completed', $asyncExecution['status']);
|
||||
$this->assertEquals(200, $asyncExecution['responseStatusCode']);
|
||||
$this->assertEquals('', $asyncExecution['responseBody']);
|
||||
$this->assertNotEmpty($asyncExecution['logs']);
|
||||
$this->assertNotEmpty($asyncExecution['errors']);
|
||||
$this->assertGreaterThan(0, $asyncExecution['duration']);
|
||||
}, 60000, 500);
|
||||
|
||||
$this->cleanupFunction($functionId);
|
||||
}
|
||||
|
||||
public function testCreateScheduledAtExecution(): void
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::user($this->getUser()['$id'])->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'timeout' => 10,
|
||||
'logging' => true,
|
||||
]);
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
// Schedule execution for the future
|
||||
\date_default_timezone_set('UTC');
|
||||
$futureTime = (new \DateTime())->add(new \DateInterval('PT2M')); // 2 minute in the future
|
||||
$futureTime->setTime($futureTime->format('H'), $futureTime->format('i'), 0, 0);
|
||||
|
||||
|
||||
$execution = $this->client->call(
|
||||
Client::METHOD_POST,
|
||||
'/functions/' . $functionId . '/executions',
|
||||
[
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'origin' => 'http://localhost',
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $this->getUser()['session'],
|
||||
],
|
||||
[
|
||||
'async' => true,
|
||||
'scheduledAt' => $futureTime->format(\DateTime::ATOM),
|
||||
'path' => '/custom-path',
|
||||
'method' => 'PATCH',
|
||||
'body' => 'custom-body',
|
||||
'headers' => [
|
||||
'x-custom-header' => 'custom-value'
|
||||
]
|
||||
]
|
||||
);
|
||||
$executionId = $execution['body']['$id'];
|
||||
|
||||
$this->assertEquals(202, $execution['headers']['status-code']);
|
||||
$this->assertEquals('scheduled', $execution['body']['status']);
|
||||
$this->assertEquals('PATCH', $execution['body']['requestMethod']);
|
||||
$this->assertEquals('/custom-path', $execution['body']['requestPath']);
|
||||
$this->assertCount(0, $execution['body']['requestHeaders']);
|
||||
|
||||
\sleep(120);
|
||||
|
||||
$this->assertEventually(function () use ($functionId, $executionId) {
|
||||
$execution = $this->getExecution($functionId, $executionId);
|
||||
|
||||
$this->assertEquals(200, $execution['headers']['status-code']);
|
||||
$this->assertEquals(200, $execution['body']['responseStatusCode']);
|
||||
$this->assertEquals('completed', $execution['body']['status']);
|
||||
$this->assertEquals('/custom-path', $execution['body']['requestPath']);
|
||||
$this->assertEquals('PATCH', $execution['body']['requestMethod']);
|
||||
$this->assertStringContainsString('body-is-custom-body', $execution['body']['logs']);
|
||||
$this->assertStringContainsString('custom-header-is-custom-value', $execution['body']['logs']);
|
||||
$this->assertStringContainsString('method-is-patch', $execution['body']['logs']);
|
||||
$this->assertStringContainsString('path-is-/custom-path', $execution['body']['logs']);
|
||||
$this->assertStringContainsString('user-is-' . $this->getUser()['$id'], $execution['body']['logs']);
|
||||
$this->assertStringContainsString('jwt-is-valid', $execution['body']['logs']);
|
||||
$this->assertGreaterThan(0, $execution['body']['duration']);
|
||||
}, 10000, 500);
|
||||
|
||||
/* Test for FAILURE */
|
||||
// Schedule synchronous execution
|
||||
$execution = $this->createExecution($functionId, [
|
||||
'async' => 'false',
|
||||
'scheduledAt' => $futureTime->format(\DateTime::ATOM),
|
||||
]);
|
||||
$this->assertEquals(400, $execution['headers']['status-code']);
|
||||
|
||||
// Execution with seconds precision
|
||||
$execution = $this->createExecution($functionId, [
|
||||
'async' => true,
|
||||
'scheduledAt' => (new \DateTime("2100-12-08 16:12:02"))->format(\DateTime::ATOM)
|
||||
]);
|
||||
$this->assertEquals(400, $execution['headers']['status-code']);
|
||||
|
||||
// Execution with milliseconds precision
|
||||
$execution = $this->createExecution($functionId, [
|
||||
'async' => true,
|
||||
'scheduledAt' => (new \DateTime("2100-12-08 16:12:02.255"))->format(\DateTime::ATOM)
|
||||
]);
|
||||
$this->assertEquals(400, $execution['headers']['status-code']);
|
||||
|
||||
// Execution too soon
|
||||
$execution = $this->createExecution($functionId, [
|
||||
'async' => true,
|
||||
'scheduledAt' => (new \DateTime())->add(new \DateInterval('PT1S'))->format(\DateTime::ATOM)
|
||||
]);
|
||||
$this->assertEquals(400, $execution['headers']['status-code']);
|
||||
|
||||
$this->cleanupFunction($functionId, $executionId);
|
||||
}
|
||||
|
||||
public function testDeleteScheduledExecution()
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::user($this->getUser()['$id'])->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'timeout' => 10,
|
||||
'logging' => true,
|
||||
]);
|
||||
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
$futureTime = (new \DateTime())->add(new \DateInterval('PT10H'));
|
||||
$futureTime->setTime($futureTime->format('H'), $futureTime->format('i'), 0, 0);
|
||||
|
||||
$execution = $this->createExecution($functionId, [
|
||||
'async' => true,
|
||||
'scheduledAt' => $futureTime->format('Y-m-d H:i:s'),
|
||||
]);
|
||||
|
||||
$this->assertEquals(202, $execution['headers']['status-code']);
|
||||
|
||||
$executionId = $execution['body']['$id'] ?? '';
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(204, $execution['headers']['status-code']);
|
||||
|
||||
$this->cleanupFunction($functionId);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Tests\E2E\Services\GraphQL;
|
||||
|
||||
use CURLFile;
|
||||
use Utopia\CLI\Console;
|
||||
|
||||
trait Base
|
||||
|
|
@ -2496,8 +2497,17 @@ trait Base
|
|||
protected string $stdout = '';
|
||||
protected string $stderr = '';
|
||||
|
||||
protected function packageCode($folder): void
|
||||
protected function packageFunction(string $function): CURLFile
|
||||
{
|
||||
Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/$folder && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr);
|
||||
$folderPath = realpath(__DIR__ . '/../../../resources/functions') . "/$function";
|
||||
$tarPath = "$folderPath/code.tar.gz";
|
||||
|
||||
Console::execute("cd $folderPath && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Tests\E2E\Services\GraphQL;
|
||||
|
||||
use CURLFile;
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
|
|
@ -83,10 +82,6 @@ class FunctionsClientTest extends Scope
|
|||
$projectId = $this->getProject()['$id'];
|
||||
$query = $this->getQuery(self::$CREATE_DEPLOYMENT);
|
||||
|
||||
$folder = 'php';
|
||||
$code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
|
||||
$this->packageCode($folder);
|
||||
|
||||
$gqlPayload = [
|
||||
'operations' => \json_encode([
|
||||
'query' => $query,
|
||||
|
|
@ -99,7 +94,7 @@ class FunctionsClientTest extends Scope
|
|||
'map' => \json_encode([
|
||||
'code' => ["variables.code"]
|
||||
]),
|
||||
'code' => new CURLFile($code, 'application/gzip', 'code.tar.gz'),
|
||||
'code' => $this->packageFunction('php')
|
||||
];
|
||||
|
||||
$deployment = $this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Tests\E2E\Services\GraphQL;
|
||||
|
||||
use CURLFile;
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
|
|
@ -82,10 +81,6 @@ class FunctionsServerTest extends Scope
|
|||
$projectId = $this->getProject()['$id'];
|
||||
$query = $this->getQuery(self::$CREATE_DEPLOYMENT);
|
||||
|
||||
$folder = 'php';
|
||||
$code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
|
||||
$this->packageCode($folder);
|
||||
|
||||
$gqlPayload = [
|
||||
'operations' => \json_encode([
|
||||
'query' => $query,
|
||||
|
|
@ -98,7 +93,7 @@ class FunctionsServerTest extends Scope
|
|||
'map' => \json_encode([
|
||||
'code' => ["variables.code"]
|
||||
]),
|
||||
'code' => new CURLFile($code, 'application/gzip', 'code.tar.gz'),
|
||||
'code' => $this->packageFunction('php'),
|
||||
];
|
||||
|
||||
$deployment = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Tests\E2E\Services\Realtime;
|
||||
|
||||
use CURLFile;
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
|
|
@ -506,21 +505,15 @@ class RealtimeConsoleClientTest extends Scope
|
|||
* Test Create Deployment
|
||||
*/
|
||||
|
||||
$folder = 'php';
|
||||
$code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
|
||||
$this->packageCode($folder);
|
||||
|
||||
$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()), [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => new CURLFile($code, 'application/x-gzip', \basename($code)),
|
||||
'code' => $this->packageFunction('php'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
$deploymentId = $deployment['body']['$id'] ?? '';
|
||||
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use Tests\E2E\Client;
|
|||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideClient;
|
||||
use Utopia\CLI\Console;
|
||||
use Tests\E2E\Services\Functions\FunctionsBase;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
|
|
@ -15,6 +15,7 @@ use WebSocket\ConnectionException;
|
|||
|
||||
class RealtimeCustomClientTest extends Scope
|
||||
{
|
||||
use FunctionsBase;
|
||||
use RealtimeBase;
|
||||
use ProjectCustom;
|
||||
use SideClient;
|
||||
|
|
@ -1271,20 +1272,13 @@ class RealtimeCustomClientTest extends Scope
|
|||
$this->assertEquals($function['headers']['status-code'], 201);
|
||||
$this->assertNotEmpty($function['body']['$id']);
|
||||
|
||||
$folder = 'timeout';
|
||||
$stderr = '';
|
||||
$stdout = '';
|
||||
$code = realpath(__DIR__ . '/../../../resources/functions') . "/{$folder}/code.tar.gz";
|
||||
|
||||
Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/{$folder} && tar --exclude code.tar.gz -czf code.tar.gz .", '', $stdout, $stderr);
|
||||
|
||||
$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']
|
||||
]), [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
|
||||
'code' => $this->packageFunction('timeout'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
|
|
|
|||
17
tests/extensions/Async.php
Normal file
17
tests/extensions/Async.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Tests;
|
||||
|
||||
use Appwrite\Tests\Async\Eventually;
|
||||
use PHPUnit\Framework\Assert;
|
||||
|
||||
const DEFAULT_TIMEOUT_MS = 10000;
|
||||
const DEFAULT_WAIT_MS = 500;
|
||||
|
||||
trait Async
|
||||
{
|
||||
public static function assertEventually(callable $probe, int $timeoutMs = DEFAULT_TIMEOUT_MS, int $waitMs = DEFAULT_WAIT_MS): void
|
||||
{
|
||||
Assert::assertThat($probe, new Eventually($timeoutMs, $waitMs));
|
||||
}
|
||||
}
|
||||
49
tests/extensions/Async/Eventually.php
Normal file
49
tests/extensions/Async/Eventually.php
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Tests\Async;
|
||||
|
||||
use PHPUnit\Framework\Constraint\Constraint;
|
||||
|
||||
final class Eventually extends Constraint
|
||||
{
|
||||
public function __construct(private int $timeoutMs, private int $waitMs)
|
||||
{
|
||||
}
|
||||
|
||||
public function evaluate(mixed $probe, string $description = '', bool $returnResult = false): ?bool
|
||||
{
|
||||
if (!is_callable($probe)) {
|
||||
throw new \Exception('Probe must be a callable');
|
||||
}
|
||||
|
||||
$start = microtime(true);
|
||||
$lastException = null;
|
||||
|
||||
do {
|
||||
try {
|
||||
$probe();
|
||||
return true;
|
||||
} catch (\Exception $exception) {
|
||||
$lastException = $exception;
|
||||
}
|
||||
|
||||
usleep($this->waitMs * 1000);
|
||||
} while (microtime(true) - $start < $this->timeoutMs / 1000);
|
||||
|
||||
if ($returnResult) {
|
||||
return false;
|
||||
}
|
||||
|
||||
throw $lastException;
|
||||
}
|
||||
|
||||
protected function failureDescription(mixed $other): string
|
||||
{
|
||||
return 'the given probe was satisfied within ' . $this->timeoutMs . 'ms.';
|
||||
}
|
||||
|
||||
public function toString(): string
|
||||
{
|
||||
return 'Eventually';
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue