diff --git a/tests/e2e/Services/GraphQL/GraphQLBase.php b/tests/e2e/Services/GraphQL/GraphQLBase.php index 8f24e41099..1b6f5828a0 100644 --- a/tests/e2e/Services/GraphQL/GraphQLBase.php +++ b/tests/e2e/Services/GraphQL/GraphQLBase.php @@ -3,28 +3,291 @@ namespace Tests\E2E\Services\GraphQL; use Tests\E2E\Client; -use Tests\E2E\Scopes\ProjectCustom; -use Tests\E2E\Scopes\Scope; -use Tests\E2E\Scopes\SideClient; -use Tests\E2E\Scopes\SideServer; -class GraphQLBase extends Scope +trait GraphQLBase { - use ProjectCustom; - use SideServer; + + static $CREATE_COLLECTION = "create_collection"; + static $CREATE_DOCUMENT = "create_document"; + static $LIST_DOCUMENTS = "list_documents"; + static $GET_DOCUMENT = "get_document"; + static $UPDATE_DOCUMENT = "update_document"; + static $CREATE_USER = "create_user"; + static $LIST_COUNTRIES = "list_countries"; + static $CREATE_KEY = "create_key"; + static $CREATE_ACCOUNT = "create_account"; + static $CREATE_ACCOUNT_SESSION = "create_account_session"; + + /** + * @var array + */ + protected static $project = []; + + /** + * @return array + */ + public function getProject(): array + { + if (!empty(self::$project)) { + return self::$project; + } + + $team = $this->client->call(Client::METHOD_POST, '/teams', [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'x-appwrite-project' => 'console', + ], [ + 'name' => 'Demo Project Team', + ]); + + $this->assertEquals(201, $team['headers']['status-code']); + $this->assertEquals('Demo Project Team', $team['body']['name']); + $this->assertNotEmpty($team['body']['$id']); + + $project = $this->client->call(Client::METHOD_POST, '/projects', [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + 'x-appwrite-project' => 'console', + ], [ + 'name' => 'Demo Project', + 'teamId' => $team['body']['$id'], + 'description' => 'Demo Project Description', + 'logo' => '', + 'url' => 'https://appwrite.io', + 'legalName' => '', + 'legalCountry' => '', + 'legalState' => '', + 'legalCity' => '', + 'legalAddress' => '', + 'legalTaxId' => '', + ]); + + $this->assertEquals(201, $project['headers']['status-code']); + $this->assertNotEmpty($project['body']); + + self::$project = [ + '$id' => $project['body']['$id'], + 'name' => $project['body']['name'] + ]; + + return self::$project; + } + + public function testCreateCollection(): array { + $projectId = $this->getProject()['$id']; + $key = ''; + $query = $this->getQuery(self::$CREATE_COLLECTION); + + $actorsVariables = [ + 'name' => 'Actors', + 'read' => ['*'], + 'write' => ['role:member', 'role:admin'], + 'rules' => [ + [ + 'label' => 'First Name', + 'key' => 'firstName', + 'type' => 'text', + 'default' => '', + 'required' => true, + 'array' => false + ], + [ + 'label' => 'Last Name', + 'key' => 'lastName', + 'type' => 'text', + 'default' => '', + 'required' => true, + 'array' => false + ], + ], + ]; + + $graphQLPayload = [ + "query" => $query, + "variables" => $actorsVariables + ]; + + $actors = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + 'x-appwrite-key' => $key + ]), $graphQLPayload); + + $errorMessage = "User (role: guest) missing scope (collections.write)"; + $this->assertEquals($actors['headers']['status-code'], 401); + $this->assertEquals($actors['body']['errors'][0]['message'], $errorMessage); + $this->assertIsArray($actors['body']['data']); + $this->assertNull($actors['body']['data']['database_createCollection']); + + $key = $this->createKey('test', ['collections.write']); + $actors = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + 'x-appwrite-key' => $key + ]), $graphQLPayload); + + $this->assertEquals($actors['headers']['status-code'], 201); + $this->assertNull($actors['body']['errors']); + $this->assertIsArray($actors['body']['data']); + $this->assertIsArray($actors['body']['data']['database_createCollection']); + + $data = $actors['body']['data']['database_createCollection']; + $this->assertArrayHasKey('id', $data); + $this->assertArrayHasKey('permissions', $data); + $this->assertEquals('Actors', $data['name']); + $this->assertArrayHasKey('dateCreated', $data); + $this->assertArrayHasKey('dateUpdated', $data); + $this->assertArrayHasKey('rules', $data); + + $permissions = $data['permissions']; + $this->assertIsArray($permissions); + $this->assertArrayHasKey('read', $permissions); + $this->assertArrayHasKey('write', $permissions); + $read = $permissions['read']; + $this->assertContains('*', $read); + $write = $permissions['write']; + $this->assertContains('role:member', $write); + $this->assertContains('role:admin', $write); + + $rules = $data['rules']; + $this->assertIsArray($rules); + $this->assertCount(2, $rules); + $firstRule = $rules[0]; + $this->assertArrayHasKey('id', $firstRule); + $this->assertEquals('rules', $firstRule['collection']); + $this->assertEquals('text', $firstRule['type']); + $this->assertEquals('firstName', $firstRule['key']); + $this->assertEquals('First Name', $firstRule['label']); + $this->assertEquals('', $firstRule['default']); + $this->assertEquals(false, $firstRule['array']); + $this->assertEquals(true, $firstRule['required']); + $this->assertEquals([], $firstRule['list']); + $secondRule = $rules[1]; + $this->assertArrayHasKey('id', $secondRule); + $this->assertEquals('rules', $secondRule['collection']); + $this->assertEquals('text', $secondRule['type']); + $this->assertEquals('lastName', $secondRule['key']); + $this->assertEquals('Last Name', $secondRule['label']); + $this->assertEquals('', $secondRule['default']); + $this->assertEquals(false, $secondRule['array']); + $this->assertEquals(true, $secondRule['required']); + $this->assertEquals([], $secondRule['list']); + + // $moviesVariables = [ + // 'name' => 'Movies', + // 'read' => ['*'], + // 'write' => ['role:member', 'role:admin'], + // 'rules' => [ + // [ + // 'label' => 'Name', + // 'key' => 'name', + // 'type' => 'text', + // 'default' => '', + // 'required' => true, + // 'array' => false + // ], + // [ + // 'label' => 'Release Year', + // 'key' => 'releaseYear', + // 'type' => 'numeric', + // 'default' => 0, + // 'required' => false, + // 'array' => false + // ], + // [ + // 'label' => 'Actors', + // 'key' => 'actors', + // 'type' => 'document', + // 'default' => [], + // 'required' => false, + // 'array' => true, + // 'list' => [$data['id']], + // ], + // ], + // ]; + + // $graphQLPayload = [ + // "query" => $query, + // "variables" => $moviesVariables + // ]; + + // $movies = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ + // 'origin' => 'http://localhost', + // 'content-type' => 'application/json', + // 'x-appwrite-project' => $projectId, + // 'x-appwrite-key' => $key + // ]), $graphQLPayload); + + // $this->assertEquals($movies['headers']['status-code'], 201); + // $this->assertNull($movies['body']['errors']); + // $this->assertIsArray($movies['body']['data']); + // $this->assertIsArray($movies['body']['data']['database_createCollection']); + + // $data = $movies['body']['data']['database_createCollection']; + // $this->assertArrayHasKey('id', $data); + // $this->assertArrayHasKey('permissions', $data); + // $this->assertEquals('Movies', $data['name']); + // $this->assertArrayHasKey('dateCreated', $data); + // $this->assertArrayHasKey('dateUpdated', $data); + // $this->assertArrayHasKey('rules', $data); + + // $permissions = $data['permissions']; + // $this->assertIsArray($permissions); + // $this->assertArrayHasKey('read', $permissions); + // $this->assertArrayHasKey('write', $permissions); + // $read = $permissions['read']; + // $this->assertContains('*', $read); + // $write = $permissions['write']; + // $this->assertContains('role:member', $write); + // $this->assertContains('role:admin', $write); + + // $rules = $data['rules']; + // $this->assertIsArray($rules); + // $this->assertCount(3, $rules); + // $firstRule = $rules[0]; + // $this->assertArrayHasKey('id', $firstRule); + // $this->assertEquals('rules', $firstRule['collection']); + // $this->assertEquals('text', $firstRule['type']); + // $this->assertEquals('name', $firstRule['key']); + // $this->assertEquals('Name', $firstRule['label']); + // $this->assertEquals('', $firstRule['default']); + // $this->assertEquals(false, $firstRule['array']); + // $this->assertEquals(true, $firstRule['required']); + // $this->assertEquals([], $firstRule['list']); + // $secondRule = $rules[1]; + // $this->assertArrayHasKey('id', $secondRule); + // $this->assertEquals('rules', $secondRule['collection']); + // $this->assertEquals('numeric', $secondRule['type']); + // $this->assertEquals('releaseYear', $secondRule['key']); + // $this->assertEquals('Release Year', $secondRule['label']); + // $this->assertEquals(0, $secondRule['default']); + // $this->assertEquals(false, $secondRule['array']); + // $this->assertEquals(false, $secondRule['required']); + // $this->assertEquals([], $secondRule['list']); + // $thirdRule = $rules[2]; + // $this->assertArrayHasKey('id', $thirdRule); + // $this->assertEquals('rules', $thirdRule['collection']); + // $this->assertEquals('document', $thirdRule['type']); + // $this->assertEquals('actors', $thirdRule['key']); + // $this->assertEquals('Actors', $thirdRule['label']); + // $this->assertEquals([], $thirdRule['default']); + // $this->assertEquals(true, $thirdRule['array']); + // $this->assertEquals(false, $thirdRule['required']); + // $this->assertEquals([$actors['body']['data']['$id']], $thirdRule['list']); + + // return $data; + + return ['actorsId' => $data['id']]; + } + public function createKey(string $name, array $scopes): string { $projectId = $this->getProject()['$id']; - $query = " - mutation createKey(\$projectId: String!, \$name: String!, \$scopes: [Json]!){ - projects_createKey (projectId: \$projectId, name: \$name, scopes: \$scopes) { - id - name - scopes - secret - } - } - "; + $query = $this->getQuery(self::$CREATE_KEY); $variables = [ "projectId" => $projectId, @@ -51,5 +314,114 @@ class GraphQLBase extends Scope return $key['body']['data']['projects_createKey']['secret']; } + + public function getQuery(string $name): String{ + switch($name) { + case self::$CREATE_COLLECTION : + return "mutation createCollection(\$name: String!, \$read: [Json]!, \$write: [Json]!, \$rules: [Json]!){ + database_createCollection (name: \$name, read : \$read, write: \$write, rules: \$rules) { + id + permissions { + read + write + } + name + dateCreated + dateUpdated + rules { + id + collection + type + key + label + default + array + required + list + } + } + }"; + case self::$CREATE_DOCUMENT : + return "mutation createDocument(\$collectionId: String!, \$data: Json!, \$read: [Json]!, \$write: [Json]!){ + database_createDocument (collectionId: \$collectionId, data: \$data, read: \$read, write: \$write) + }"; + + case self::$LIST_DOCUMENTS : + return "query listDocuments(\$collectionId: String, \$filters: [Json]){ + database_listDocuments (collectionId: \$collectionId, filters: \$filters) { + sum + documents + } + }"; + + case self::$GET_DOCUMENT : + return "query getDocument(\$collectionId: String!, \$documentId: String!){ + database_getDocument (collectionId: \$collectionId, documentId: \$documentId) + }"; + + case self::$UPDATE_DOCUMENT: + return "mutation updateDocument(\$collectionId: String!, \$documentId: String!, \$data: Json!, \$read: [Json]!, \$write: [Json]!){ + database_updateDocument (collectionId: \$collectionId, documentId: \$documentId,data: \$data, read: \$read, write: \$write) + }"; + + case self::$CREATE_USER : + return "mutation createUser(\$email: String!, \$password: String!, \$name: String){ + users_create (email: \$email, password: \$password, name: \$name) { + id + name + registration + status + email + emailVerification + prefs + } + }"; + + case self::$LIST_COUNTRIES: + return "query listCountries { + locale_getCountries{ + sum + countries { + name + code + } + } + }"; + + case self::$CREATE_KEY : + return "mutation createKey(\$projectId: String!, \$name: String!, \$scopes: [Json]!){ + projects_createKey (projectId: \$projectId, name: \$name, scopes: \$scopes) { + id + name + scopes + secret + } + }"; + + case self::$CREATE_ACCOUNT : + return "mutation createAccount(\$email: String!, \$password: String!, \$name: String){ + account_create (email: \$email, password: \$password, name: \$name) { + id + name + registration + status + email + emailVerification + prefs + } + }"; + + case self::$CREATE_ACCOUNT_SESSION : + return "mutation createAccountSession(\$email: String!, \$password: String!){ + account_createSession (email: \$email, password: \$password) { + id + userId + expire + ip + current + } + }"; + } + } } \ No newline at end of file diff --git a/tests/e2e/Services/GraphQL/GraphQLClientTest.php b/tests/e2e/Services/GraphQL/GraphQLClientTest.php new file mode 100644 index 0000000000..01000c6b6d --- /dev/null +++ b/tests/e2e/Services/GraphQL/GraphQLClientTest.php @@ -0,0 +1,362 @@ +getProject()['$id']; + + /* + * Create First Account + */ + $query = $this->getQuery(self::$CREATE_ACCOUNT); + $variables = [ + "email" => "test1@test.com", + "password" => "testtest", + "name" => "test1" + ]; + $graphQLPayload = [ + "query" => $query, + "variables" => $variables + ]; + $account1 = $this->client->call(Client::METHOD_POST, '/graphql', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + ], $graphQLPayload); + + $this->assertEquals($account1['headers']['status-code'], 201); + $this->assertNull($account1['body']['errors']); + $this->assertIsArray($account1['body']['data']); + $this->assertIsArray($account1['body']['data']['account_create']); + $account1 = $account1['body']['data']['account_create']; + $this->assertEquals($variables['name'], $account1['name']); + $this->assertEquals($variables['email'], $account1['email']); + + /* + * Create First Account Session + */ + $query = $this->getQuery(self::$CREATE_ACCOUNT_SESSION); + $graphQLPayload = [ + "query" => $query, + "variables" => $variables + ]; + $session1 = $this->client->call(Client::METHOD_POST, '/graphql', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + ], $graphQLPayload); + $this->assertEquals($session1['headers']['status-code'], 201); + $this->assertNull($session1['body']['errors']); + $this->assertIsArray($session1['body']['data']); + $this->assertIsArray($session1['body']['data']['account_createSession']); + $session1Cookie = $this->client->parseCookie((string)$session1['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + + /* + * Create Second Account + */ + $query = $this->getQuery(self::$CREATE_ACCOUNT); + $variables = [ + "email" => "test2@test.com", + "password" => "testtest", + "name" => "test2" + ]; + $graphQLPayload = [ + "query" => $query, + "variables" => $variables + ]; + $account2 = $this->client->call(Client::METHOD_POST, '/graphql', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + ], $graphQLPayload); + + $this->assertEquals($account2['headers']['status-code'], 201); + $this->assertNull($account2['body']['errors']); + $this->assertIsArray($account2['body']['data']); + $this->assertIsArray($account2['body']['data']['account_create']); + $account2 = $account2['body']['data']['account_create']; + $this->assertEquals($variables['name'], $account2['name']); + $this->assertEquals($variables['email'], $account2['email']); + + /* + * Create Second Account Session + */ + $query = $this->getQuery(self::$CREATE_ACCOUNT_SESSION); + $graphQLPayload = [ + "query" => $query, + "variables" => $variables + ]; + $session2 = $this->client->call(Client::METHOD_POST, '/graphql', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + ], $graphQLPayload); + $this->assertEquals($session2['headers']['status-code'], 201); + $this->assertNull($session2['body']['errors']); + $this->assertIsArray($session2['body']['data']); + $this->assertIsArray($session2['body']['data']['account_createSession']); + $session2Cookie = $this->client->parseCookie((string)$session2['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']]; + + return [ + "session1Cookie" => $session1Cookie, + "user1Id" => $session1['body']['data']['account_createSession']['userId'], + "session2Cookie" => $session2Cookie, + "user2Id" => $session2['body']['data']['account_createSession']['userId'], + ]; + } + + /** + * @depends testCreateCollection + * @depends testCreateAccounts + */ + public function testWildCardPermissions(array $collections, array $accounts) { + $projectId = $this->getProject()['$id']; + /* + * Account 1 Creates a document with wildcard permissions + */ + $query = $this->getQuery(self::$CREATE_DOCUMENT); + $createDocumentVariables = [ + 'collectionId' => $collections['actorsId'], + 'data' => [ + 'firstName' => 'Robert', + 'lastName' => "Downey" + ], + 'read' => ['*'], + 'write' => ['*'], + ]; + $graphQLPayload = [ + "query" => $query, + "variables" => $createDocumentVariables + ]; + $document = $this->client->call(Client::METHOD_POST, '/graphql', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $accounts['session1Cookie'], + ], $graphQLPayload); + + $this->assertEquals($document['headers']['status-code'], 201); + $this->assertNull($document['body']['errors']); + $this->assertIsArray($document['body']['data']); + $this->assertIsArray($document['body']['data']['database_createDocument']); + $doc = $document['body']['data']['database_createDocument']; + $this->assertArrayHasKey('$id', $doc); + $this->assertEquals($collections['actorsId'], $doc['$collection']); + $this->assertEquals('Robert', $doc['firstName']); + $this->assertEquals('Downey', $doc['lastName']); + $permissions = $doc['$permissions']; + $this->assertEquals($createDocumentVariables['read'], $permissions['read']); + $this->assertEquals($createDocumentVariables['write'], $permissions['write']); + + /* + * Account 1 tries to access it + */ + $query = $this->getQuery(self::$GET_DOCUMENT); + $getDocumentVariables = [ + 'collectionId' => $collections['actorsId'], + 'documentId' => $doc['$id'] + ]; + $graphQLPayload = [ + "query" => $query, + "variables" => $getDocumentVariables + ]; + $document = $this->client->call(Client::METHOD_POST, '/graphql', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $accounts['session1Cookie'], + ], $graphQLPayload); + + $this->assertEquals($document['headers']['status-code'], 200); + $this->assertNull($document['body']['errors']); + $this->assertIsArray($document['body']['data']); + $this->assertIsArray($document['body']['data']['database_getDocument']); + $doc = $document['body']['data']['database_getDocument']; + $this->assertArrayHasKey('$id', $doc); + $this->assertEquals($collections['actorsId'], $doc['$collection']); + $this->assertEquals('Robert', $doc['firstName']); + $this->assertEquals('Downey', $doc['lastName']); + $permissions = $doc['$permissions']; + $this->assertEquals($createDocumentVariables['read'], $permissions['read']); + $this->assertEquals($createDocumentVariables['write'], $permissions['write']); + + /* + * Account 2 tries to access it + */ + $document = $this->client->call(Client::METHOD_POST, '/graphql', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $accounts['session2Cookie'], + ], $graphQLPayload); + $this->assertEquals($document['headers']['status-code'], 200); + $this->assertNull($document['body']['errors']); + $this->assertIsArray($document['body']['data']); + $this->assertIsArray($document['body']['data']['database_getDocument']); + $doc = $document['body']['data']['database_getDocument']; + $this->assertArrayHasKey('$id', $doc); + $this->assertEquals($collections['actorsId'], $doc['$collection']); + $this->assertEquals('Robert', $doc['firstName']); + $this->assertEquals('Downey', $doc['lastName']); + $permissions = $doc['$permissions']; + $this->assertEquals($createDocumentVariables['read'], $permissions['read']); + $this->assertEquals($createDocumentVariables['write'], $permissions['write']); + } + + + /** + * @depends testCreateCollection + * @depends testCreateAccounts + */ + public function testUserRole(array $collections, array $accounts) { + $projectId = $this->getProject()['$id']; + /* + * Account 1 Creates a document with user permissions + */ + $query = $this->getQuery(self::$CREATE_DOCUMENT); + $createDocumentVariables = [ + 'collectionId' => $collections['actorsId'], + 'data' => [ + 'firstName' => 'Robert', + 'lastName' => "Downey" + ], + 'read' => ["user:{$accounts['user1Id']}"], + 'write' => ["user:{$accounts['user1Id']}"], + ]; + $graphQLPayload = [ + "query" => $query, + "variables" => $createDocumentVariables + ]; + $document = $this->client->call(Client::METHOD_POST, '/graphql', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $accounts['session1Cookie'], + ], $graphQLPayload); + + $this->assertEquals($document['headers']['status-code'], 201); + $this->assertNull($document['body']['errors']); + $this->assertIsArray($document['body']['data']); + $this->assertIsArray($document['body']['data']['database_createDocument']); + $doc = $document['body']['data']['database_createDocument']; + $this->assertArrayHasKey('$id', $doc); + $this->assertEquals($collections['actorsId'], $doc['$collection']); + $this->assertEquals($createDocumentVariables['data']['firstName'], $doc['firstName']); + $this->assertEquals($createDocumentVariables['data']['lastName'], $doc['lastName']); + $permissions = $doc['$permissions']; + $this->assertEquals($createDocumentVariables['read'], $permissions['read']); + $this->assertEquals($createDocumentVariables['write'], $permissions['write']); + + /* + * Account 1 tries to access it + */ + $query = $this->getQuery(self::$GET_DOCUMENT); + $getDocumentVariables = [ + 'collectionId' => $collections['actorsId'], + 'documentId' => $doc['$id'] + ]; + $graphQLPayload = [ + "query" => $query, + "variables" => $getDocumentVariables + ]; + $document = $this->client->call(Client::METHOD_POST, '/graphql', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $accounts['session1Cookie'], + ], $graphQLPayload); + + $this->assertEquals($document['headers']['status-code'], 200); + $this->assertNull($document['body']['errors']); + $this->assertIsArray($document['body']['data']); + $this->assertIsArray($document['body']['data']['database_getDocument']); + $doc = $document['body']['data']['database_getDocument']; + $this->assertArrayHasKey('$id', $doc); + $this->assertEquals($collections['actorsId'], $doc['$collection']); + $this->assertEquals($createDocumentVariables['data']['firstName'], $doc['firstName']); + $this->assertEquals($createDocumentVariables['data']['lastName'], $doc['lastName']); + $permissions = $doc['$permissions']; + $this->assertEquals($createDocumentVariables['read'], $permissions['read']); + $this->assertEquals($createDocumentVariables['write'], $permissions['write']); + + /* + * Account 2 tries to access it + */ + $document = $this->client->call(Client::METHOD_POST, '/graphql', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $accounts['session2Cookie'], + ], $graphQLPayload); + + $this->assertEquals($document['headers']['status-code'], 404); + $this->assertEquals($document['body']['errors'][0]['message'], "No document found"); + + /* + * Account 1 Updates the document permissions + */ + $query = $this->getQuery(self::$UPDATE_DOCUMENT); + $updateDocumentVariables = [ + 'collectionId' => $collections['actorsId'], + 'documentId' => $doc['$id'], + 'data' => [], + 'read' => ['*'], + 'write' => ['*'] + ]; + $graphQLPayload = [ + "query" => $query, + "variables" => $updateDocumentVariables + ]; + $document = $this->client->call(Client::METHOD_POST, '/graphql', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $accounts['session1Cookie'], + ], $graphQLPayload); + + $this->assertEquals($document['headers']['status-code'], 200); + $this->assertNull($document['body']['errors']); + $this->assertIsArray($document['body']['data']); + $this->assertIsArray($document['body']['data']['database_updateDocument']); + $doc = $document['body']['data']['database_updateDocument']; + $this->assertArrayHasKey('$id', $doc); + $this->assertEquals($collections['actorsId'], $doc['$collection']); + $this->assertEquals($createDocumentVariables['data']['firstName'], $doc['firstName']); + $this->assertEquals($createDocumentVariables['data']['lastName'], $doc['lastName']); + $permissions = $doc['$permissions']; + $this->assertEquals($updateDocumentVariables['read'], $permissions['read']); + $this->assertEquals($updateDocumentVariables['write'], $permissions['write']); + + /* + * Account 2 tries to access it + */ + $query = $this->getQuery(self::$GET_DOCUMENT); + $getDocumentVariables = [ + 'collectionId' => $collections['actorsId'], + 'documentId' => $doc['$id'] + ]; + $graphQLPayload = [ + "query" => $query, + "variables" => $getDocumentVariables + ]; + $document = $this->client->call(Client::METHOD_POST, '/graphql', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $accounts['session2Cookie'], + ], $graphQLPayload); + + $this->assertEquals($document['headers']['status-code'], 200); + $this->assertNull($document['body']['errors']); + $this->assertIsArray($document['body']['data']); + $this->assertIsArray($document['body']['data']['database_getDocument']); + $doc = $document['body']['data']['database_getDocument']; + $this->assertArrayHasKey('$id', $doc); + $this->assertEquals($collections['actorsId'], $doc['$collection']); + $this->assertEquals($createDocumentVariables['data']['firstName'], $doc['firstName']); + $this->assertEquals($createDocumentVariables['data']['lastName'], $doc['lastName']); + $permissions = $doc['$permissions']; + $this->assertEquals($updateDocumentVariables['read'], $permissions['read']); + $this->assertEquals($updateDocumentVariables['write'], $permissions['write']); + } + +} \ No newline at end of file diff --git a/tests/e2e/Services/GraphQL/GraphQLServerTest.php b/tests/e2e/Services/GraphQL/GraphQLServerTest.php index 1ba34e92b6..26f5f81580 100644 --- a/tests/e2e/Services/GraphQL/GraphQLServerTest.php +++ b/tests/e2e/Services/GraphQL/GraphQLServerTest.php @@ -3,7 +3,6 @@ namespace Tests\E2E\Services\GraphQL; use Tests\E2E\Client; -use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; @@ -11,240 +10,15 @@ use Tests\E2E\Scopes\SideServer; class GraphQLServerTest extends Scope { use SideServer; - use ProjectCustom; use GraphQLBase; - public function testCreateCollection(): array { - $projectId = $this->getProject()['$id']; - $key = $this->getProject()['apiKey']; - $query = " - mutation createCollection(\$name: String!, \$read: [Json]!, \$write: [Json]!, \$rules: [Json]!){ - database_createCollection (name: \$name, read : \$read, write: \$write, rules: \$rules) { - id - permissions { - read - write - } - name - dateCreated - dateUpdated - rules { - id - collection - type - key - label - default - array - required - list - } - } - } - "; - - $actorsVariables = [ - 'name' => 'Actors', - 'read' => ['*'], - 'write' => ['role:member', 'role:admin'], - 'rules' => [ - [ - 'label' => 'First Name', - 'key' => 'firstName', - 'type' => 'text', - 'default' => '', - 'required' => true, - 'array' => false - ], - [ - 'label' => 'Last Name', - 'key' => 'lastName', - 'type' => 'text', - 'default' => '', - 'required' => true, - 'array' => false - ], - ], - ]; - - $graphQLPayload = [ - "query" => $query, - "variables" => $actorsVariables - ]; - - $actors = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $projectId, - 'x-appwrite-key' => $key - ]), $graphQLPayload); - - - $this->assertEquals($actors['headers']['status-code'], 201); - $this->assertNull($actors['body']['errors']); - $this->assertIsArray($actors['body']['data']); - $this->assertIsArray($actors['body']['data']['database_createCollection']); - - $data = $actors['body']['data']['database_createCollection']; - $this->assertArrayHasKey('id', $data); - $this->assertArrayHasKey('permissions', $data); - $this->assertEquals('Actors', $data['name']); - $this->assertArrayHasKey('dateCreated', $data); - $this->assertArrayHasKey('dateUpdated', $data); - $this->assertArrayHasKey('rules', $data); - - $permissions = $data['permissions']; - $this->assertIsArray($permissions); - $this->assertArrayHasKey('read', $permissions); - $this->assertArrayHasKey('write', $permissions); - $read = $permissions['read']; - $this->assertContains('*', $read); - $write = $permissions['write']; - $this->assertContains('role:member', $write); - $this->assertContains('role:admin', $write); - - $rules = $data['rules']; - $this->assertIsArray($rules); - $this->assertCount(2, $rules); - $firstRule = $rules[0]; - $this->assertArrayHasKey('id', $firstRule); - $this->assertEquals('rules', $firstRule['collection']); - $this->assertEquals('text', $firstRule['type']); - $this->assertEquals('firstName', $firstRule['key']); - $this->assertEquals('First Name', $firstRule['label']); - $this->assertEquals('', $firstRule['default']); - $this->assertEquals(false, $firstRule['array']); - $this->assertEquals(true, $firstRule['required']); - $this->assertEquals([], $firstRule['list']); - $secondRule = $rules[1]; - $this->assertArrayHasKey('id', $secondRule); - $this->assertEquals('rules', $secondRule['collection']); - $this->assertEquals('text', $secondRule['type']); - $this->assertEquals('lastName', $secondRule['key']); - $this->assertEquals('Last Name', $secondRule['label']); - $this->assertEquals('', $secondRule['default']); - $this->assertEquals(false, $secondRule['array']); - $this->assertEquals(true, $secondRule['required']); - $this->assertEquals([], $secondRule['list']); - - // $moviesVariables = [ - // 'name' => 'Movies', - // 'read' => ['*'], - // 'write' => ['role:member', 'role:admin'], - // 'rules' => [ - // [ - // 'label' => 'Name', - // 'key' => 'name', - // 'type' => 'text', - // 'default' => '', - // 'required' => true, - // 'array' => false - // ], - // [ - // 'label' => 'Release Year', - // 'key' => 'releaseYear', - // 'type' => 'numeric', - // 'default' => 0, - // 'required' => false, - // 'array' => false - // ], - // [ - // 'label' => 'Actors', - // 'key' => 'actors', - // 'type' => 'document', - // 'default' => [], - // 'required' => false, - // 'array' => true, - // 'list' => [$data['id']], - // ], - // ], - // ]; - - // $graphQLPayload = [ - // "query" => $query, - // "variables" => $moviesVariables - // ]; - - // $movies = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ - // 'origin' => 'http://localhost', - // 'content-type' => 'application/json', - // 'x-appwrite-project' => $projectId, - // 'x-appwrite-key' => $key - // ]), $graphQLPayload); - - // $this->assertEquals($movies['headers']['status-code'], 201); - // $this->assertNull($movies['body']['errors']); - // $this->assertIsArray($movies['body']['data']); - // $this->assertIsArray($movies['body']['data']['database_createCollection']); - - // $data = $movies['body']['data']['database_createCollection']; - // $this->assertArrayHasKey('id', $data); - // $this->assertArrayHasKey('permissions', $data); - // $this->assertEquals('Movies', $data['name']); - // $this->assertArrayHasKey('dateCreated', $data); - // $this->assertArrayHasKey('dateUpdated', $data); - // $this->assertArrayHasKey('rules', $data); - - // $permissions = $data['permissions']; - // $this->assertIsArray($permissions); - // $this->assertArrayHasKey('read', $permissions); - // $this->assertArrayHasKey('write', $permissions); - // $read = $permissions['read']; - // $this->assertContains('*', $read); - // $write = $permissions['write']; - // $this->assertContains('role:member', $write); - // $this->assertContains('role:admin', $write); - - // $rules = $data['rules']; - // $this->assertIsArray($rules); - // $this->assertCount(3, $rules); - // $firstRule = $rules[0]; - // $this->assertArrayHasKey('id', $firstRule); - // $this->assertEquals('rules', $firstRule['collection']); - // $this->assertEquals('text', $firstRule['type']); - // $this->assertEquals('name', $firstRule['key']); - // $this->assertEquals('Name', $firstRule['label']); - // $this->assertEquals('', $firstRule['default']); - // $this->assertEquals(false, $firstRule['array']); - // $this->assertEquals(true, $firstRule['required']); - // $this->assertEquals([], $firstRule['list']); - // $secondRule = $rules[1]; - // $this->assertArrayHasKey('id', $secondRule); - // $this->assertEquals('rules', $secondRule['collection']); - // $this->assertEquals('numeric', $secondRule['type']); - // $this->assertEquals('releaseYear', $secondRule['key']); - // $this->assertEquals('Release Year', $secondRule['label']); - // $this->assertEquals(0, $secondRule['default']); - // $this->assertEquals(false, $secondRule['array']); - // $this->assertEquals(false, $secondRule['required']); - // $this->assertEquals([], $secondRule['list']); - // $thirdRule = $rules[2]; - // $this->assertArrayHasKey('id', $thirdRule); - // $this->assertEquals('rules', $thirdRule['collection']); - // $this->assertEquals('document', $thirdRule['type']); - // $this->assertEquals('actors', $thirdRule['key']); - // $this->assertEquals('Actors', $thirdRule['label']); - // $this->assertEquals([], $thirdRule['default']); - // $this->assertEquals(true, $thirdRule['array']); - // $this->assertEquals(false, $thirdRule['required']); - // $this->assertEquals([$actors['body']['data']['$id']], $thirdRule['list']); - - // return $data; - - return ['actorsId' => $data['id']]; - } - /** * @depends testCreateCollection */ public function testDocumentCreate(array $data) { $projectId = $this->getProject()['$id']; - $key = $this->getProject()['apiKey']; - $query = " - mutation createUser(\$collectionId: String!, \$data: Json!, \$read: [Json]!, \$write: [Json]!){ - database_createDocument (collectionId: \$collectionId, data: \$data, read: \$read, write: \$write) - } - "; + $key = ''; + $query = $this->getQuery(self::$CREATE_DOCUMENT); $variables = [ 'collectionId' => $data['actorsId'], @@ -267,7 +41,20 @@ class GraphQLServerTest extends Scope 'x-appwrite-key' => $key ], $graphQLPayload); + $errorMessage = "User (role: guest) missing scope (documents.write)"; + $this->assertEquals($document['headers']['status-code'], 401); + $this->assertEquals($document['body']['errors'][0]['message'], $errorMessage); + $this->assertIsArray($document['body']['data']); + $this->assertNull($document['body']['data']['database_createDocument']); + $key = $this->createKey('test', ['documents.write']); + $document = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + 'x-appwrite-key' => $key + ]), $graphQLPayload); + $this->assertEquals($document['headers']['status-code'], 201); $this->assertNull($document['body']['errors']); $this->assertIsArray($document['body']['data']); @@ -275,34 +62,17 @@ class GraphQLServerTest extends Scope $doc = $document['body']['data']['database_createDocument']; $this->assertArrayHasKey('$id', $doc); $this->assertEquals($data['actorsId'], $doc['$collection']); - $this->assertEquals('Robert', $doc['firstName']); - $this->assertEquals('Downey', $doc['lastName']); + $this->assertEquals($variables['data']['firstName'], $doc['firstName']); + $this->assertEquals($variables['data']['lastName'], $doc['lastName']); $permissions = $doc['$permissions']; - $this->assertIsArray($permissions); - $this->assertArrayHasKey('read', $permissions); - $this->assertArrayHasKey('write', $permissions); - $read = $permissions['read']; - $this->assertContains('*', $read); - $write = $permissions['write']; - $this->assertContains('*', $write); + $this->assertEquals($variables['read'], $permissions['read']); + $this->assertEquals($variables['write'], $permissions['write']); } public function testUserCreate() { $projectId = $this->getProject()['$id']; - $key = $this->getProject()['apiKey']; - $query = " - mutation createUser(\$email: String!, \$password: String!, \$name: String){ - users_create (email: \$email, password: \$password, name: \$name) { - id - name - registration - status - email - emailVerification - prefs - } - } - "; + $key = ''; + $query = $this->getQuery(self::$CREATE_USER); $variables = [ 'email' => 'users.service@example.com', @@ -321,16 +91,29 @@ class GraphQLServerTest extends Scope 'x-appwrite-key' => $key ], $graphQLPayload); + $errorMessage = "User (role: guest) missing scope (users.write)"; + $this->assertEquals($user['headers']['status-code'], 401); + $this->assertEquals($user['body']['errors'][0]['message'], $errorMessage); + $this->assertIsArray($user['body']['data']); + $this->assertNull($user['body']['data']['users_create']); + + $key = $this->createKey('test', ['users.write']); + $user = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + 'x-appwrite-key' => $key + ]), $graphQLPayload); + $this->assertEquals($user['headers']['status-code'], 201); $this->assertNull($user['body']['errors']); $this->assertIsArray($user['body']['data']); $this->assertIsArray($user['body']['data']['users_create']); - $data = $user['body']['data']['users_create']; $this->assertArrayHasKey('id', $data); $this->assertArrayHasKey('registration', $data); - $this->assertEquals('Project User', $data['name']); - $this->assertEquals('users.service@example.com', $data['email']); + $this->assertEquals($variables['name'], $data['name']); + $this->assertEquals($variables['email'], $data['email']); $this->assertEquals(0, $data['status']); $this->assertEquals(false, $data['emailVerification']); $this->assertEquals([], $data['prefs']); @@ -340,26 +123,14 @@ class GraphQLServerTest extends Scope public function testScopeBasedAuth() { $key = $this->createKey("test", ['locale.read']); $projectId = $this->getProject()['$id']; - // Check that locale can be fetched - $query = " - query listCountries { - locale_getCountries{ - sum - countries { - name - code - } - } - } - "; + // Check that locale can be fetched + $query = $this->getQuery(self::$LIST_COUNTRIES); $variables = []; - $graphQLPayload = [ "query" => $query, "variables" => $variables ]; - $countries = $this->client->call(Client::METHOD_POST, '/graphql', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, @@ -374,6 +145,7 @@ class GraphQLServerTest extends Scope $this->assertEquals(194, count($data['countries'])); $this->assertEquals(194, $data['sum']); + // Create a new key with no scopes granted $key = $this->createKey("test", []); $countries = $this->client->call(Client::METHOD_POST, '/graphql', [ @@ -387,7 +159,6 @@ class GraphQLServerTest extends Scope $this->assertEquals($countries['body']['errors'][0]['message'], $errorMessage); $this->assertIsArray($countries['body']['data']); $this->assertNull($countries['body']['data']['locale_getCountries']); - } } \ No newline at end of file