2020-01-13 18:30:13 +00:00
< ? php
namespace Tests\E2E\Services\Users ;
2022-09-06 04:13:24 +00:00
use Appwrite\Tests\Retry ;
2023-05-27 00:23:01 +00:00
use Appwrite\Utopia\Response ;
2026-01-15 03:14:53 +00:00
use PHPUnit\Framework\Attributes\DataProvider ;
2020-01-13 18:30:13 +00:00
use Tests\E2E\Client ;
2024-01-09 03:43:39 +00:00
use Utopia\Database\Document ;
2022-12-14 15:42:25 +00:00
use Utopia\Database\Helpers\ID ;
2024-01-09 03:43:39 +00:00
use Utopia\Database\Query ;
2020-01-13 18:30:13 +00:00
trait UsersBase
{
2026-02-05 22:54:14 +00:00
/**
* Static caches for test data
*/
private static array $cachedUser = [];
private static array $cachedHashedPasswordUsers = [];
private static array $cachedUserTarget = [];
private static bool $userNameUpdated = false ;
private static bool $userEmailUpdated = false ;
private static bool $userNumberUpdated = false ;
/**
* Helper to get or create a base test user
*/
protected function setupUser () : array
{
$projectId = $this -> getProject ()[ '$id' ];
if ( ! empty ( static :: $cachedUser [ $projectId ])) {
return static :: $cachedUser [ $projectId ];
}
$user = $this -> client -> call ( Client :: METHOD_POST , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $projectId ,
], $this -> getHeaders ()), [
'userId' => ID :: unique (),
'email' => 'cristiano.ronaldo@manchester-united.co.uk' ,
'password' => 'password' ,
'name' => 'Cristiano Ronaldo' ,
]);
if ( $user [ 'headers' ][ 'status-code' ] === 409 ) {
// User already exists, fetch by searching
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $projectId ,
], $this -> getHeaders ()), [
'search' => 'cristiano.ronaldo@manchester-united.co.uk' ,
]);
if ( ! empty ( $response [ 'body' ][ 'users' ])) {
static :: $cachedUser [ $projectId ] = [ 'userId' => $response [ 'body' ][ 'users' ][ 0 ][ '$id' ]];
return static :: $cachedUser [ $projectId ];
}
}
if ( $user [ 'headers' ][ 'status-code' ] === 201 ) {
2026-02-06 08:13:23 +00:00
static :: $cachedUser [ $projectId ] = [ 'userId' => $user [ 'body' ][ '$id' ]];
2026-02-05 22:54:14 +00:00
}
return static :: $cachedUser [ $projectId ];
}
/**
* Helper to create user1 ( Lionel Messi )
*/
protected function setupUser1 () : void
{
$projectId = $this -> getProject ()[ '$id' ];
$res = $this -> client -> call ( Client :: METHOD_POST , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $projectId ,
], $this -> getHeaders ()), [
'userId' => ID :: custom ( 'user1' ),
'email' => 'lionel.messi@psg.fr' ,
'password' => 'password' ,
'name' => 'Lionel Messi' ,
]);
// Ignore 409 conflict - user already exists
}
/**
* Helper to create all hashed password users for testing
*/
protected function setupHashedPasswordUsers () : void
{
$projectId = $this -> getProject ()[ '$id' ];
if ( ! empty ( static :: $cachedHashedPasswordUsers [ $projectId ])) {
return ;
}
// MD5 user
$this -> client -> call ( Client :: METHOD_POST , '/users/md5' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $projectId ,
], $this -> getHeaders ()), [
'userId' => 'md5' ,
'email' => 'md5@appwrite.io' ,
'password' => '144fa7eaa4904e8ee120651997f70dcc' , // appwrite
'name' => 'MD5 User' ,
]);
// Bcrypt user
$this -> client -> call ( Client :: METHOD_POST , '/users/bcrypt' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $projectId ,
], $this -> getHeaders ()), [
'userId' => 'bcrypt' ,
'email' => 'bcrypt@appwrite.io' ,
'password' => '$2a$15$xX/myGbFU.ZSKHSi6EHdBOySTdYm8QxBLXmOPHrYMwV0mHRBBSBOq' , // appwrite (15 rounds)
'name' => 'Bcrypt User' ,
]);
// Argon2 user
$this -> client -> call ( Client :: METHOD_POST , '/users/argon2' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $projectId ,
], $this -> getHeaders ()), [
'userId' => 'argon2' ,
'email' => 'argon2@appwrite.io' ,
'password' => '$argon2i$v=19$m=20,t=3,p=2$YXBwd3JpdGU$A/54i238ed09ZR4NwlACU5XnkjNBZU9QeOEuhjLiexI' , // appwrite (salt appwrite, parallel 2, memory 20, iterations 3, length 32)
'name' => 'Argon2 User' ,
]);
// SHA512 user
$this -> client -> call ( Client :: METHOD_POST , '/users/sha' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $projectId ,
], $this -> getHeaders ()), [
'userId' => 'sha512' ,
'email' => 'sha512@appwrite.io' ,
'password' => '4243da0a694e8a2f727c8060fe0507c8fa01ca68146c76d2c190805b638c20c6bf6ba04e21f11ae138785d0bff63c416e6f87badbffad37f6dee50094cc38c70' , // appwrite (sha512)
'name' => 'SHA512 User' ,
'passwordVersion' => 'sha512'
]);
// Scrypt user
$this -> client -> call ( Client :: METHOD_POST , '/users/scrypt' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $projectId ,
], $this -> getHeaders ()), [
'userId' => 'scrypt' ,
'email' => 'scrypt@appwrite.io' ,
'password' => '3fdef49701bc4cfaacd551fe017283513284b4731e6945c263246ef948d3cf63b5d269c31fd697246085111a428245e24a4ddc6b64c687bc60a8910dbafc1d5b' , // appwrite (salt appwrite, cpu 16384, memory 13, parallel 2, length 64)
'name' => 'Scrypt User' ,
'passwordSalt' => 'appwrite' ,
'passwordCpu' => 16384 ,
'passwordMemory' => 13 ,
'passwordParallel' => 2 ,
'passwordLength' => 64
]);
// PHPass user
$this -> client -> call ( Client :: METHOD_POST , '/users/phpass' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $projectId ,
], $this -> getHeaders ()), [
'userId' => 'phpass' ,
'email' => 'phpass@appwrite.io' ,
'password' => '$P$Br387rwferoKN7uwHZqNMu98q3U8RO.' ,
'name' => 'PHPass User' ,
]);
// Scrypt Modified user
$this -> client -> call ( Client :: METHOD_POST , '/users/scrypt-modified' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $projectId ,
], $this -> getHeaders ()), [
'userId' => 'scrypt-modified' ,
'email' => 'scrypt-modified@appwrite.io' ,
'password' => 'UlM7JiXRcQhzAGlaonpSqNSLIz475WMddOgLjej5De9vxTy48K6WtqlEzrRFeK4t0COfMhWCb8wuMHgxOFCHFQ==' , // appwrite
'name' => 'Scrypt Modified User' ,
'passwordSalt' => 'UxLMreBr6tYyjQ==' ,
'passwordSaltSeparator' => 'Bw==' ,
'passwordSignerKey' => 'XyEKE9RcTDeLEsL/RjwPDBv/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ==' ,
]);
static :: $cachedHashedPasswordUsers [ $projectId ] = true ;
}
/**
* Helper to create or get a user target
*/
protected function setupUserTarget () : array
{
$projectId = $this -> getProject ()[ '$id' ];
if ( ! empty ( static :: $cachedUserTarget [ $projectId ])) {
return static :: $cachedUserTarget [ $projectId ];
}
$data = $this -> setupUser ();
// Create provider
$provider = $this -> client -> call ( Client :: METHOD_POST , '/messaging/providers/sendgrid' , \array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $projectId ,
], $this -> getHeaders ()), [
'providerId' => ID :: unique (),
'name' => 'Sengrid1' ,
'apiKey' => 'my-apikey' ,
'from' => 'from@domain.com' ,
]);
if ( $provider [ 'headers' ][ 'status-code' ] !== 201 ) {
// Provider may already exist, try to find it
$providers = $this -> client -> call ( Client :: METHOD_GET , '/messaging/providers' , \array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $projectId ,
], $this -> getHeaders ()));
foreach ( $providers [ 'body' ][ 'providers' ] ? ? [] as $p ) {
if ( $p [ 'name' ] === 'Sengrid1' ) {
$provider = [ 'body' => $p ];
break ;
}
}
}
// Create target
$response = $this -> client -> call ( Client :: METHOD_POST , '/users/' . $data [ 'userId' ] . '/targets' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $projectId ,
], $this -> getHeaders ()), [
'targetId' => ID :: unique (),
'providerId' => $provider [ 'body' ][ '$id' ],
'providerType' => 'email' ,
'identifier' => 'random-email@mail.org' ,
]);
if ( $response [ 'headers' ][ 'status-code' ] === 201 ) {
static :: $cachedUserTarget [ $projectId ] = $response [ 'body' ];
}
return static :: $cachedUserTarget [ $projectId ] ? ? [];
}
/**
* Helper to ensure user name is updated ( for search tests )
*/
protected function ensureUserNameUpdated () : array
{
$data = $this -> setupUser ();
$projectId = $this -> getProject ()[ '$id' ];
if ( static :: $userNameUpdated ) {
return $data ;
}
$this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $data [ 'userId' ] . '/name' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $projectId ,
], $this -> getHeaders ()), [
'name' => 'Updated name' ,
]);
static :: $userNameUpdated = true ;
return $data ;
}
/**
* Helper to ensure user email is updated ( for search and password tests )
*/
protected function ensureUserEmailUpdated () : array
{
$data = $this -> setupUser ();
$projectId = $this -> getProject ()[ '$id' ];
if ( static :: $userEmailUpdated ) {
return $data ;
}
$this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $data [ 'userId' ] . '/email' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $projectId ,
], $this -> getHeaders ()), [
'email' => 'users.service@updated.com' ,
]);
static :: $userEmailUpdated = true ;
return $data ;
}
/**
* Helper to ensure user phone number is updated ( for search tests )
*/
protected function ensureUserNumberUpdated () : array
{
$data = $this -> setupUser ();
$projectId = $this -> getProject ()[ '$id' ];
if ( static :: $userNumberUpdated ) {
return $data ;
}
$this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $data [ 'userId' ] . '/phone' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $projectId ,
], $this -> getHeaders ()), [
'number' => '+910000000000' ,
]);
static :: $userNumberUpdated = true ;
return $data ;
}
public function testCreateUser () : void
2020-01-13 18:30:13 +00:00
{
/**
* Test for SUCCESS
*/
2020-01-13 18:55:57 +00:00
$user = $this -> client -> call ( Client :: METHOD_POST , '/users' , array_merge ([
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2020-01-13 18:55:57 +00:00
], $this -> getHeaders ()), [
2022-08-14 10:33:36 +00:00
'userId' => ID :: unique (),
2021-10-05 21:15:43 +00:00
'email' => 'cristiano.ronaldo@manchester-united.co.uk' ,
2020-01-13 18:55:57 +00:00
'password' => 'password' ,
2021-10-05 21:15:43 +00:00
'name' => 'Cristiano Ronaldo' ,
2021-12-30 08:09:23 +00:00
], false );
2023-11-28 13:12:34 +00:00
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 201 );
2021-12-30 08:09:23 +00:00
// Test empty prefs is object not array
$bodyString = $user [ 'body' ];
2022-05-23 14:54:50 +00:00
$prefs = substr ( $bodyString , strpos ( $bodyString , '"prefs":' ) + 8 , 2 );
2021-12-30 08:09:23 +00:00
$this -> assertEquals ( '{}' , $prefs );
2022-05-12 13:20:06 +00:00
2021-12-30 08:09:23 +00:00
$body = json_decode ( $bodyString , true );
2020-01-13 18:55:57 +00:00
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 201 );
2021-12-30 08:09:23 +00:00
$this -> assertEquals ( $body [ 'name' ], 'Cristiano Ronaldo' );
$this -> assertEquals ( $body [ 'email' ], 'cristiano.ronaldo@manchester-united.co.uk' );
$this -> assertEquals ( $body [ 'status' ], true );
2022-07-04 09:55:11 +00:00
$this -> assertGreaterThan ( '2000-01-01 00:00:00' , $body [ 'registration' ]);
2023-05-27 00:15:38 +00:00
$this -> assertEquals ( $body [ 'labels' ], []);
2020-01-13 18:55:57 +00:00
2021-07-05 11:03:52 +00:00
/**
* Test Create with Custom ID for SUCCESS
*/
$res = $this -> client -> call ( Client :: METHOD_POST , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2022-08-14 10:33:36 +00:00
'userId' => ID :: custom ( 'user1' ),
2021-10-05 21:15:43 +00:00
'email' => 'lionel.messi@psg.fr' ,
2021-07-05 11:03:52 +00:00
'password' => 'password' ,
2021-10-05 21:15:43 +00:00
'name' => 'Lionel Messi' ,
2021-07-05 11:03:52 +00:00
]);
$this -> assertEquals ( $res [ 'headers' ][ 'status-code' ], 201 );
$this -> assertEquals ( $res [ 'body' ][ '$id' ], 'user1' );
2021-10-05 21:15:43 +00:00
$this -> assertEquals ( $res [ 'body' ][ 'name' ], 'Lionel Messi' );
$this -> assertEquals ( $res [ 'body' ][ 'email' ], 'lionel.messi@psg.fr' );
2021-07-29 12:14:40 +00:00
$this -> assertEquals ( true , $res [ 'body' ][ 'status' ]);
2022-07-04 09:55:11 +00:00
$this -> assertGreaterThan ( '2000-01-01 00:00:00' , $res [ 'body' ][ 'registration' ]);
2021-07-05 11:03:52 +00:00
2022-12-18 06:27:41 +00:00
/**
2022-06-14 10:40:51 +00:00
* Test Create with hashed passwords
*/
2022-08-14 16:29:07 +00:00
$res = $this -> client -> call ( Client :: METHOD_POST , '/users/md5' , array_merge ([
2022-06-14 10:40:51 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2022-06-14 10:49:46 +00:00
'userId' => 'md5' ,
2022-06-14 10:40:51 +00:00
'email' => 'md5@appwrite.io' ,
'password' => '144fa7eaa4904e8ee120651997f70dcc' , // appwrite
'name' => 'MD5 User' ,
]);
2022-08-14 16:29:07 +00:00
$res = $this -> client -> call ( Client :: METHOD_POST , '/users/bcrypt' , array_merge ([
2022-06-14 10:40:51 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2022-06-14 10:49:46 +00:00
'userId' => 'bcrypt' ,
2022-06-14 10:40:51 +00:00
'email' => 'bcrypt@appwrite.io' ,
'password' => '$2a$15$xX/myGbFU.ZSKHSi6EHdBOySTdYm8QxBLXmOPHrYMwV0mHRBBSBOq' , // appwrite (15 rounds)
2022-06-17 09:25:28 +00:00
'name' => 'Bcrypt User' ,
2022-06-14 10:40:51 +00:00
]);
$this -> assertEquals ( $res [ 'headers' ][ 'status-code' ], 201 );
$this -> assertEquals ( $res [ 'body' ][ 'password' ], '$2a$15$xX/myGbFU.ZSKHSi6EHdBOySTdYm8QxBLXmOPHrYMwV0mHRBBSBOq' );
$this -> assertEquals ( $res [ 'body' ][ 'hash' ], 'bcrypt' );
2022-08-14 16:29:07 +00:00
$res = $this -> client -> call ( Client :: METHOD_POST , '/users/argon2' , array_merge ([
2022-06-14 10:40:51 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2022-06-14 10:49:46 +00:00
'userId' => 'argon2' ,
'email' => 'argon2@appwrite.io' ,
2022-06-14 10:40:51 +00:00
'password' => '$argon2i$v=19$m=20,t=3,p=2$YXBwd3JpdGU$A/54i238ed09ZR4NwlACU5XnkjNBZU9QeOEuhjLiexI' , // appwrite (salt appwrite, parallel 2, memory 20, iterations 3, length 32)
2022-06-14 10:49:46 +00:00
'name' => 'Argon2 User' ,
2022-06-14 10:40:51 +00:00
]);
$this -> assertEquals ( $res [ 'headers' ][ 'status-code' ], 201 );
$this -> assertEquals ( $res [ 'body' ][ 'password' ], '$argon2i$v=19$m=20,t=3,p=2$YXBwd3JpdGU$A/54i238ed09ZR4NwlACU5XnkjNBZU9QeOEuhjLiexI' );
$this -> assertEquals ( $res [ 'body' ][ 'hash' ], 'argon2' );
2022-08-14 16:29:07 +00:00
$res = $this -> client -> call ( Client :: METHOD_POST , '/users/sha' , array_merge ([
2022-06-14 10:40:51 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2022-06-14 10:49:46 +00:00
'userId' => 'sha512' ,
'email' => 'sha512@appwrite.io' ,
2022-06-14 10:40:51 +00:00
'password' => '4243da0a694e8a2f727c8060fe0507c8fa01ca68146c76d2c190805b638c20c6bf6ba04e21f11ae138785d0bff63c416e6f87badbffad37f6dee50094cc38c70' , // appwrite (sha512)
2022-06-14 10:49:46 +00:00
'name' => 'SHA512 User' ,
2022-06-14 10:40:51 +00:00
'passwordVersion' => 'sha512'
]);
$this -> assertEquals ( $res [ 'headers' ][ 'status-code' ], 201 );
$this -> assertEquals ( $res [ 'body' ][ 'password' ], '4243da0a694e8a2f727c8060fe0507c8fa01ca68146c76d2c190805b638c20c6bf6ba04e21f11ae138785d0bff63c416e6f87badbffad37f6dee50094cc38c70' );
$this -> assertEquals ( $res [ 'body' ][ 'hash' ], 'sha' );
$this -> assertEquals ( $res [ 'body' ][ 'hashOptions' ][ 'version' ], 'sha512' );
2022-08-14 16:29:07 +00:00
$res = $this -> client -> call ( Client :: METHOD_POST , '/users/scrypt' , array_merge ([
2022-06-14 10:40:51 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2022-06-14 10:49:46 +00:00
'userId' => 'scrypt' ,
2022-06-14 10:40:51 +00:00
'email' => 'scrypt@appwrite.io' ,
'password' => '3fdef49701bc4cfaacd551fe017283513284b4731e6945c263246ef948d3cf63b5d269c31fd697246085111a428245e24a4ddc6b64c687bc60a8910dbafc1d5b' , // appwrite (salt appwrite, cpu 16384, memory 13, parallel 2, length 64)
2022-06-17 09:25:28 +00:00
'name' => 'Scrypt User' ,
2022-06-14 10:40:51 +00:00
'passwordSalt' => 'appwrite' ,
'passwordCpu' => 16384 ,
'passwordMemory' => 13 ,
'passwordParallel' => 2 ,
'passwordLength' => 64
]);
$this -> assertEquals ( $res [ 'headers' ][ 'status-code' ], 201 );
$this -> assertEquals ( $res [ 'body' ][ 'password' ], '3fdef49701bc4cfaacd551fe017283513284b4731e6945c263246ef948d3cf63b5d269c31fd697246085111a428245e24a4ddc6b64c687bc60a8910dbafc1d5b' );
$this -> assertEquals ( $res [ 'body' ][ 'hash' ], 'scrypt' );
$this -> assertEquals ( $res [ 'body' ][ 'hashOptions' ][ 'salt' ], 'appwrite' );
2022-06-16 09:21:35 +00:00
$this -> assertEquals ( $res [ 'body' ][ 'hashOptions' ][ 'costCpu' ], 16384 );
$this -> assertEquals ( $res [ 'body' ][ 'hashOptions' ][ 'costMemory' ], 13 );
$this -> assertEquals ( $res [ 'body' ][ 'hashOptions' ][ 'costParallel' ], 2 );
2022-06-14 10:40:51 +00:00
$this -> assertEquals ( $res [ 'body' ][ 'hashOptions' ][ 'length' ], 64 );
2022-08-14 16:29:07 +00:00
$res = $this -> client -> call ( Client :: METHOD_POST , '/users/phpass' , array_merge ([
2022-06-14 10:40:51 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2022-06-14 10:49:46 +00:00
'userId' => 'phpass' ,
2022-06-14 10:40:51 +00:00
'email' => 'phpass@appwrite.io' ,
2022-06-22 08:00:12 +00:00
'password' => '$P$Br387rwferoKN7uwHZqNMu98q3U8RO.' ,
2022-06-14 10:40:51 +00:00
'name' => 'PHPass User' ,
]);
$this -> assertEquals ( $res [ 'headers' ][ 'status-code' ], 201 );
2022-06-22 08:00:12 +00:00
$this -> assertEquals ( $res [ 'body' ][ 'password' ], '$P$Br387rwferoKN7uwHZqNMu98q3U8RO.' );
2022-06-14 10:40:51 +00:00
2022-08-14 16:29:07 +00:00
$res = $this -> client -> call ( Client :: METHOD_POST , '/users/scrypt-modified' , array_merge ([
2022-06-14 10:40:51 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2022-06-14 10:49:46 +00:00
'userId' => 'scrypt-modified' ,
2022-06-14 10:40:51 +00:00
'email' => 'scrypt-modified@appwrite.io' ,
'password' => 'UlM7JiXRcQhzAGlaonpSqNSLIz475WMddOgLjej5De9vxTy48K6WtqlEzrRFeK4t0COfMhWCb8wuMHgxOFCHFQ==' , // appwrite
2022-06-17 09:25:28 +00:00
'name' => 'Scrypt Modified User' ,
2022-06-14 10:40:51 +00:00
'passwordSalt' => 'UxLMreBr6tYyjQ==' ,
'passwordSaltSeparator' => 'Bw==' ,
'passwordSignerKey' => 'XyEKE9RcTDeLEsL/RjwPDBv/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ==' ,
]);
$this -> assertEquals ( $res [ 'headers' ][ 'status-code' ], 201 );
$this -> assertEquals ( $res [ 'body' ][ 'password' ], 'UlM7JiXRcQhzAGlaonpSqNSLIz475WMddOgLjej5De9vxTy48K6WtqlEzrRFeK4t0COfMhWCb8wuMHgxOFCHFQ==' );
2022-06-16 09:21:35 +00:00
$this -> assertEquals ( $res [ 'body' ][ 'hash' ], 'scryptMod' );
2022-06-14 10:40:51 +00:00
$this -> assertEquals ( $res [ 'body' ][ 'hashOptions' ][ 'salt' ], 'UxLMreBr6tYyjQ==' );
2022-06-16 09:21:35 +00:00
$this -> assertEquals ( $res [ 'body' ][ 'hashOptions' ][ 'signerKey' ], 'XyEKE9RcTDeLEsL/RjwPDBv/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ==' );
$this -> assertEquals ( $res [ 'body' ][ 'hashOptions' ][ 'saltSeparator' ], 'Bw==' );
2022-06-14 10:40:51 +00:00
2026-02-05 22:54:14 +00:00
// Cache the user ID for other tests
$projectId = $this -> getProject ()[ '$id' ];
static :: $cachedUser [ $projectId ] = [ 'userId' => $body [ '$id' ]];
2020-01-13 18:55:57 +00:00
}
2022-06-14 10:49:46 +00:00
/**
* Tries to login into all accounts created with hashed password . Ensures hash veifying logic .
*/
2026-02-05 22:54:14 +00:00
public function testCreateUserSessionHashed () : void
2022-06-14 10:49:46 +00:00
{
2026-02-05 22:54:14 +00:00
$this -> setupHashedPasswordUsers ();
2022-12-18 06:27:41 +00:00
$userIds = [ 'md5' , 'bcrypt' , 'argon2' , 'sha512' , 'scrypt' , 'phpass' , 'scrypt-modified' ];
2022-09-19 08:43:59 +00:00
foreach ( $userIds as $userId ) {
// Ensure sessions can be created with hashed passwords
$response = $this -> client -> call ( Client :: METHOD_POST , '/account/sessions/email' , array_merge ([
'origin' => 'http://localhost' ,
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
]), [
'email' => $userId . '@appwrite.io' ,
'password' => 'appwrite' ,
]);
$this -> assertEquals ( 201 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $userId , $response [ 'body' ][ 'userId' ]);
}
foreach ( $userIds as $userId ) {
// Ensure all passwords were re-hashed
$response = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $userId , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), []);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $userId , $response [ 'body' ][ '$id' ]);
$this -> assertEquals ( $userId . '@appwrite.io' , $response [ 'body' ][ 'email' ]);
$this -> assertEquals ( 'argon2' , $response [ 'body' ][ 'hash' ]);
$this -> assertStringStartsWith ( '$argon2' , $response [ 'body' ][ 'password' ]);
}
foreach ( $userIds as $userId ) {
// Ensure sessions can be created after re-hashing of passwords
$response = $this -> client -> call ( Client :: METHOD_POST , '/account/sessions/email' , array_merge ([
'origin' => 'http://localhost' ,
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
]), [
'email' => $userId . '@appwrite.io' ,
'password' => 'appwrite' ,
]);
$this -> assertEquals ( 201 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $userId , $response [ 'body' ][ 'userId' ]);
}
2022-06-14 10:49:46 +00:00
}
2026-02-05 22:54:14 +00:00
public function testCreateToken () : void
2023-10-11 13:21:20 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> setupUser ();
2023-10-11 13:21:20 +00:00
/**
* Test for SUCCESS
*/
2023-11-30 11:35:52 +00:00
$token = $this -> client -> call ( Client :: METHOD_POST , '/users/' . $data [ 'userId' ] . '/tokens' , array_merge ([
2024-01-17 11:03:04 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( 201 , $token [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $data [ 'userId' ], $token [ 'body' ][ 'userId' ]);
$this -> assertNotEmpty ( $token [ 'body' ][ 'secret' ]);
$this -> assertNotEmpty ( $token [ 'body' ][ 'expire' ]);
$token = $this -> client -> call ( Client :: METHOD_POST , '/users/' . $data [ 'userId' ] . '/tokens' , array_merge ([
'content-type' => 'application/json' ,
2023-10-11 13:21:20 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-11-02 13:15:29 +00:00
], $this -> getHeaders ()), [
2024-01-17 11:03:04 +00:00
'length' => 15 ,
2023-11-02 13:15:29 +00:00
'expire' => 60 ,
]);
2023-10-11 13:21:20 +00:00
2023-10-23 10:32:09 +00:00
$this -> assertEquals ( 201 , $token [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $data [ 'userId' ], $token [ 'body' ][ 'userId' ]);
2024-01-17 11:03:04 +00:00
$this -> assertEquals ( 15 , strlen ( $token [ 'body' ][ 'secret' ]));
2023-10-11 13:21:20 +00:00
$this -> assertNotEmpty ( $token [ 'body' ][ 'expire' ]);
2024-01-17 11:03:04 +00:00
/**
* Test for FAILURE
*/
$token = $this -> client -> call ( Client :: METHOD_POST , '/users/' . $data [ 'userId' ] . '/tokens' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'length' => 1 ,
'expire' => 1 ,
]);
$this -> assertEquals ( 400 , $token [ 'headers' ][ 'status-code' ]);
$this -> assertArrayNotHasKey ( 'userId' , $token [ 'body' ]);
$this -> assertArrayNotHasKey ( 'secret' , $token [ 'body' ]);
$token = $this -> client -> call ( Client :: METHOD_POST , '/users/' . $data [ 'userId' ] . '/tokens' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'expire' => 999999999999999 ,
]);
$this -> assertEquals ( 400 , $token [ 'headers' ][ 'status-code' ]);
$this -> assertArrayNotHasKey ( 'userId' , $token [ 'body' ]);
$this -> assertArrayNotHasKey ( 'secret' , $token [ 'body' ]);
2023-10-11 13:21:20 +00:00
}
2026-02-05 22:54:14 +00:00
public function testCreateSession () : void
2024-06-21 22:25:27 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> setupUser ();
2024-06-21 22:25:27 +00:00
/**
* Test for SUCCESS
*/
$response = $this -> client -> call ( Client :: METHOD_POST , '/users/' . $data [ 'userId' ] . '/sessions' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( 201 , $response [ 'headers' ][ 'status-code' ]);
$session = $response [ 'body' ];
$this -> assertEquals ( $data [ 'userId' ], $session [ 'userId' ]);
$this -> assertNotEmpty ( $session [ 'secret' ]);
$this -> assertNotEmpty ( $session [ 'expire' ]);
$this -> assertEquals ( 'server' , $session [ 'provider' ]);
2024-11-22 21:52:27 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , '/account' , [
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-session' => $session [ 'secret' ]
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2025-01-11 17:56:36 +00:00
$response = $this -> client -> call ( Client :: METHOD_DELETE , '/account/sessions/current' , [
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-session' => $session [ 'secret' ]
]);
$this -> assertEquals ( 204 , $response [ 'headers' ][ 'status-code' ]);
2024-06-21 22:25:27 +00:00
}
2024-01-15 11:30:54 +00:00
2022-08-16 13:02:28 +00:00
/**
* Tests all optional parameters of createUser ( email , phone , anonymous .. )
*/
2026-02-05 22:54:14 +00:00
public function testCreateUserTypes () : void
2022-08-16 13:03:38 +00:00
{
2022-08-16 13:02:28 +00:00
/**
* Test for SUCCESS
2022-12-18 06:27:41 +00:00
*/
2022-08-16 13:02:28 +00:00
// Email + password
$response = $this -> client -> call ( Client :: METHOD_POST , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'userId' => 'unique()' ,
'email' => 'emailuser@appwrite.io' ,
'password' => 'emailUserPassword' ,
]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'email' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'password' ]);
$this -> assertEmpty ( $response [ 'body' ][ 'phone' ]);
// Phone
$response = $this -> client -> call ( Client :: METHOD_POST , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'userId' => 'unique()' ,
'phone' => '+123456789012' ,
]);
$this -> assertEmpty ( $response [ 'body' ][ 'email' ]);
$this -> assertEmpty ( $response [ 'body' ][ 'password' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'phone' ]);
// Anonymous
$response = $this -> client -> call ( Client :: METHOD_POST , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'userId' => 'unique()' ,
]);
2022-08-16 13:03:38 +00:00
2022-08-16 13:02:28 +00:00
$this -> assertEmpty ( $response [ 'body' ][ 'email' ]);
$this -> assertEmpty ( $response [ 'body' ][ 'password' ]);
$this -> assertEmpty ( $response [ 'body' ][ 'phone' ]);
// Email-only
$response = $this -> client -> call ( Client :: METHOD_POST , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'userId' => 'unique()' ,
'email' => 'emailonlyuser@appwrite.io' ,
]);
2022-08-16 13:03:38 +00:00
2022-08-16 13:02:28 +00:00
$this -> assertNotEmpty ( $response [ 'body' ][ 'email' ]);
$this -> assertEmpty ( $response [ 'body' ][ 'password' ]);
$this -> assertEmpty ( $response [ 'body' ][ 'phone' ]);
// Password-only
$response = $this -> client -> call ( Client :: METHOD_POST , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'userId' => 'unique()' ,
'password' => 'passwordOnlyUser' ,
]);
2022-08-16 13:03:38 +00:00
2022-08-16 13:02:28 +00:00
$this -> assertEmpty ( $response [ 'body' ][ 'email' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'password' ]);
$this -> assertEmpty ( $response [ 'body' ][ 'phone' ]);
// Password and phone
$response = $this -> client -> call ( Client :: METHOD_POST , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'userId' => 'unique()' ,
'password' => 'passwordOnlyUser' ,
'phone' => '+123456789013' ,
]);
2022-08-16 13:03:38 +00:00
2022-08-16 13:02:28 +00:00
$this -> assertEmpty ( $response [ 'body' ][ 'email' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'password' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'phone' ]);
}
2026-02-05 22:54:14 +00:00
public function testListUsers () : void
2021-08-09 12:55:30 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> setupUser ();
$this -> setupUser1 ();
$this -> setupHashedPasswordUsers ();
2026-02-06 07:53:42 +00:00
// In --functional mode, this test runs independently with 9 users created above
// (setupUser: 1 + setupUser1: 1 + setupHashedPasswordUsers: 7)
// In sequential mode, there may be more users from other tests
$minUsers = 9 ;
2022-08-16 13:02:28 +00:00
2021-08-09 12:55:30 +00:00
/**
2021-09-21 08:22:13 +00:00
* Test for SUCCESS listUsers
2021-08-09 12:55:30 +00:00
*/
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'users' ]);
2026-02-06 07:53:42 +00:00
$this -> assertGreaterThanOrEqual ( $minUsers , count ( $response [ 'body' ][ 'users' ]));
// Find our users by ID instead of assuming position
$userIds = array_column ( $response [ 'body' ][ 'users' ], '$id' );
$this -> assertContains ( $data [ 'userId' ], $userIds );
$this -> assertContains ( 'user1' , $userIds );
// Find user1 for later use in queries
$user1 = null ;
foreach ( $response [ 'body' ][ 'users' ] as $user ) {
if ( $user [ '$id' ] === 'user1' ) {
$user1 = $user ;
break ;
}
}
$this -> assertNotNull ( $user1 , 'user1 should exist in user list' );
2022-08-15 19:35:50 +00:00
2025-08-26 13:44:15 +00:00
// This test ensures that by default, endpoints dont support select queries
// If we add select query to this endpoint, you will need to remove this test
// Please make sure to add it to another place, unless all endpoints support select queries
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
Query :: select ([ 'name' ]) -> toString ()
]
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 400 );
2022-08-15 19:35:50 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
Query :: equal ( 'name' , [ $user1 [ 'name' ]]) -> toString ()
]
2022-08-15 19:35:50 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'users' ]);
$this -> assertCount ( 1 , $response [ 'body' ][ 'users' ]);
$this -> assertEquals ( $response [ 'body' ][ 'users' ][ 0 ][ 'name' ], $user1 [ 'name' ]);
2024-01-09 03:43:39 +00:00
2022-08-15 19:35:50 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
Query :: equal ( 'name' , [ $user1 [ 'name' ]]) -> toString ()
]
2022-08-15 19:35:50 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'users' ]);
$this -> assertCount ( 1 , $response [ 'body' ][ 'users' ]);
$this -> assertEquals ( $response [ 'body' ][ 'users' ][ 0 ][ 'email' ], $user1 [ 'email' ]);
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
Query :: equal ( 'status' , [ true ]) -> toString ()
]
2022-08-15 19:35:50 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'users' ]);
2026-02-06 08:22:14 +00:00
// In parallel mode, count may vary - just ensure our known users are present
$this -> assertGreaterThanOrEqual ( $minUsers , count ( $response [ 'body' ][ 'users' ]));
// Verify our test users are in the results by ID
$userIds = array_column ( $response [ 'body' ][ 'users' ], '$id' );
$this -> assertContains ( $data [ 'userId' ], $userIds );
$this -> assertContains ( 'user1' , $userIds );
2022-08-15 19:35:50 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
Query :: equal ( 'status' , [ false ]) -> toString ()
]
2022-08-15 19:35:50 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertEmpty ( $response [ 'body' ][ 'users' ]);
$this -> assertCount ( 0 , $response [ 'body' ][ 'users' ]);
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
Query :: equal ( 'passwordUpdate' , [ $user1 [ 'passwordUpdate' ]]) -> toString ()
]
2022-08-15 19:35:50 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'users' ]);
$this -> assertCount ( 1 , $response [ 'body' ][ 'users' ]);
$this -> assertEquals ( $response [ 'body' ][ 'users' ][ 0 ][ 'passwordUpdate' ], $user1 [ 'passwordUpdate' ]);
2021-08-09 12:55:30 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
Query :: equal ( 'registration' , [ $user1 [ 'registration' ]]) -> toString ()
]
2022-08-15 19:35:50 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'users' ]);
$this -> assertCount ( 1 , $response [ 'body' ][ 'users' ]);
$this -> assertEquals ( $response [ 'body' ][ 'users' ][ 0 ][ 'registration' ], $user1 [ 'registration' ]);
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
Query :: equal ( 'emailVerification' , [ false ]) -> toString ()
]
2022-08-15 19:35:50 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'users' ]);
2026-02-06 08:22:14 +00:00
// In parallel mode, count may vary - just ensure our known users are present
$this -> assertGreaterThanOrEqual ( $minUsers , count ( $response [ 'body' ][ 'users' ]));
// Verify our test users are in the results by ID
$userIds = array_column ( $response [ 'body' ][ 'users' ], '$id' );
$this -> assertContains ( $data [ 'userId' ], $userIds );
$this -> assertContains ( 'user1' , $userIds );
2022-08-15 19:35:50 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
Query :: equal ( 'emailVerification' , [ true ]) -> toString ()
]
2022-08-15 19:35:50 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertEmpty ( $response [ 'body' ][ 'users' ]);
$this -> assertCount ( 0 , $response [ 'body' ][ 'users' ]);
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
Query :: equal ( 'phoneVerification' , [ false ]) -> toString ()
]
2022-08-15 19:35:50 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
2022-08-19 21:09:50 +00:00
$this -> assertIsArray ( $response [ 'body' ][ 'users' ]);
2026-02-06 08:22:14 +00:00
$this -> assertGreaterThanOrEqual ( $minUsers , count ( $response [ 'body' ][ 'users' ]));
2022-08-15 19:35:50 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
Query :: equal ( 'phoneVerification' , [ true ]) -> toString ()
]
2022-08-15 19:35:50 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertEmpty ( $response [ 'body' ][ 'users' ]);
$this -> assertCount ( 0 , $response [ 'body' ][ 'users' ]);
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
Query :: cursorAfter ( new Document ([ '$id' => $data [ 'userId' ]])) -> toString ()
]
2021-08-09 12:55:30 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'users' ]);
2026-02-06 08:22:14 +00:00
// CursorAfter should return results, count varies in parallel mode
$this -> assertGreaterThanOrEqual ( 1 , count ( $response [ 'body' ][ 'users' ]));
// First result after cursor should be user1 (created right after setupUser)
2021-08-09 12:55:30 +00:00
$this -> assertEquals ( $response [ 'body' ][ 'users' ][ 0 ][ '$id' ], 'user1' );
2021-10-05 10:30:33 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
Query :: cursorBefore ( new Document ([ '$id' => 'user1' ])) -> toString ()
]
2021-10-05 10:30:33 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ][ 'users' ]);
$this -> assertCount ( 1 , $response [ 'body' ][ 'users' ]);
$this -> assertEquals ( $response [ 'body' ][ 'users' ][ 0 ][ '$id' ], $data [ 'userId' ]);
/**
2021-09-21 08:22:13 +00:00
* Test for SUCCESS searchUsers
2021-10-05 10:30:33 +00:00
*/
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2022-08-15 19:35:50 +00:00
'search' => " Ronaldo " ,
2021-09-21 08:22:13 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'users' ]);
2021-09-23 06:57:16 +00:00
$this -> assertCount ( 1 , $response [ 'body' ][ 'users' ]);
2021-09-21 08:22:13 +00:00
$this -> assertEquals ( $response [ 'body' ][ 'users' ][ 0 ][ '$id' ], $data [ 'userId' ]);
2022-03-15 12:04:24 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2022-08-15 19:35:50 +00:00
'search' => " cristiano.ronaldo@manchester-united.co.uk " ,
2022-03-15 12:04:24 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'users' ]);
$this -> assertCount ( 1 , $response [ 'body' ][ 'users' ]);
$this -> assertEquals ( $response [ 'body' ][ 'users' ][ 0 ][ '$id' ], $data [ 'userId' ]);
2021-09-21 08:22:13 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2022-08-15 19:35:50 +00:00
'search' => " cristiano.ronaldo " ,
2021-09-21 08:22:13 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'users' ]);
2021-09-23 06:57:16 +00:00
$this -> assertCount ( 1 , $response [ 'body' ][ 'users' ]);
2021-09-21 08:22:13 +00:00
$this -> assertEquals ( $response [ 'body' ][ 'users' ][ 0 ][ '$id' ], $data [ 'userId' ]);
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2022-08-15 19:35:50 +00:00
'search' => " manchester " ,
2021-09-21 08:22:13 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'users' ]);
2021-09-23 06:57:16 +00:00
$this -> assertCount ( 1 , $response [ 'body' ][ 'users' ]);
2021-09-21 08:22:13 +00:00
$this -> assertEquals ( $response [ 'body' ][ 'users' ][ 0 ][ '$id' ], $data [ 'userId' ]);
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2022-08-15 19:35:50 +00:00
'search' => " united.co.uk " ,
2022-02-21 21:53:23 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertIsArray ( $response [ 'body' ]);
$this -> assertIsArray ( $response [ 'body' ][ 'users' ]);
2022-03-01 11:09:34 +00:00
$this -> assertIsInt ( $response [ 'body' ][ 'total' ]);
$this -> assertEquals ( 1 , $response [ 'body' ][ 'total' ]);
2022-02-21 21:53:23 +00:00
$this -> assertCount ( 1 , $response [ 'body' ][ 'users' ]);
2025-11-25 08:11:01 +00:00
// Some databases only support fulltext search on complete words
2026-02-12 15:56:39 +00:00
if ( $this -> getSupportForFulltextWildcard ()) {
2025-09-16 16:13:38 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'search' => " man " ,
]);
2025-08-11 19:07:05 +00:00
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertIsArray ( $response [ 'body' ]);
$this -> assertIsArray ( $response [ 'body' ][ 'users' ]);
$this -> assertIsInt ( $response [ 'body' ][ 'total' ]);
$this -> assertEquals ( 1 , $response [ 'body' ][ 'total' ]);
$this -> assertCount ( 1 , $response [ 'body' ][ 'users' ]);
}
2021-09-21 08:22:13 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2022-08-15 19:35:50 +00:00
'search' => $data [ 'userId' ],
2021-09-21 08:22:13 +00:00
]);
2022-02-22 09:39:33 +00:00
2021-09-21 08:22:13 +00:00
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'users' ]);
2021-09-23 07:01:10 +00:00
$this -> assertCount ( 1 , $response [ 'body' ][ 'users' ]);
2021-09-21 08:22:13 +00:00
$this -> assertEquals ( $response [ 'body' ][ 'users' ][ 0 ][ '$id' ], $data [ 'userId' ]);
2021-10-07 15:49:47 +00:00
2023-09-28 05:58:29 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'search' => '>' ,
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertEmpty ( $response [ 'body' ][ 'users' ]);
$this -> assertCount ( 0 , $response [ 'body' ][ 'users' ]);
2021-10-07 15:49:47 +00:00
/**
* Test for FAILURE
*/
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
Query :: cursorAfter ( new Document ([ '$id' => 'unknown' ])) -> toString ()
]
2021-10-07 15:49:47 +00:00
]);
$this -> assertEquals ( 400 , $response [ 'headers' ][ 'status-code' ]);
2021-08-09 12:55:30 +00:00
}
2026-02-05 22:54:14 +00:00
public function testGetUser () : void
2020-01-13 18:55:57 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> setupUser ();
2020-01-13 18:55:57 +00:00
/**
* Test for SUCCESS
*/
$user = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ], array_merge ([
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2020-01-13 18:55:57 +00:00
], $this -> getHeaders ()));
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
2026-02-05 22:54:14 +00:00
$this -> assertNotEmpty ( $user [ 'body' ][ 'name' ]);
$this -> assertNotEmpty ( $user [ 'body' ][ 'email' ]);
2021-07-14 11:02:12 +00:00
$this -> assertEquals ( $user [ 'body' ][ 'status' ], true );
2022-07-04 09:55:11 +00:00
$this -> assertGreaterThan ( '2000-01-01 00:00:00' , $user [ 'body' ][ 'registration' ]);
2020-01-13 18:55:57 +00:00
$sessions = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ] . '/sessions' , array_merge ([
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2020-01-13 18:55:57 +00:00
], $this -> getHeaders ()));
$this -> assertEquals ( $sessions [ 'headers' ][ 'status-code' ], 200 );
$this -> assertIsArray ( $sessions [ 'body' ]);
$users = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2020-01-13 18:55:57 +00:00
], $this -> getHeaders ()));
$this -> assertEquals ( $users [ 'headers' ][ 'status-code' ], 200 );
$this -> assertIsArray ( $users [ 'body' ]);
$this -> assertIsArray ( $users [ 'body' ][ 'users' ]);
2022-02-27 09:57:09 +00:00
$this -> assertIsInt ( $users [ 'body' ][ 'total' ]);
$this -> assertGreaterThan ( 0 , $users [ 'body' ][ 'total' ]);
2020-01-13 18:55:57 +00:00
2025-10-20 15:18:17 +00:00
/**
2025-10-29 09:08:08 +00:00
* Test for SUCCESS with total = false
2025-10-20 15:18:17 +00:00
*/
$usersWithIncludeTotalFalse = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2025-10-29 09:08:08 +00:00
'total' => false
2025-10-20 15:18:17 +00:00
]);
2025-10-20 15:38:14 +00:00
$this -> assertEquals ( 200 , $usersWithIncludeTotalFalse [ 'headers' ][ 'status-code' ]);
2025-10-20 15:18:17 +00:00
$this -> assertIsArray ( $usersWithIncludeTotalFalse [ 'body' ]);
$this -> assertIsArray ( $usersWithIncludeTotalFalse [ 'body' ][ 'users' ]);
$this -> assertIsInt ( $usersWithIncludeTotalFalse [ 'body' ][ 'total' ]);
$this -> assertEquals ( 0 , $usersWithIncludeTotalFalse [ 'body' ][ 'total' ]);
$this -> assertGreaterThan ( 0 , count ( $usersWithIncludeTotalFalse [ 'body' ][ 'users' ]));
2022-10-15 14:40:07 +00:00
/**
* Test for FAILURE
*/
$user = $this -> client -> call ( Client :: METHOD_GET , '/users/non_existent' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 404 );
$this -> assertEquals ( $user [ 'body' ][ 'code' ], 404 );
$this -> assertEquals ( $user [ 'body' ][ 'message' ], 'User with the requested ID could not be found.' );
$this -> assertEquals ( $user [ 'body' ][ 'type' ], 'user_not_found' );
2020-01-13 18:55:57 +00:00
}
2026-02-05 22:54:14 +00:00
public function testListUserMemberships () : void
2025-03-28 05:47:18 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> setupUser ();
2025-03-28 05:47:18 +00:00
/**
* Test for SUCCESS
*/
// create a new team
$team = $this -> client -> call ( Client :: METHOD_POST , '/teams' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'teamId' => 'unique()' ,
'name' => 'Test Team' ,
]);
// create a new membership
$membership = $this -> client -> call ( Client :: METHOD_POST , '/teams/' . $team [ 'body' ][ '$id' ] . '/memberships' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'userId' => $data [ 'userId' ],
'roles' => [ 'new-role' ],
]);
// list the memberships
$response = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ] . '/memberships' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertEquals ( $response [ 'body' ][ 'memberships' ][ 0 ][ '$id' ], $membership [ 'body' ][ '$id' ]);
$this -> assertEquals ( $response [ 'body' ][ 'memberships' ][ 0 ][ 'roles' ], [ 'new-role' ]);
$this -> assertEquals ( $response [ 'body' ][ 'total' ], 1 );
// create another membership with a new role
$team = $this -> client -> call ( Client :: METHOD_POST , '/teams' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'teamId' => 'unique()' ,
'name' => 'Test Team 2' ,
]);
$membership = $this -> client -> call ( Client :: METHOD_POST , '/teams/' . $team [ 'body' ][ '$id' ] . '/memberships' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'userId' => $data [ 'userId' ],
'roles' => [ 'new-role-2' ],
]);
// list out memberships and query by role
$response = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ] . '/memberships' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
Query :: contains ( 'roles' , [ 'new-role-2' ]) -> toString ()
]
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertEquals ( $response [ 'body' ][ 'memberships' ][ 0 ][ '$id' ], $membership [ 'body' ][ '$id' ]);
$this -> assertEquals ( $response [ 'body' ][ 'memberships' ][ 0 ][ 'roles' ], [ 'new-role-2' ]);
$this -> assertEquals ( $response [ 'body' ][ 'total' ], 1 );
/**
* Test for FAILURE
*/
// query using equal on array field
$response = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ] . '/memberships' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
Query :: equal ( 'roles' , [ 'new-role-2' ]) -> toString ()
]
]);
$this -> assertEquals ( $response [ 'body' ][ 'code' ], 400 );
$this -> assertEquals ( $response [ 'body' ][ 'message' ], 'Invalid `queries` param: Invalid query: Cannot query equal on attribute "roles" because it is an array.' );
$this -> assertEquals ( $response [ 'body' ][ 'type' ], 'general_argument_invalid' );
}
2026-02-05 22:54:14 +00:00
public function testUpdateUserName () : void
2021-08-29 10:30:48 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> setupUser ();
2021-08-29 10:30:48 +00:00
/**
* Test for SUCCESS
*/
2024-01-20 09:43:31 +00:00
$user = $this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $data [ 'userId' ] . '/name' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'name' => '' ,
]);
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
$this -> assertEquals ( $user [ 'body' ][ 'name' ], '' );
$user = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ], array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
$this -> assertEquals ( $user [ 'body' ][ 'name' ], '' );
2021-08-29 10:30:48 +00:00
$user = $this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $data [ 'userId' ] . '/name' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'name' => 'Updated name' ,
]);
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
$this -> assertEquals ( $user [ 'body' ][ 'name' ], 'Updated name' );
$user = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ], array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
$this -> assertEquals ( $user [ 'body' ][ 'name' ], 'Updated name' );
2026-02-05 22:54:14 +00:00
// Mark name as updated for search tests
static :: $userNameUpdated = true ;
2021-08-29 10:30:48 +00:00
}
2026-02-05 22:54:14 +00:00
public function testUpdateUserNameSearch () : void
2022-04-26 10:07:33 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> ensureUserNameUpdated ();
2022-04-26 10:07:33 +00:00
$id = $data [ 'userId' ] ? ? '' ;
$newName = 'Updated name' ;
/**
* Test for SUCCESS
*/
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2022-08-15 19:35:50 +00:00
'search' => $newName ,
2022-04-26 10:07:33 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'users' ]);
$this -> assertCount ( 1 , $response [ 'body' ][ 'users' ]);
$this -> assertEquals ( $response [ 'body' ][ 'users' ][ 0 ][ '$id' ], $id );
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2022-08-15 19:35:50 +00:00
'search' => $id ,
2022-04-26 10:07:33 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'users' ]);
$this -> assertCount ( 1 , $response [ 'body' ][ 'users' ]);
$this -> assertEquals ( $response [ 'body' ][ 'users' ][ 0 ][ '$id' ], $id );
}
2026-02-05 22:54:14 +00:00
public function testUpdateUserEmail () : void
2021-08-29 10:30:48 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> setupUser ();
2021-08-29 10:30:48 +00:00
/**
* Test for SUCCESS
*/
2024-01-20 09:43:31 +00:00
$user = $this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $data [ 'userId' ] . '/email' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'email' => '' ,
]);
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
$this -> assertEquals ( $user [ 'body' ][ 'email' ], '' );
$user = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ], array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
$this -> assertEquals ( $user [ 'body' ][ 'email' ], '' );
2021-08-29 10:30:48 +00:00
$user = $this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $data [ 'userId' ] . '/email' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'email' => 'users.service@updated.com' ,
]);
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
$this -> assertEquals ( $user [ 'body' ][ 'email' ], 'users.service@updated.com' );
$user = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ], array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
$this -> assertEquals ( $user [ 'body' ][ 'email' ], 'users.service@updated.com' );
2026-02-05 22:54:14 +00:00
// Mark email as updated for search tests
static :: $userEmailUpdated = true ;
2021-08-29 10:30:48 +00:00
}
2026-02-05 22:54:14 +00:00
public function testUpdateUserEmailSearch () : void
2022-04-26 10:07:33 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> ensureUserEmailUpdated ();
2022-04-26 10:07:33 +00:00
$id = $data [ 'userId' ] ? ? '' ;
$newEmail = '"users.service@updated.com"' ;
/**
* Test for SUCCESS
*/
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2022-08-15 19:35:50 +00:00
'search' => $newEmail ,
2022-04-26 10:07:33 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'users' ]);
$this -> assertCount ( 1 , $response [ 'body' ][ 'users' ]);
$this -> assertEquals ( $response [ 'body' ][ 'users' ][ 0 ][ '$id' ], $id );
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2022-08-15 19:35:50 +00:00
'search' => $id ,
2022-04-26 10:07:33 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'users' ]);
$this -> assertCount ( 1 , $response [ 'body' ][ 'users' ]);
$this -> assertEquals ( $response [ 'body' ][ 'users' ][ 0 ][ '$id' ], $id );
}
2026-02-05 22:54:14 +00:00
public function testUpdateUserPassword () : void
2021-08-29 10:30:48 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> ensureUserEmailUpdated ();
2021-08-29 10:30:48 +00:00
/**
* Test for SUCCESS
*/
2024-03-06 17:34:21 +00:00
$session = $this -> client -> call ( Client :: METHOD_POST , '/account/sessions/email' , [
2024-01-20 09:43:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2024-03-06 17:34:21 +00:00
], [
2024-01-20 09:43:31 +00:00
'email' => 'users.service@updated.com' ,
'password' => 'password'
2024-03-06 17:34:21 +00:00
]);
2024-01-20 09:43:31 +00:00
$this -> assertEquals ( $session [ 'headers' ][ 'status-code' ], 201 );
2024-03-06 17:34:21 +00:00
$user = $this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $data [ 'userId' ] . '/password' , array_merge ([
2024-01-20 09:43:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2024-03-06 17:34:21 +00:00
], $this -> getHeaders ()), [
2024-01-20 09:43:31 +00:00
'password' => '' ,
2024-03-06 17:34:21 +00:00
]);
2024-01-20 09:43:31 +00:00
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $user [ 'body' ][ '$id' ]);
$this -> assertEmpty ( $user [ 'body' ][ 'password' ]);
2026-02-24 01:00:07 +00:00
$this -> assertEventually ( function () {
$session = $this -> client -> call ( Client :: METHOD_POST , '/account/sessions/email' , [
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], [
'email' => 'users.service@updated.com' ,
'password' => 'password'
]);
2024-01-20 09:43:31 +00:00
2026-02-24 01:00:07 +00:00
$this -> assertEquals ( 401 , $session [ 'headers' ][ 'status-code' ]);
}, 15_000 , 500 );
2025-06-16 17:35:52 +00:00
$this -> updateProjectinvalidateSessionsProperty ( true );
2021-08-29 10:30:48 +00:00
$user = $this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $data [ 'userId' ] . '/password' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'password' => 'password2' ,
]);
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $user [ 'body' ][ '$id' ]);
2024-01-20 09:43:31 +00:00
$this -> assertNotEmpty ( $user [ 'body' ][ 'password' ]);
2021-08-29 10:30:48 +00:00
2025-06-14 12:37:42 +00:00
$sessions = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ] . '/sessions' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( $sessions [ 'headers' ][ 'status-code' ], 200 );
$this -> assertIsArray ( $sessions [ 'body' ]);
$this -> assertEmpty ( $sessions [ 'body' ][ 'sessions' ]);
2022-06-14 08:17:50 +00:00
$session = $this -> client -> call ( Client :: METHOD_POST , '/account/sessions/email' , [
2021-08-29 10:30:48 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], [
'email' => 'users.service@updated.com' ,
'password' => 'password2'
]);
$this -> assertEquals ( $session [ 'headers' ][ 'status-code' ], 201 );
2025-06-16 17:35:52 +00:00
$this -> updateProjectinvalidateSessionsProperty ( false );
2021-08-29 10:30:48 +00:00
}
2022-09-06 04:13:24 +00:00
#[Retry(count: 1)]
2026-02-05 22:54:14 +00:00
public function testUpdateUserStatus () : void
2020-01-13 18:55:57 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> setupUser ();
2020-01-13 18:55:57 +00:00
/**
* Test for SUCCESS
*/
$user = $this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $data [ 'userId' ] . '/status' , array_merge ([
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2020-01-13 18:55:57 +00:00
], $this -> getHeaders ()), [
2021-07-14 11:02:12 +00:00
'status' => false ,
2020-01-13 18:55:57 +00:00
]);
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
2021-07-14 11:02:12 +00:00
$this -> assertEquals ( $user [ 'body' ][ 'status' ], false );
2020-01-13 18:55:57 +00:00
$user = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ], array_merge ([
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2020-01-13 18:55:57 +00:00
], $this -> getHeaders ()));
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
2021-07-14 11:02:12 +00:00
$this -> assertEquals ( $user [ 'body' ][ 'status' ], false );
2020-01-13 18:55:57 +00:00
2026-02-05 22:54:14 +00:00
// Reset status back to true for other tests
$this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $data [ 'userId' ] . '/status' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'status' => true ,
]);
2020-01-13 18:55:57 +00:00
}
2026-02-05 22:54:14 +00:00
public function testUpdateEmailVerification () : void
2021-05-31 05:50:52 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> setupUser ();
2021-05-31 05:50:52 +00:00
/**
* Test for SUCCESS
*/
$user = $this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $data [ 'userId' ] . '/verification' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'emailVerification' => true ,
]);
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
$this -> assertEquals ( $user [ 'body' ][ 'emailVerification' ], true );
$user = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ], array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
$this -> assertEquals ( $user [ 'body' ][ 'emailVerification' ], true );
}
2022-12-22 03:12:45 +00:00
#[Retry(count: 1)]
2026-02-05 22:54:14 +00:00
public function testUpdateAndGetUserPrefs () : void
2020-01-13 18:55:57 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> setupUser ();
2020-01-13 18:55:57 +00:00
/**
* Test for SUCCESS
*/
2022-05-23 14:54:50 +00:00
$user = $this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $data [ 'userId' ] . '/prefs' , array_merge ([
2020-01-13 18:55:57 +00:00
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2020-01-13 18:55:57 +00:00
], $this -> getHeaders ()), [
'prefs' => [
2020-10-30 19:53:27 +00:00
'funcKey1' => 'funcValue1' ,
'funcKey2' => 'funcValue2' ,
2020-01-13 18:55:57 +00:00
],
]);
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
2020-10-30 19:53:27 +00:00
$this -> assertEquals ( $user [ 'body' ][ 'funcKey1' ], 'funcValue1' );
$this -> assertEquals ( $user [ 'body' ][ 'funcKey2' ], 'funcValue2' );
2020-01-13 18:55:57 +00:00
2022-05-23 14:54:50 +00:00
$user = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ] . '/prefs' , array_merge ([
2021-01-10 11:56:48 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
$this -> assertEquals ( $user [ 'body' ], [
'funcKey1' => 'funcValue1' ,
'funcKey2' => 'funcValue2' ,
]);
2020-01-19 20:38:00 +00:00
/**
* Test for FAILURE
*/
$user = $this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $data [ 'userId' ] . '/prefs' , array_merge ([
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2020-01-19 20:38:00 +00:00
], $this -> getHeaders ()), [
'prefs' => 'bad-string' ,
]);
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 400 );
$user = $this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $data [ 'userId' ] . '/prefs' , array_merge ([
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2020-01-19 20:38:00 +00:00
], $this -> getHeaders ()));
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 400 );
2020-01-13 18:30:13 +00:00
}
2026-02-05 22:54:14 +00:00
public function testUpdateUserNumber () : void
2022-10-05 12:00:53 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> setupUser ();
$this -> setupUser1 ();
2022-10-05 12:00:53 +00:00
/**
* Test for SUCCESS
*/
2024-01-20 09:43:31 +00:00
$updatedNumber = " " ;
$user = $this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $data [ 'userId' ] . '/phone' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'number' => $updatedNumber ,
]);
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
2026-03-11 05:25:08 +00:00
$this -> assertEmpty ( $user [ 'body' ][ 'phone' ] ? ? '' );
2024-01-20 09:43:31 +00:00
$user = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ], array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
2026-03-11 05:25:08 +00:00
$this -> assertEmpty ( $user [ 'body' ][ 'phone' ] ? ? '' );
2024-01-20 09:43:31 +00:00
2022-10-05 12:00:53 +00:00
$updatedNumber = " +910000000000 " ; //dummy number
$user = $this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $data [ 'userId' ] . '/phone' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'number' => $updatedNumber ,
]);
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
$this -> assertEquals ( $user [ 'body' ][ 'phone' ], $updatedNumber );
$user = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ], array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 200 );
$this -> assertEquals ( $user [ 'body' ][ 'phone' ], $updatedNumber );
2022-12-18 06:27:41 +00:00
/**
2022-10-05 18:10:11 +00:00
* Test for FAILURE
*/
2024-01-22 10:29:41 +00:00
$errorType = " user_target_already_exists " ;
2022-10-05 18:10:11 +00:00
$user1Id = " user1 " ;
$statusCodeForUserPhoneAlredyExists = 409 ;
// adding same number ($updatedNumber) to different user i.e user1
$response = $this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $user1Id . '/phone' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'number' => $updatedNumber ,
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], $statusCodeForUserPhoneAlredyExists );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertEquals ( $response [ 'body' ][ 'type' ], $errorType );
2026-02-05 22:54:14 +00:00
// Mark phone as updated for search tests
static :: $userNumberUpdated = true ;
2022-10-05 12:00:53 +00:00
}
2026-03-11 05:25:08 +00:00
public function testUpdateTwoUsersPhoneToEmpty () : void
{
$projectId = $this -> getProject ()[ '$id' ];
$headers = array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $projectId ,
], $this -> getHeaders ());
// Create two users with distinct valid phone numbers
$user1 = $this -> client -> call ( Client :: METHOD_POST , '/users' , $headers , [
'userId' => ID :: unique (),
'email' => 'user1-phone-empty-test@appwrite.io' ,
'password' => 'password' ,
'name' => 'User One' ,
'phone' => '+16175551201' ,
]);
$this -> assertEquals ( 201 , $user1 [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( '+16175551201' , $user1 [ 'body' ][ 'phone' ]);
$user2 = $this -> client -> call ( Client :: METHOD_POST , '/users' , $headers , [
'userId' => ID :: unique (),
'email' => 'user2-phone-empty-test@appwrite.io' ,
'password' => 'password' ,
'name' => 'User Two' ,
'phone' => '+16175551202' ,
]);
$this -> assertEquals ( 201 , $user2 [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( '+16175551202' , $user2 [ 'body' ][ 'phone' ]);
// Update first user's phone to empty - must succeed
$response1 = $this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $user1 [ 'body' ][ '$id' ] . '/phone' , $headers , [
'number' => '' ,
]);
$this -> assertEquals ( 200 , $response1 [ 'headers' ][ 'status-code' ], 'First user phone should update to empty' );
$this -> assertEmpty ( $response1 [ 'body' ][ 'phone' ] ? ? '' );
// Update second user's phone to empty - must succeed (would fail with duplicate if empty was stored as '')
$response2 = $this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $user2 [ 'body' ][ '$id' ] . '/phone' , $headers , [
'number' => '' ,
]);
$this -> assertEquals ( 200 , $response2 [ 'headers' ][ 'status-code' ], 'Second user phone should update to empty without duplicate error' );
$this -> assertEmpty ( $response2 [ 'body' ][ 'phone' ] ? ? '' );
// Verify both users have empty phone via GET
$get1 = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $user1 [ 'body' ][ '$id' ], $headers );
$get2 = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $user2 [ 'body' ][ '$id' ], $headers );
$this -> assertEquals ( 200 , $get1 [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 200 , $get2 [ 'headers' ][ 'status-code' ]);
$this -> assertEmpty ( $get1 [ 'body' ][ 'phone' ] ? ? '' );
$this -> assertEmpty ( $get2 [ 'body' ][ 'phone' ] ? ? '' );
}
2026-02-05 22:54:14 +00:00
public function testUpdateUserNumberSearch () : void
2022-10-05 12:00:53 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> ensureUserNumberUpdated ();
2022-10-05 12:00:53 +00:00
$id = $data [ 'userId' ] ? ? '' ;
$newNumber = " +910000000000 " ; //dummy number
/**
* Test for SUCCESS
*/
$response = $this -> client -> call ( Client :: METHOD_GET , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'search' => $newNumber ,
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 200 );
$this -> assertNotEmpty ( $response [ 'body' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'users' ]);
$this -> assertCount ( 1 , $response [ 'body' ][ 'users' ]);
$this -> assertEquals ( $response [ 'body' ][ 'users' ][ 0 ][ '$id' ], $id );
$this -> assertEquals ( $response [ 'body' ][ 'users' ][ 0 ][ 'phone' ], $newNumber );
}
2026-01-15 03:14:53 +00:00
public static function userLabelsProvider () : array
2023-05-27 00:23:01 +00:00
{
return [
'single label' => [
[ 'admin' ],
Response :: STATUS_CODE_OK ,
[ 'admin' ],
],
'replace with multiple labels' => [
[ 'vip' , 'pro' ],
Response :: STATUS_CODE_OK ,
[ 'vip' , 'pro' ],
],
'clear labels' => [
[],
Response :: STATUS_CODE_OK ,
[],
],
'duplicate labels' => [
[ 'vip' , 'vip' , 'pro' ],
Response :: STATUS_CODE_OK ,
[ 'vip' , 'pro' ],
],
'invalid label' => [
[ 'invalid-label' ],
Response :: STATUS_CODE_BAD_REQUEST ,
[],
],
'too long' => [
[ \str_repeat ( 'a' , 129 )],
Response :: STATUS_CODE_BAD_REQUEST ,
[],
],
'too many labels' => [
[ \array_fill ( 0 , 101 , 'a' )],
Response :: STATUS_CODE_BAD_REQUEST ,
[],
],
];
}
2026-01-15 03:14:53 +00:00
#[DataProvider('userLabelsProvider')]
2026-02-05 22:54:14 +00:00
public function testUpdateUserLabels ( array $labels , int $expectedStatus , array $expectedLabels ) : void
2023-05-27 00:23:01 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> setupUser ();
2023-05-27 00:23:01 +00:00
$user = $this -> client -> call ( Client :: METHOD_PUT , '/users/' . $data [ 'userId' ] . '/labels' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'labels' => $labels ,
]);
$this -> assertEquals ( $expectedStatus , $user [ 'headers' ][ 'status-code' ]);
if ( $expectedStatus === Response :: STATUS_CODE_OK ) {
$this -> assertEquals ( $user [ 'body' ][ 'labels' ], $expectedLabels );
}
}
2026-02-05 22:54:14 +00:00
public function testUpdateUserLabelsWithoutLabels () : void
2023-05-27 00:23:01 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> setupUser ();
2023-05-27 00:23:01 +00:00
$user = $this -> client -> call ( Client :: METHOD_PUT , '/users/' . $data [ 'userId' ] . '/labels' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), []);
$this -> assertEquals ( Response :: STATUS_CODE_BAD_REQUEST , $user [ 'headers' ][ 'status-code' ]);
}
public function testUpdateUserLabelsNonExistentUser () : void
{
$user = $this -> client -> call ( Client :: METHOD_PUT , '/users/dne/labels' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'labels' => [ 'admin' ],
]);
$this -> assertEquals ( Response :: STATUS_CODE_NOT_FOUND , $user [ 'headers' ][ 'status-code' ]);
}
2021-11-15 09:49:11 +00:00
2026-02-05 22:54:14 +00:00
public function testGetLogs () : void
2021-11-15 09:49:11 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> setupUser ();
2021-11-15 09:49:11 +00:00
/**
* Test for SUCCESS
*/
$logs = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ] . '/logs' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2022-08-19 23:31:02 +00:00
], $this -> getHeaders ()));
2021-11-15 09:49:11 +00:00
$this -> assertEquals ( $logs [ 'headers' ][ 'status-code' ], 200 );
$this -> assertIsArray ( $logs [ 'body' ][ 'logs' ]);
2022-08-19 23:31:02 +00:00
$this -> assertIsNumeric ( $logs [ 'body' ][ 'total' ]);
2021-11-15 09:49:11 +00:00
$logs = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ] . '/logs' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
Query :: limit ( 1 ) -> toString ()
],
2021-11-15 09:49:11 +00:00
]);
$this -> assertEquals ( $logs [ 'headers' ][ 'status-code' ], 200 );
$this -> assertIsArray ( $logs [ 'body' ][ 'logs' ]);
2022-08-19 23:31:02 +00:00
$this -> assertLessThanOrEqual ( 1 , count ( $logs [ 'body' ][ 'logs' ]));
$this -> assertIsNumeric ( $logs [ 'body' ][ 'total' ]);
2021-11-15 09:49:11 +00:00
$logs = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ] . '/logs' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
Query :: offset ( 1 ) -> toString ()
],
2021-11-15 09:49:11 +00:00
]);
$this -> assertEquals ( $logs [ 'headers' ][ 'status-code' ], 200 );
$this -> assertIsArray ( $logs [ 'body' ][ 'logs' ]);
2022-08-19 23:31:02 +00:00
$this -> assertIsNumeric ( $logs [ 'body' ][ 'total' ]);
2021-11-15 09:49:11 +00:00
$logs = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ] . '/logs' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
Query :: limit ( 1 ) -> toString (),
Query :: offset ( 1 ) -> toString (),
],
2021-11-15 09:49:11 +00:00
]);
$this -> assertEquals ( $logs [ 'headers' ][ 'status-code' ], 200 );
$this -> assertIsArray ( $logs [ 'body' ][ 'logs' ]);
2022-08-19 23:31:02 +00:00
$this -> assertLessThanOrEqual ( 1 , count ( $logs [ 'body' ][ 'logs' ]));
$this -> assertIsNumeric ( $logs [ 'body' ][ 'total' ]);
2022-08-19 00:09:34 +00:00
/**
* Test for FAILURE
*/
$response = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ] . '/logs' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
Query :: limit ( - 1 ) -> toString ()
]
2022-08-19 00:09:34 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 400 );
$response = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ] . '/logs' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
Query :: offset ( - 1 ) -> toString ()
]
2022-08-19 00:09:34 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 400 );
$response = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ] . '/logs' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
Query :: equal ( '$id' , [ 'asdf' ]) -> toString ()
]
2022-08-19 00:09:34 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 400 );
$response = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ] . '/logs' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
Query :: orderAsc ( '$id' ) -> toString ()
]
2022-08-19 00:09:34 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 400 );
$response = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ] . '/logs' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-01-09 03:43:39 +00:00
'queries' => [
'{ "method": "cursorAsc", "attribute": "$id" }'
]
2022-08-19 00:09:34 +00:00
]);
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 400 );
2021-11-15 09:49:11 +00:00
}
2026-02-05 22:54:14 +00:00
public function testCreateUserTarget () : void
2023-08-23 20:24:25 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> setupUser ();
2023-08-25 10:25:04 +00:00
$provider = $this -> client -> call ( Client :: METHOD_POST , '/messaging/providers/sendgrid' , \array_merge ([
2023-08-23 20:24:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-08-25 10:25:04 +00:00
], $this -> getHeaders ()), [
2023-11-14 12:44:07 +00:00
'providerId' => ID :: unique (),
2023-08-23 20:24:25 +00:00
'name' => 'Sengrid1' ,
2023-10-25 18:32:22 +00:00
'apiKey' => 'my-apikey' ,
'from' => 'from@domain.com' ,
2023-08-23 20:24:25 +00:00
]);
$this -> assertEquals ( 201 , $provider [ 'headers' ][ 'status-code' ]);
$response = $this -> client -> call ( Client :: METHOD_POST , '/users/' . $data [ 'userId' ] . '/targets' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-08-25 10:25:04 +00:00
], $this -> getHeaders ()), [
2023-08-23 20:24:25 +00:00
'targetId' => ID :: unique (),
'providerId' => $provider [ 'body' ][ '$id' ],
2023-11-14 12:44:07 +00:00
'providerType' => 'email' ,
2023-11-21 09:41:09 +00:00
'identifier' => 'random-email@mail.org' ,
2023-08-23 20:24:25 +00:00
]);
$this -> assertEquals ( 201 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $provider [ 'body' ][ '$id' ], $response [ 'body' ][ 'providerId' ]);
2023-11-21 09:41:09 +00:00
$this -> assertEquals ( 'random-email@mail.org' , $response [ 'body' ][ 'identifier' ]);
2026-02-05 22:54:14 +00:00
// Cache for other tests
$projectId = $this -> getProject ()[ '$id' ];
static :: $cachedUserTarget [ $projectId ] = $response [ 'body' ];
2023-08-23 20:24:25 +00:00
}
2023-08-23 20:25:08 +00:00
2026-02-05 22:54:14 +00:00
public function testUpdateUserTarget () : void
2023-08-23 20:24:25 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> setupUserTarget ();
2023-11-14 12:44:07 +00:00
$response = $this -> client -> call ( Client :: METHOD_PATCH , '/users/' . $data [ 'userId' ] . '/targets/' . $data [ '$id' ], array_merge ([
2023-08-23 20:24:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-08-25 10:25:04 +00:00
], $this -> getHeaders ()), [
2023-11-21 09:41:09 +00:00
'identifier' => 'random-email1@mail.org' ,
2023-08-23 20:24:25 +00:00
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2023-11-21 09:41:09 +00:00
$this -> assertEquals ( 'random-email1@mail.org' , $response [ 'body' ][ 'identifier' ]);
2024-10-22 01:35:11 +00:00
$this -> assertEquals ( false , $response [ 'body' ][ 'expired' ]);
2026-02-05 22:54:14 +00:00
// Update cache with new data
$projectId = $this -> getProject ()[ '$id' ];
static :: $cachedUserTarget [ $projectId ] = $response [ 'body' ];
2023-08-23 20:24:25 +00:00
}
2023-08-23 20:25:08 +00:00
2026-02-05 22:54:14 +00:00
public function testListUserTarget () : void
2023-08-23 20:24:25 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> setupUserTarget ();
2023-08-23 20:24:25 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ] . '/targets' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-08-25 10:25:04 +00:00
], $this -> getHeaders ()));
2024-10-22 01:54:34 +00:00
2023-08-23 20:24:25 +00:00
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2026-02-05 22:54:14 +00:00
$this -> assertGreaterThanOrEqual ( 1 , \count ( $response [ 'body' ][ 'targets' ]));
2023-08-23 20:24:25 +00:00
}
2026-02-05 22:54:14 +00:00
public function testGetUserTarget () : void
2023-08-23 20:24:25 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> setupUserTarget ();
2023-08-23 20:25:08 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ] . '/targets/' . $data [ '$id' ], array_merge ([
2023-08-23 20:24:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-08-25 10:25:04 +00:00
], $this -> getHeaders ()));
2023-08-23 20:24:25 +00:00
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $data [ '$id' ], $response [ 'body' ][ '$id' ]);
}
2026-02-05 22:54:14 +00:00
public function testDeleteUserTarget () : void
2023-08-23 20:24:25 +00:00
{
2026-02-05 22:54:14 +00:00
$data = $this -> setupUserTarget ();
2023-08-23 20:25:08 +00:00
$response = $this -> client -> call ( Client :: METHOD_DELETE , '/users/' . $data [ 'userId' ] . '/targets/' . $data [ '$id' ], array_merge ([
2023-08-23 20:24:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-08-25 10:25:04 +00:00
], $this -> getHeaders ()));
2023-11-14 12:44:07 +00:00
2023-08-23 20:24:25 +00:00
$this -> assertEquals ( 204 , $response [ 'headers' ][ 'status-code' ]);
2023-11-14 12:44:07 +00:00
2026-02-05 22:54:14 +00:00
// Clear cached target since it was deleted
$projectId = $this -> getProject ()[ '$id' ];
unset ( static :: $cachedUserTarget [ $projectId ]);
2023-08-23 20:24:25 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , '/users/' . $data [ 'userId' ] . '/targets' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-08-25 10:25:04 +00:00
], $this -> getHeaders ()));
2023-11-14 12:44:07 +00:00
2023-08-23 20:24:25 +00:00
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
}
2026-02-05 22:54:14 +00:00
public function testDeleteUser () : void
2020-08-28 21:56:22 +00:00
{
2026-02-05 22:54:14 +00:00
// Create a new user specifically for deletion test
$userId = ID :: unique ();
$user = $this -> client -> call ( Client :: METHOD_POST , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'userId' => $userId ,
'email' => 'deletetest@example.com' ,
'password' => 'password' ,
'name' => 'Delete Test User' ,
]);
$this -> assertEquals ( 201 , $user [ 'headers' ][ 'status-code' ]);
2020-08-28 21:56:22 +00:00
/**
* Test for SUCCESS
*/
2026-02-05 22:54:14 +00:00
$user = $this -> client -> call ( Client :: METHOD_DELETE , '/users/' . $userId , array_merge ([
2020-08-28 21:56:22 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 204 );
/**
* Test for FAILURE
*/
2026-02-05 22:54:14 +00:00
$user = $this -> client -> call ( Client :: METHOD_DELETE , '/users/' . $userId , array_merge ([
2020-08-28 21:56:22 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 404 );
}
2024-05-29 07:32:58 +00:00
public function testUserJWT ()
2024-05-28 09:25:54 +00:00
{
// Create user
$userId = ID :: unique ();
$user = $this -> client -> call ( Client :: METHOD_POST , '/users' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'userId' => $userId ,
'email' => 'jwtuser@appwrite.io' ,
'password' => 'password' ,
], false );
$this -> assertEquals ( $user [ 'headers' ][ 'status-code' ], 201 );
2024-07-21 13:28:23 +00:00
// Create JWT 0, with no session available
$response = $this -> client -> call ( Client :: METHOD_POST , '/users/' . $userId . '/jwts' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), []);
$this -> assertEquals ( 201 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'jwt' ]);
$jwt0 = $response [ 'body' ][ 'jwt' ];
// Ensure JWT 0 works
$response = $this -> client -> call ( Client :: METHOD_GET , '/account' , array_merge ([
'origin' => 'http://localhost' ,
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-jwt' => $jwt0 ,
]));
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $userId , $response [ 'body' ][ '$id' ]);
2024-05-28 09:25:54 +00:00
// Create two sessions
$response = $this -> client -> call ( Client :: METHOD_POST , '/account/sessions/email' , array_merge ([
'origin' => 'http://localhost' ,
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
]), [
'email' => 'jwtuser@appwrite.io' ,
'password' => 'password' ,
]);
$this -> assertEquals ( 201 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $userId , $response [ 'body' ][ 'userId' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ '$id' ]);
$session1Id = $response [ 'body' ][ '$id' ];
$response = $this -> client -> call ( Client :: METHOD_POST , '/account/sessions/email' , array_merge ([
'origin' => 'http://localhost' ,
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
]), [
'email' => 'jwtuser@appwrite.io' ,
'password' => 'password' ,
]);
$this -> assertEquals ( 201 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $userId , $response [ 'body' ][ 'userId' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ '$id' ]);
$session2Id = $response [ 'body' ][ '$id' ];
// Create JWT 1 for older session by ID
$response = $this -> client -> call ( Client :: METHOD_POST , '/users/' . $userId . '/jwts' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'sessionId' => $session1Id
]);
$this -> assertEquals ( 201 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'jwt' ]);
$jwt1 = $response [ 'body' ][ 'jwt' ];
// Ensure JWT 1 works
$response = $this -> client -> call ( Client :: METHOD_GET , '/account' , array_merge ([
'origin' => 'http://localhost' ,
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-jwt' => $jwt1 ,
]));
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $userId , $response [ 'body' ][ '$id' ]);
2024-07-21 13:28:23 +00:00
// Create JWT 2 for latest session using 'current' param
2024-05-28 09:25:54 +00:00
$response = $this -> client -> call ( Client :: METHOD_POST , '/users/' . $userId . '/jwts' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2024-07-21 13:28:23 +00:00
'duration' => 5 ,
'sessionId' => 'current'
2024-05-28 09:25:54 +00:00
]);
$this -> assertEquals ( 201 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertNotEmpty ( $response [ 'body' ][ 'jwt' ]);
$jwt2 = $response [ 'body' ][ 'jwt' ];
// Ensure JWT 2 works
$response = $this -> client -> call ( Client :: METHOD_GET , '/account' , array_merge ([
'origin' => 'http://localhost' ,
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-jwt' => $jwt2 ,
]));
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $userId , $response [ 'body' ][ '$id' ]);
// Wait, ensure JWT 2 no longer works because of short duration
\sleep ( 10 );
$response = $this -> client -> call ( Client :: METHOD_GET , '/account' , array_merge ([
'origin' => 'http://localhost' ,
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-jwt' => $jwt2 ,
]));
$this -> assertEquals ( 401 , $response [ 'headers' ][ 'status-code' ]);
// Delete session, ensure JWT 1 no longer works because of session missing
$response = $this -> client -> call ( Client :: METHOD_DELETE , '/users/' . $userId . '/sessions' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'sessionId' => $session1Id
]);
$this -> assertEquals ( 204 , $response [ 'headers' ][ 'status-code' ]);
$response = $this -> client -> call ( Client :: METHOD_GET , '/account' , array_merge ([
'origin' => 'http://localhost' ,
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-jwt' => $jwt1 ,
]));
$this -> assertEquals ( 401 , $response [ 'headers' ][ 'status-code' ]);
2024-07-21 13:28:23 +00:00
// Ensure JWT 0 works still even with no sessions
$response = $this -> client -> call ( Client :: METHOD_DELETE , '/users/' . $userId . '/sessions' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'sessionId' => $session2Id
]);
$this -> assertEquals ( 204 , $response [ 'headers' ][ 'status-code' ]);
$response = $this -> client -> call ( Client :: METHOD_GET , '/account' , array_merge ([
'origin' => 'http://localhost' ,
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-jwt' => $jwt0 ,
]));
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $userId , $response [ 'body' ][ '$id' ]);
2024-05-28 09:25:54 +00:00
// Cleanup after test
$response = $this -> client -> call ( Client :: METHOD_DELETE , '/users/' . $userId , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( $response [ 'headers' ][ 'status-code' ], 204 );
}
2020-01-13 18:55:57 +00:00
// TODO add test for session delete
// TODO add test for all sessions delete
2022-05-23 14:54:50 +00:00
}