From 28650fa91ca7a5725abfd8b23edda802d2ba61c6 Mon Sep 17 00:00:00 2001 From: Luciano Righetti Date: Mon, 10 Jan 2022 11:58:52 +0100 Subject: [PATCH] add: add users add/edit/delete api tests and openapi docs. --- tests/Fixture/AuthKeysFixture.php | 8 +- tests/Helper/ApiTestTrait.php | 44 ++++++++- tests/TestCase/Api/Users/AddUserApiTest.php | 77 ++++++++++++++++ .../TestCase/Api/Users/DeleteUserApiTest.php | 60 ++++++++++++ tests/TestCase/Api/Users/EditUserApiTest.php | 91 +++++++++++++++++++ .../TestCase/Api/Users/IndexUsersApiTest.php | 6 +- tests/TestCase/Api/Users/ViewUserApiTest.php | 20 ++-- 7 files changed, 287 insertions(+), 19 deletions(-) create mode 100644 tests/TestCase/Api/Users/AddUserApiTest.php create mode 100644 tests/TestCase/Api/Users/DeleteUserApiTest.php create mode 100644 tests/TestCase/Api/Users/EditUserApiTest.php diff --git a/tests/Fixture/AuthKeysFixture.php b/tests/Fixture/AuthKeysFixture.php index 8291811..802ca5c 100644 --- a/tests/Fixture/AuthKeysFixture.php +++ b/tests/Fixture/AuthKeysFixture.php @@ -14,7 +14,7 @@ class AuthKeysFixture extends TestFixture public const ADMIN_API_KEY = 'd033e22ae348aeb5660fc2140aec35850c4da997'; public const SYNC_API_KEY = '6b387ced110858dcbcda36edb044dc18f91a0894'; public const ORG_ADMIN_API_KEY = '1c4685d281d478dbcebd494158024bc3539004d0'; - public const USER_API_KEY = '12dea96fec20593566ab75692c9949596833adc9'; + public const REGULAR_USER_API_KEY = '12dea96fec20593566ab75692c9949596833adc9'; public function init(): void { @@ -57,9 +57,9 @@ class AuthKeysFixture extends TestFixture ], [ 'uuid' => $faker->uuid(), - 'authkey' => $hasher->hash(self::USER_API_KEY), - 'authkey_start' => substr(self::USER_API_KEY, 0, 4), - 'authkey_end' => substr(self::USER_API_KEY, -4), + 'authkey' => $hasher->hash(self::REGULAR_USER_API_KEY), + 'authkey_start' => substr(self::REGULAR_USER_API_KEY, 0, 4), + 'authkey_end' => substr(self::REGULAR_USER_API_KEY, -4), 'expiration' => 0, 'user_id' => UsersFixture::USER_REGULAR_USER_ID, 'comment' => '', diff --git a/tests/Helper/ApiTestTrait.php b/tests/Helper/ApiTestTrait.php index 572b7c6..21b0c8b 100644 --- a/tests/Helper/ApiTestTrait.php +++ b/tests/Helper/ApiTestTrait.php @@ -65,7 +65,7 @@ trait ApiTestTrait * @param string $method The HTTP method used to call the endpoint * @return void */ - public function validateRequest(string $endpoint, string $method = 'get'): void + public function assertRequestMatchesOpenApiSpec(string $endpoint, string $method = 'get'): void { // TODO: find a workaround to create a PSR-7 request object for validation throw NotImplementedException("Unfortunately cakephp does not save the PSR-7 request object in the test context"); @@ -78,9 +78,49 @@ trait ApiTestTrait * @param string $method The HTTP method used to call the endpoint * @return void */ - public function validateResponse(string $endpoint, string $method = 'get'): void + public function assertResponseMatchesOpenApiSpec(string $endpoint, string $method = 'get'): void { $address = new OperationAddress($endpoint, $method); $this->responseValidator->validate($address, $this->_response); } + + /** + * Validates a record exists in the database + * + * @param string $table The table name + * @param array $conditions The conditions to check + * @return void + * @throws \Exception + * @throws \Cake\Datasource\Exception\RecordNotFoundException + * + * @see https://book.cakephp.org/4/en/orm-query-builder.html + */ + public function assertDbRecordExists(string $table, array $conditions): void + { + $record = $this->getTableLocator()->get($table)->find()->where($conditions)->first(); + if (!$record) { + throw new \PHPUnit\Framework\AssertionFailedError("Record not found in table '$table' with conditions: " . json_encode($conditions)); + } + $this->assertNotEmpty($record); + } + + /** + * Validates a record do notexists in the database + * + * @param string $table The table name + * @param array $conditions The conditions to check + * @return void + * @throws \Exception + * @throws \Cake\Datasource\Exception\RecordNotFoundException + * + * @see https://book.cakephp.org/4/en/orm-query-builder.html + */ + public function assertDbRecordNotExists(string $table, array $conditions): void + { + $record = $this->getTableLocator()->get($table)->find()->where($conditions)->first(); + if ($record) { + throw new \PHPUnit\Framework\AssertionFailedError("Record found in table '$table' with conditions: " . json_encode($conditions)); + } + $this->assertEmpty($record); + } } diff --git a/tests/TestCase/Api/Users/AddUserApiTest.php b/tests/TestCase/Api/Users/AddUserApiTest.php new file mode 100644 index 0000000..b3d85a3 --- /dev/null +++ b/tests/TestCase/Api/Users/AddUserApiTest.php @@ -0,0 +1,77 @@ +initializeValidator(APP . '../webroot/docs/openapi.yaml'); + } + + public function testAddUser(): void + { + $this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY); + $this->post( + self::ENDPOINT, + [ + 'individual_id' => UsersFixture::USER_REGULAR_USER_ID, + 'organisation_id' => OrganisationsFixture::ORGANISATION_A_ID, + 'role_id' => RolesFixture::ROLE_REGULAR_USER_ID, + 'disabled' => false, + 'username' => 'test', + 'password' => 'Password123456!', + ] + ); + + $this->assertResponseOk(); + $this->assertResponseContains('"username": "test"'); + $this->assertDbRecordExists('Users', ['username' => 'test']); + //TODO: $this->assertRequestMatchesOpenApiSpec(); + $this->assertResponseMatchesOpenApiSpec(self::ENDPOINT, 'post'); + } + + public function testAddUserNotAllowedToRegularUser(): void + { + $this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY); + $this->post( + self::ENDPOINT, + [ + 'individual_id' => UsersFixture::USER_REGULAR_USER_ID, + 'organisation_id' => OrganisationsFixture::ORGANISATION_A_ID, + 'role_id' => RolesFixture::ROLE_REGULAR_USER_ID, + 'disabled' => false, + 'username' => 'test', + 'password' => 'Password123456!' + ] + ); + + $this->assertResponseCode(405); + $this->assertDbRecordNotExists('Users', ['username' => 'test']); + //TODO: $this->assertRequestMatchesOpenApiSpec(); + $this->assertResponseMatchesOpenApiSpec(self::ENDPOINT, 'post'); + } +} diff --git a/tests/TestCase/Api/Users/DeleteUserApiTest.php b/tests/TestCase/Api/Users/DeleteUserApiTest.php new file mode 100644 index 0000000..dad2d1f --- /dev/null +++ b/tests/TestCase/Api/Users/DeleteUserApiTest.php @@ -0,0 +1,60 @@ +initializeValidator(APP . '../webroot/docs/openapi.yaml'); + } + + public function testDeleteUser(): void + { + $this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY); + $url = sprintf('%s/%d', self::ENDPOINT, UsersFixture::USER_REGULAR_USER_ID); + $this->delete($url); + + $this->assertResponseOk(); + $this->assertDbRecordNotExists('Users', ['id' => UsersFixture::USER_REGULAR_USER_ID]); + //TODO: $this->assertRequestMatchesOpenApiSpec(); + $this->assertResponseMatchesOpenApiSpec($url, 'delete'); + $this->addWarning('TODO: CRUDComponent::delete() sets some view variables, does not take into account `isRest()`, fix it.'); + } + + public function testDeleteUserNotAllowedToRegularUser(): void + { + $this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY); + $url = sprintf('%s/%d', self::ENDPOINT, UsersFixture::USER_ORG_ADMIN_ID); + $this->delete($url); + + $this->assertResponseCode(405); + $this->assertDbRecordExists('Users', ['id' => UsersFixture::USER_ORG_ADMIN_ID]); + //TODO: $this->assertRequestMatchesOpenApiSpec(); + $this->assertResponseMatchesOpenApiSpec($url, 'delete'); + $this->addWarning('TODO: CRUDComponent::delete() sets some view variables, does not take into account `isRest()`, fix it.'); + } +} diff --git a/tests/TestCase/Api/Users/EditUserApiTest.php b/tests/TestCase/Api/Users/EditUserApiTest.php new file mode 100644 index 0000000..6c94877 --- /dev/null +++ b/tests/TestCase/Api/Users/EditUserApiTest.php @@ -0,0 +1,91 @@ +initializeValidator(APP . '../webroot/docs/openapi.yaml'); + } + + public function testEditUser(): void + { + $this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY); + $url = sprintf('%s/%d', self::ENDPOINT, UsersFixture::USER_REGULAR_USER_ID); + $this->put( + $url, + [ + 'id' => UsersFixture::USER_REGULAR_USER_ID, + 'role_id' => RolesFixture::ROLE_ORG_ADMIN_ID, + ] + ); + + $this->assertResponseOk(); + $this->assertDbRecordExists('Users', [ + 'id' => UsersFixture::USER_REGULAR_USER_ID, + 'role_id' => RolesFixture::ROLE_ORG_ADMIN_ID + ]); + //TODO: $this->assertRequestMatchesOpenApiSpec(); + $this->assertResponseMatchesOpenApiSpec($url, 'put'); + } + + public function testEditRoleNotAllowedToRegularUser(): void + { + $this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY); + $this->put( + self::ENDPOINT, + [ + 'role_id' => RolesFixture::ROLE_ADMIN_ID, + ] + ); + + $this->assertDbRecordNotExists('Users', [ + 'id' => UsersFixture::USER_REGULAR_USER_ID, + 'role_id' => RolesFixture::ROLE_ADMIN_ID + ]); + //TODO: $this->assertRequestMatchesOpenApiSpec(); + $this->assertResponseMatchesOpenApiSpec(self::ENDPOINT, 'put'); + } + + public function testEditSelfUser(): void + { + $this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY); + $this->put( + self::ENDPOINT, + [ + 'username' => 'test', + ] + ); + + $this->assertDbRecordExists('Users', [ + 'id' => UsersFixture::USER_REGULAR_USER_ID, + 'username' => 'test' + ]); + //TODO: $this->assertRequestMatchesOpenApiSpec(); + $this->assertResponseMatchesOpenApiSpec(self::ENDPOINT, 'put'); + } +} diff --git a/tests/TestCase/Api/Users/IndexUsersApiTest.php b/tests/TestCase/Api/Users/IndexUsersApiTest.php index 46e615d..6721e77 100644 --- a/tests/TestCase/Api/Users/IndexUsersApiTest.php +++ b/tests/TestCase/Api/Users/IndexUsersApiTest.php @@ -30,14 +30,14 @@ class IndexUsersApiTest extends TestCase $this->initializeValidator(APP . '../webroot/docs/openapi.yaml'); } - public function testIndex(): void + public function testIndexUsers(): void { $this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY); $this->get(self::ENDPOINT); $this->assertResponseOk(); $this->assertResponseContains(sprintf('"username": "%s"', UsersFixture::USER_ADMIN_USERNAME)); - // TODO: $this->validateRequest() - $this->validateResponse(self::ENDPOINT); + // TODO: $this->assertRequestMatchesOpenApiSpec(); + $this->assertResponseMatchesOpenApiSpec(self::ENDPOINT); } } diff --git a/tests/TestCase/Api/Users/ViewUserApiTest.php b/tests/TestCase/Api/Users/ViewUserApiTest.php index 7c5a346..34c9c62 100644 --- a/tests/TestCase/Api/Users/ViewUserApiTest.php +++ b/tests/TestCase/Api/Users/ViewUserApiTest.php @@ -30,26 +30,26 @@ class ViewUserApiTest extends TestCase $this->initializeValidator(APP . '../webroot/docs/openapi.yaml'); } - public function testViewMe(): void + public function testViewMyUser(): void { $this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY); $this->get(self::ENDPOINT); $this->assertResponseOk(); $this->assertResponseContains(sprintf('"username": "%s"', UsersFixture::USER_ADMIN_USERNAME)); - // TODO: $this->validateRequest() - $this->validateResponse(self::ENDPOINT); + // TODO: $this->assertRequestMatchesOpenApiSpec(); + $this->assertResponseMatchesOpenApiSpec(self::ENDPOINT); } - - public function testViewById(): void + + public function testViewUserById(): void { $this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY); - $url = sprintf('%s/%d', self::ENDPOINT, UsersFixture::USER_ADMIN_ID); + $url = sprintf('%s/%d', self::ENDPOINT, UsersFixture::USER_REGULAR_USER_ID); $this->get($url); - + $this->assertResponseOk(); - $this->assertResponseContains(sprintf('"username": "%s"', UsersFixture::USER_ADMIN_USERNAME)); - // TODO: $this->validateRequest() - $this->validateResponse($url); + $this->assertResponseContains(sprintf('"username": "%s"', UsersFixture::USER_REGULAR_USER_USERNAME)); + // TODO: $this->assertRequestMatchesOpenApiSpec(); + $this->assertResponseMatchesOpenApiSpec($url); } }