From c4d64a52d6177f512e94065677b488bf9153a268 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Fri, 30 Aug 2024 12:55:25 +0900 Subject: [PATCH 1/4] Fix Bandwidth and other metrics not being tracked for custom domain executions --- app/controllers/general.php | 9 +++++++++ .../e2e/Services/Functions/FunctionsCustomServerTest.php | 1 + 2 files changed, 10 insertions(+) diff --git a/app/controllers/general.php b/app/controllers/general.php index 8defeb72f6..ff670c68ca 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -330,7 +330,16 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo throw $th; } } finally { + $fileSize = 0; + $file = $request->getFiles('file'); + if (!empty($file)) { + $fileSize = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size']; + } + $queueForUsage + ->addMetric(METRIC_NETWORK_REQUESTS, 1) + ->addMetric(METRIC_NETWORK_INBOUND, $request->getSize() + $fileSize) + ->addMetric(METRIC_NETWORK_OUTBOUND, $response->getSize()) ->addMetric(METRIC_EXECUTIONS, 1) ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS), 1) ->addMetric(METRIC_EXECUTIONS_COMPUTE, (int)($execution->getAttribute('duration') * 1000)) // per project diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index 576dba3118..c88178c4cc 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -2445,6 +2445,7 @@ class FunctionsCustomServerTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(19, count($response['body'])); $this->assertEquals('24h', $response['body']['range']); + $this->assertEquals(1, $response['body']['executionsTotal']); // Cleanup : Delete function $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [ From cdfc6e640a0727ac593e90cdcb876edd14df2fd4 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Mon, 2 Sep 2024 13:18:19 +0900 Subject: [PATCH 2/4] Add Tests --- tests/e2e/General/UsageTest.php | 109 +++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-) diff --git a/tests/e2e/General/UsageTest.php b/tests/e2e/General/UsageTest.php index f4e45c293a..75b9e58bf3 100644 --- a/tests/e2e/General/UsageTest.php +++ b/tests/e2e/General/UsageTest.php @@ -13,6 +13,7 @@ use Tests\E2E\Scopes\SideServer; use Tests\E2E\Services\Functions\FunctionsBase; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; +use Utopia\Database\Query; use Utopia\Database\Validator\Datetime as DatetimeValidator; class UsageTest extends Scope @@ -761,7 +762,7 @@ class UsageTest extends Scope /** @depends testPrepareFunctionsStats */ #[Retry(count: 1)] - public function testFunctionsStats(array $data): void + public function testFunctionsStats(array $data): array { $functionId = $data['functionId']; $executionTime = $data['executionTime']; @@ -818,6 +819,112 @@ class UsageTest extends Scope $this->validateDates($response['body']['executionsTime']); $this->assertGreaterThan(0, $response['body']['buildsTime'][array_key_last($response['body']['buildsTime'])]['value']); $this->validateDates($response['body']['buildsTime']); + + return $data; + } + + /** @depends testFunctionsStats */ + public function testCustomDomainsFunctionStats(array $data): void + { + $functionId = $data['functionId']; + + $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $functionId, array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'] + ], $this->getHeaders()), [ + 'name' => 'Test', + 'execute' => ['any'] + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + + $rules = $this->client->call(Client::METHOD_GET, '/proxy/rules', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => [ + Query::equal('resourceId', [$functionId])->toString(), + Query::equal('resourceType', ['function'])->toString(), + ], + ]); + + $this->assertEquals(200, $rules['headers']['status-code']); + $this->assertEquals(1, $rules['body']['total']); + $this->assertCount(1, $rules['body']['rules']); + $this->assertNotEmpty($rules['body']['rules'][0]['domain']); + + $domain = $rules['body']['rules'][0]['domain']; + + $response = $this->client->call( + Client::METHOD_GET, + '/functions/' . $functionId . '/usage?range=30d', + $this->getConsoleHeaders() + ); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(19, count($response['body'])); + $this->assertEquals('30d', $response['body']['range']); + + $functionsMetrics = $response['body']; + + $response = $this->client->call( + Client::METHOD_GET, + '/project/usage', + $this->getConsoleHeaders(), + [ + 'period' => '1h', + 'startDate' => self::getToday(), + 'endDate' => self::getTomorrow(), + ] + ); + + $this->assertEquals(200, $response['headers']['status-code']); + + $projectMetrics = $response['body']; + + // Create custom domain execution + $proxyClient = new Client(); + $proxyClient->setEndpoint('http://' . $domain); + + $response = $proxyClient->call(Client::METHOD_GET, '/', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'] + ])); + + $this->assertEquals(200, $response['headers']['status-code']); + + sleep(self::WAIT); + + // Compare new values with old values + $response = $this->client->call( + Client::METHOD_GET, + '/functions/' . $functionId . '/usage?range=30d', + $this->getConsoleHeaders() + ); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(19, count($response['body'])); + $this->assertEquals('30d', $response['body']['range']); + + // Check if the new values are greater than the old values + $this->assertEquals($functionsMetrics['executionsTotal'] + 1, $response['body']['executionsTotal']); + $this->assertGreaterThan($functionsMetrics['executionsTimeTotal'], $response['body']['executionsTimeTotal']); + $this->assertGreaterThan($functionsMetrics['executionsMbSecondsTotal'], $response['body']['executionsMbSecondsTotal']); + + $response = $this->client->call( + Client::METHOD_GET, + '/project/usage', + $this->getConsoleHeaders(), + [ + 'period' => '1h', + 'startDate' => self::getToday(), + 'endDate' => self::getTomorrow(), + ] + ); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals($projectMetrics['executionsTotal'] + 1, $response['body']['executionsTotal']); + $this->assertGreaterThan($projectMetrics['executionsMbSecondsTotal'], $response['body']['executionsMbSecondsTotal']); } public function tearDown(): void From 87e12d028d05c62ad9905bd74f01726fe8a5ffd2 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Mon, 2 Sep 2024 13:50:58 +0900 Subject: [PATCH 3/4] Increase timer, run linter. --- tests/e2e/General/UsageTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/e2e/General/UsageTest.php b/tests/e2e/General/UsageTest.php index 75b9e58bf3..81ddc9f784 100644 --- a/tests/e2e/General/UsageTest.php +++ b/tests/e2e/General/UsageTest.php @@ -860,7 +860,7 @@ class UsageTest extends Scope '/functions/' . $functionId . '/usage?range=30d', $this->getConsoleHeaders() ); - + $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(19, count($response['body'])); $this->assertEquals('30d', $response['body']['range']); @@ -880,7 +880,7 @@ class UsageTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); - $projectMetrics = $response['body']; + $projectMetrics = $response['body']; // Create custom domain execution $proxyClient = new Client(); @@ -893,7 +893,7 @@ class UsageTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); - sleep(self::WAIT); + sleep(self::WAIT + 20); // Compare new values with old values $response = $this->client->call( @@ -901,7 +901,7 @@ class UsageTest extends Scope '/functions/' . $functionId . '/usage?range=30d', $this->getConsoleHeaders() ); - + $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(19, count($response['body'])); $this->assertEquals('30d', $response['body']['range']); From e17f391f258cf2b659bff1d393f76b3f6edf0b46 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Mon, 2 Sep 2024 18:57:02 +0900 Subject: [PATCH 4/4] Improve Test Reliabiltiy --- tests/e2e/General/UsageTest.php | 67 ++++++++++++------- .../Functions/FunctionsCustomServerTest.php | 35 +++++++--- 2 files changed, 66 insertions(+), 36 deletions(-) diff --git a/tests/e2e/General/UsageTest.php b/tests/e2e/General/UsageTest.php index 81ddc9f784..32e9eb6454 100644 --- a/tests/e2e/General/UsageTest.php +++ b/tests/e2e/General/UsageTest.php @@ -6,6 +6,7 @@ use Appwrite\Functions\Specification; use Appwrite\Tests\Retry; use CURLFile; use DateTime; +use PHPUnit\Framework\ExpectationFailedException; use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; @@ -894,37 +895,51 @@ class UsageTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); sleep(self::WAIT + 20); + $tries = 0; - // Compare new values with old values - $response = $this->client->call( - Client::METHOD_GET, - '/functions/' . $functionId . '/usage?range=30d', - $this->getConsoleHeaders() - ); + while (true) { + try { + // Compare new values with old values + $response = $this->client->call( + Client::METHOD_GET, + '/functions/' . $functionId . '/usage?range=30d', + $this->getConsoleHeaders() + ); - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(19, count($response['body'])); - $this->assertEquals('30d', $response['body']['range']); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(19, count($response['body'])); + $this->assertEquals('30d', $response['body']['range']); - // Check if the new values are greater than the old values - $this->assertEquals($functionsMetrics['executionsTotal'] + 1, $response['body']['executionsTotal']); - $this->assertGreaterThan($functionsMetrics['executionsTimeTotal'], $response['body']['executionsTimeTotal']); - $this->assertGreaterThan($functionsMetrics['executionsMbSecondsTotal'], $response['body']['executionsMbSecondsTotal']); + // Check if the new values are greater than the old values + $this->assertEquals($functionsMetrics['executionsTotal'] + 1, $response['body']['executionsTotal']); + $this->assertGreaterThan($functionsMetrics['executionsTimeTotal'], $response['body']['executionsTimeTotal']); + $this->assertGreaterThan($functionsMetrics['executionsMbSecondsTotal'], $response['body']['executionsMbSecondsTotal']); - $response = $this->client->call( - Client::METHOD_GET, - '/project/usage', - $this->getConsoleHeaders(), - [ - 'period' => '1h', - 'startDate' => self::getToday(), - 'endDate' => self::getTomorrow(), - ] - ); + $response = $this->client->call( + Client::METHOD_GET, + '/project/usage', + $this->getConsoleHeaders(), + [ + 'period' => '1h', + 'startDate' => self::getToday(), + 'endDate' => self::getTomorrow(), + ] + ); - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals($projectMetrics['executionsTotal'] + 1, $response['body']['executionsTotal']); - $this->assertGreaterThan($projectMetrics['executionsMbSecondsTotal'], $response['body']['executionsMbSecondsTotal']); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals($projectMetrics['executionsTotal'] + 1, $response['body']['executionsTotal']); + $this->assertGreaterThan($projectMetrics['executionsMbSecondsTotal'], $response['body']['executionsMbSecondsTotal']); + + break; + } catch (ExpectationFailedException $th) { + if ($tries >= 5) { + throw $th; + } else { + $tries++; + sleep(5); + } + } + } } public function tearDown(): void diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index c88178c4cc..0607f40924 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -5,6 +5,7 @@ namespace Tests\E2E\Services\Functions; use Appwrite\Functions\Specification; use Appwrite\Tests\Retry; use CURLFile; +use PHPUnit\Framework\ExpectationFailedException; use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; @@ -2435,17 +2436,31 @@ class FunctionsCustomServerTest extends Scope // Await Aggregation sleep(App::getEnv('_APP_USAGE_AGGREGATION_INTERVAL', 30)); - $response = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/usage', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] - ], $this->getHeaders()), [ - 'range' => '24h' - ]); + $tries = 0; + while (true) { + try { + $response = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/usage', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'] + ], $this->getHeaders()), [ + 'range' => '24h' + ]); - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(19, count($response['body'])); - $this->assertEquals('24h', $response['body']['range']); - $this->assertEquals(1, $response['body']['executionsTotal']); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(19, count($response['body'])); + $this->assertEquals('24h', $response['body']['range']); + $this->assertEquals(1, $response['body']['executionsTotal']); + + break; + } catch (ExpectationFailedException $th) { + if ($tries >= 5) { + throw $th; + } else { + $tries++; + sleep(5); + } + } + } // Cleanup : Delete function $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [