diff --git a/tests/e2e/Services/Project/ProtocolsBase.php b/tests/e2e/Services/Project/ProtocolsBase.php new file mode 100644 index 0000000000..01b06bceb4 --- /dev/null +++ b/tests/e2e/Services/Project/ProtocolsBase.php @@ -0,0 +1,189 @@ +updateProtocolStatus($protocol, false); + + $this->assertSame(200, $response['headers']['status-code']); + $this->assertNotEmpty($response['body']['$id']); + $this->assertSame(false, $response['body']['protocolStatusFor' . ucfirst($protocol)]); + } + + // Cleanup + foreach (self::$protocols as $protocol) { + $this->updateProtocolStatus($protocol, true); + } + } + + public function testEnableProtocol(): void + { + // Disable first + foreach (self::$protocols as $protocol) { + $this->updateProtocolStatus($protocol, false); + } + + // Re-enable + foreach (self::$protocols as $protocol) { + $response = $this->updateProtocolStatus($protocol, true); + + $this->assertSame(200, $response['headers']['status-code']); + $this->assertNotEmpty($response['body']['$id']); + $this->assertSame(true, $response['body']['protocolStatusFor' . ucfirst($protocol)]); + } + } + + public function testDisableProtocolIdempotent(): void + { + $first = $this->updateProtocolStatus('rest', false); + $this->assertSame(200, $first['headers']['status-code']); + $this->assertSame(false, $first['body']['protocolStatusForRest']); + + $second = $this->updateProtocolStatus('rest', false); + $this->assertSame(200, $second['headers']['status-code']); + $this->assertSame(false, $second['body']['protocolStatusForRest']); + + // Cleanup + $this->updateProtocolStatus('rest', true); + } + + public function testEnableProtocolIdempotent(): void + { + $first = $this->updateProtocolStatus('rest', true); + $this->assertSame(200, $first['headers']['status-code']); + $this->assertSame(true, $first['body']['protocolStatusForRest']); + + $second = $this->updateProtocolStatus('rest', true); + $this->assertSame(200, $second['headers']['status-code']); + $this->assertSame(true, $second['body']['protocolStatusForRest']); + } + + public function testDisabledRestBlocksClientRequest(): void + { + $this->updateProtocolStatus('rest', false); + + $response = $this->client->call(Client::METHOD_GET, '/teams', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ]); + + $this->assertSame(403, $response['headers']['status-code']); + $this->assertSame('general_api_disabled', $response['body']['type']); + + // Cleanup + $this->updateProtocolStatus('rest', true); + } + + public function testEnabledRestAllowsClientRequest(): void + { + $this->updateProtocolStatus('rest', false); + $this->updateProtocolStatus('rest', true); + + $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertSame(200, $response['headers']['status-code']); + } + + public function testDisabledGraphqlBlocksClientRequest(): void + { + $this->updateProtocolStatus('graphql', false); + + $response = $this->client->call(Client::METHOD_POST, '/graphql', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], [ + 'query' => '{ localeListCountries { total } }', + ]); + + $this->assertSame(403, $response['headers']['status-code']); + $this->assertSame('general_api_disabled', $response['body']['type']); + + // Cleanup + $this->updateProtocolStatus('graphql', true); + } + + public function testDisableOneProtocolDoesNotAffectOther(): void + { + $this->updateProtocolStatus('graphql', false); + + // REST should still work + $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertSame(200, $response['headers']['status-code']); + + // Cleanup + $this->updateProtocolStatus('graphql', true); + } + + public function testResponseModel(): void + { + $response = $this->updateProtocolStatus('rest', false); + + $this->assertSame(200, $response['headers']['status-code']); + $this->assertArrayHasKey('$id', $response['body']); + $this->assertArrayHasKey('name', $response['body']); + $this->assertArrayHasKey('protocolStatusForRest', $response['body']); + $this->assertArrayHasKey('protocolStatusForGraphql', $response['body']); + $this->assertArrayHasKey('protocolStatusForWebsocket', $response['body']); + + // Cleanup + $this->updateProtocolStatus('rest', true); + } + + // Failure flow + + public function testUpdateProtocolWithoutAuthentication(): void + { + $response = $this->updateProtocolStatus('rest', false, false); + + $this->assertSame(401, $response['headers']['status-code']); + } + + public function testUpdateProtocolInvalidProtocolId(): void + { + $response = $this->updateProtocolStatus('invalid', false); + + $this->assertSame(400, $response['headers']['status-code']); + } + + public function testUpdateProtocolEmptyProtocolId(): void + { + $response = $this->updateProtocolStatus('', false); + + $this->assertSame(400, $response['headers']['status-code']); + } + + // Helpers + + protected function updateProtocolStatus(string $protocolId, bool $enabled, bool $authenticated = true): mixed + { + $headers = [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ]; + + if ($authenticated) { + $headers = array_merge($headers, $this->getHeaders()); + } + + return $this->client->call(Client::METHOD_PUT, '/project/protocols/' . $protocolId . '/status', $headers, [ + 'enabled' => $enabled, + ]); + } +} diff --git a/tests/e2e/Services/Project/ProtocolsConsoleClientTest.php b/tests/e2e/Services/Project/ProtocolsConsoleClientTest.php new file mode 100644 index 0000000000..b2cec9a438 --- /dev/null +++ b/tests/e2e/Services/Project/ProtocolsConsoleClientTest.php @@ -0,0 +1,14 @@ +updateServiceStatus($service, false); + + $this->assertSame(200, $response['headers']['status-code']); + $this->assertNotEmpty($response['body']['$id']); + $this->assertSame(false, $response['body']['serviceStatusFor' . ucfirst($service)]); + } + + // Cleanup + foreach (self::$optionalServices as $service) { + $this->updateServiceStatus($service, true); + } + } + + public function testEnableService(): void + { + // Disable first + foreach (self::$optionalServices as $service) { + $this->updateServiceStatus($service, false); + } + + // Re-enable + foreach (self::$optionalServices as $service) { + $response = $this->updateServiceStatus($service, true); + + $this->assertSame(200, $response['headers']['status-code']); + $this->assertNotEmpty($response['body']['$id']); + $this->assertSame(true, $response['body']['serviceStatusFor' . ucfirst($service)]); + } + } + + public function testDisableServiceIdempotent(): void + { + $first = $this->updateServiceStatus('teams', false); + $this->assertSame(200, $first['headers']['status-code']); + $this->assertSame(false, $first['body']['serviceStatusForTeams']); + + $second = $this->updateServiceStatus('teams', false); + $this->assertSame(200, $second['headers']['status-code']); + $this->assertSame(false, $second['body']['serviceStatusForTeams']); + + // Cleanup + $this->updateServiceStatus('teams', true); + } + + public function testEnableServiceIdempotent(): void + { + $first = $this->updateServiceStatus('teams', true); + $this->assertSame(200, $first['headers']['status-code']); + $this->assertSame(true, $first['body']['serviceStatusForTeams']); + + $second = $this->updateServiceStatus('teams', true); + $this->assertSame(200, $second['headers']['status-code']); + $this->assertSame(true, $second['body']['serviceStatusForTeams']); + } + + public function testDisabledServiceBlocksClientRequest(): void + { + $this->updateServiceStatus('teams', false); + + $response = $this->client->call(Client::METHOD_GET, '/teams', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ]); + + $this->assertSame(403, $response['headers']['status-code']); + $this->assertSame('general_service_disabled', $response['body']['type']); + + // Cleanup + $this->updateServiceStatus('teams', true); + } + + public function testEnabledServiceAllowsClientRequest(): void + { + $this->updateServiceStatus('teams', false); + $this->updateServiceStatus('teams', true); + + $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertSame(200, $response['headers']['status-code']); + } + + public function testDisableOneServiceDoesNotAffectOther(): void + { + $this->updateServiceStatus('teams', false); + + $response = $this->client->call(Client::METHOD_GET, '/functions', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertSame(200, $response['headers']['status-code']); + + // Cleanup + $this->updateServiceStatus('teams', true); + } + + public function testResponseModel(): void + { + $response = $this->updateServiceStatus('teams', false); + + $this->assertSame(200, $response['headers']['status-code']); + $this->assertArrayHasKey('$id', $response['body']); + $this->assertArrayHasKey('name', $response['body']); + $this->assertArrayHasKey('serviceStatusForTeams', $response['body']); + + // Cleanup + $this->updateServiceStatus('teams', true); + } + + // Failure flow + + public function testUpdateServiceWithoutAuthentication(): void + { + $response = $this->updateServiceStatus('teams', false, false); + + $this->assertSame(401, $response['headers']['status-code']); + } + + public function testUpdateServiceInvalidServiceId(): void + { + $response = $this->updateServiceStatus('invalid', false); + + $this->assertSame(400, $response['headers']['status-code']); + } + + public function testUpdateServiceEmptyServiceId(): void + { + $response = $this->updateServiceStatus('', false); + + $this->assertSame(400, $response['headers']['status-code']); + } + + // Helpers + + protected function updateServiceStatus(string $serviceId, bool $enabled, bool $authenticated = true): mixed + { + $headers = [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ]; + + if ($authenticated) { + $headers = array_merge($headers, $this->getHeaders()); + } + + return $this->client->call(Client::METHOD_PUT, '/project/services/' . $serviceId . '/status', $headers, [ + 'enabled' => $enabled, + ]); + } +} diff --git a/tests/e2e/Services/Project/ServicesConsoleClientTest.php b/tests/e2e/Services/Project/ServicesConsoleClientTest.php new file mode 100644 index 0000000000..b5660607f4 --- /dev/null +++ b/tests/e2e/Services/Project/ServicesConsoleClientTest.php @@ -0,0 +1,14 @@ +