From 1280e64304f8d167ff2ffd56e63f4097fc661d4c Mon Sep 17 00:00:00 2001 From: Josh Cunningham Date: Tue, 3 Jul 2018 15:01:47 -0700 Subject: [PATCH 1/2] Add pagination, docs, and better tests for Rules --- src/API/Management/Rules.php | 166 ++++++++++++++------ tests/API/Management/RulesTest.php | 235 +++++++++++++++++++++++++---- 2 files changed, 323 insertions(+), 78 deletions(-) diff --git a/src/API/Management/Rules.php b/src/API/Management/Rules.php index d3bceac1..fab40868 100644 --- a/src/API/Management/Rules.php +++ b/src/API/Management/Rules.php @@ -2,107 +2,179 @@ namespace Auth0\SDK\API\Management; -use Auth0\SDK\API\Header\ContentType; - +use Auth0\SDK\Exception\CoreException; + +/** + * Class Rules. + * Handles requests to the Rules endpoint of the v2 Management API. + * + * @package Auth0\SDK\API\Management + */ class Rules extends GenericResource { /** + * Get all Rules, by page if desired. + * Required scope: "read:rules" + * + * @param null|boolean $enabled Retrieves rules that match the value, otherwise all rules are retrieved. + * @param null|string|array $fields Fields to include or exclude from the result. + * @param null|boolean $include_fields True to include $fields, false to exclude $fields. + * @param null|integer $page Page number to get, zero-based. + * @param null|integer $per_page Number of results to get, null to return the default number. * - * @param null|string $enabled - * @param null|string|array $fields - * @param null|string|array $include_fields * @return mixed + * + * @throws \Exception Thrown by the HTTP client when there is a problem with the API call. + * + * @link https://auth0.com/docs/api/management/v2#!/Rules/get_rules */ - public function getAll($enabled = null, $fields = null, $include_fields = null) + public function getAll($enabled = null, $fields = null, $include_fields = null, $page = null, $per_page = null) { - $request = $this->apiClient->get() - ->rules(); + $params = []; + // Only return enabled Rules. if ($enabled !== null) { - $request->withParam('enabled', $enabled); + $params['enabled'] = (bool) $enabled; } - if ($fields !== null) { - if (is_array($fields)) { - $fields = implode(',', $fields); + // Fields to include or exclude from results. + if (! empty($fields)) { + $params['fields'] = is_array($fields) ? implode(',', $fields) : $fields; + if (null !== $include_fields) { + $params['include_fields'] = $include_fields; } + } - $request->withParam('fields', $fields); + // Pagination parameters. + if (null !== $page) { + $params['page'] = abs(intval($page)); } - if ($include_fields !== null) { - $request->withParam('include_fields', $include_fields); + if (null !== $per_page) { + $params['per_page'] = abs(intval($per_page)); } - return $request->call(); + return $this->apiClient->method('get') + ->addPath('rules') + ->withDictParams($params) + ->call(); } /** + * Get a single rule by ID. + * Required scope: "read:rules" + * + * @param string $id Rule ID to get. + * @param null|string|array $fields Fields to include or exclude from the result. + * @param null|boolean $include_fields True to include $fields, false to exclude $fields. * - * @param string $id - * @param null|string|array $fields - * @param null|string|array $include_fields * @return mixed + * + * @throws CoreException Thrown when $id is empty or not a string. + * @throws \Exception Thrown by the HTTP client when there is a problem with the API call. + * + * @link https://auth0.com/docs/api/management/v2#!/Rules/get_rules_by_id */ public function get($id, $fields = null, $include_fields = null) { - $request = $this->apiClient->get() - ->rules($id); - - if ($fields !== null) { - if (is_array($fields)) { - $fields = implode(',', $fields); - } - - $request->withParam('fields', $fields); + if (empty($id) || ! is_string($id)) { + throw new CoreException('Empty or invalid "id" parameter.'); } - if ($include_fields !== null) { - $request->withParam('include_fields', $include_fields); - } + $params = []; - $info = $request->call(); + // Fields to include or exclude from results. + if (! empty($fields)) { + $params['fields'] = is_array($fields) ? implode(',', $fields) : $fields; + if (null !== $include_fields) { + $params['include_fields'] = $include_fields; + } + } - return $info; + return $this->apiClient->method('get') + ->addPath('rules', $id) + ->withDictParams($params) + ->call(); } /** + * Delete a rule by ID. + * Required scope: "delete:rules" + * + * @param string $id Rule ID to delete. * - * @param string $id * @return mixed + * + * @throws CoreException Thrown when $id is empty or not a string. + * @throws \Exception Thrown by the HTTP client when there is a problem with the API call. + * + * @link https://auth0.com/docs/api/management/v2#!/Rules/delete_rules_by_id */ public function delete($id) { - return $this->apiClient->delete() - ->rules($id) + if (empty($id) || ! is_string($id)) { + throw new CoreException('Empty or invalid "id" parameter.'); + } + + return $this->apiClient->method('delete') + ->addPath('rules', $id) ->call(); } /** + * Create a new Rule. + * Required scope: "create:rules" + * + * @param array $data Dictionary array of keys and values to create a Rule. * - * @param array $data * @return mixed + * + * @throws CoreException Thrown when required "script" or "name" fields are missing or empty. + * @throws \Exception Thrown by the HTTP client when there is a problem with the API call. + * + * @link https://auth0.com/docs/api/management/v2#!/Rules/post_rules + * @link https://auth0.com/docs/rules/current#create-rules-with-the-management-api */ - public function create($data) + public function create(array $data) { - return $this->apiClient->post() - ->rules() - ->withHeader(new ContentType('application/json')) + if (empty($data['name'])) { + throw new CoreException('Missing required "name" field.'); + } + + if (empty($data['script'])) { + throw new CoreException('Missing required "script" field.'); + } + + return $this->apiClient->method('post') + ->addPath('rules') ->withBody(json_encode($data)) ->call(); } /** + * Update a Rule by ID. + * Required scope: "update:rules" + * + * @param string $id Rule ID to delete. + * @param array $data Rule data to update. * - * @param string $id - * @param array $data * @return mixed + * + * @throws CoreException Thrown when $id is empty or not a string or if $data is empty. + * @throws \Exception Thrown by the HTTP client when there is a problem with the API call. */ - public function update($id, $data) + public function update($id, array $data) { - return $this->apiClient->patch() - ->rules($id) - ->withHeader(new ContentType('application/json')) + if (empty($id) || ! is_string($id)) { + throw new CoreException('Empty or invalid "id" parameter.'); + } + + if (empty($data)) { + throw new CoreException('Empty "data" parameter; nothing to do.'); + } + + return $this->apiClient->method('patch') + ->addPath('rules', $id) ->withBody(json_encode($data)) ->call(); } diff --git a/tests/API/Management/RulesTest.php b/tests/API/Management/RulesTest.php index 7c78ebbe..5147043b 100644 --- a/tests/API/Management/RulesTest.php +++ b/tests/API/Management/RulesTest.php @@ -1,53 +1,226 @@ getEnv(); - $token = $this->getToken( - $env, [ - 'rules' => [ - 'actions' => ['create', 'read', 'delete', 'update'] - ] - ] - ); + self::$api = self::getApiStatic( 'rules', ['read', 'create', 'delete', 'update'] ); + } + + /** + * Test that get methods work as expected. + * + * @return void + * + * @throws CoreException Thrown when there is a problem with parameters passed to the method. + * @throws \Exception Thrown by the HTTP client when there is a problem with the API call. + */ + public function testGet() + { + $results = self::$api->getAll(); + $this->assertNotEmpty($results); + + // Check getting a single rule by a known ID. + $get_rule_id = $results[0]['id']; + $result = self::$api->get($get_rule_id); + $this->assertNotEmpty($result); + $this->assertEquals($results[0]['id'], $get_rule_id); - $this->domain = $env['DOMAIN']; + // Iterate through the results to see if we have enabled and disabled Rules. + $has_enabled = false; + $has_disabled = false; + foreach ($results as $result) { + if ($result['enabled']) { + $has_enabled = true; + } else { + $has_disabled = true; + } + } - $api = new Management($token, $env['DOMAIN']); + // Check enabled rules. + $enabled_results = self::$api->getAll(true); + if ($has_enabled) { + $this->assertNotEmpty($enabled_results); + } else { + $this->assertEmpty($enabled_results); + } - return $api->rules; + // Check disabled rules. + $disabled_results = self::$api->getAll(false); + if ($has_disabled) { + $this->assertNotEmpty($disabled_results); + } else { + $this->assertEmpty($disabled_results); + } } - protected function getCreateBody() + /** + * Test that get methods respect fields. + * + * @return void + * + * @throws CoreException Thrown when there is a problem with parameters passed to the method. + * @throws \Exception Thrown by the HTTP client when there is a problem with the API call. + */ + public function testGetWithFields() { - $name = 'test-create-rule'.rand(); - echo "\n-- Using rule name $name \n"; + $fields = ['id', 'name']; - return [ - 'name' => $name, - 'script' => "function (user, context, callback) {\n callback(null, user, context);\n}", - 'enabled' => true, - ]; + $fields_results = self::$api->getAll(null, $fields, true); + $this->assertNotEmpty($fields_results); + $this->assertCount(count($fields), $fields_results[0]); + + $get_rule_id = $fields_results[0]['id']; + $fields_result = self::$api->get($get_rule_id, $fields, true); + $this->assertNotEmpty($fields_result); + $this->assertCount(count($fields), $fields_result); } - protected function getUpdateBody() + + /** + * Test that getAll method respects pagination. + * + * @return void + * + * @throws \Exception Thrown by the HTTP client when there is a problem with the API call. + */ + public function testGetAllPagination() { - return [ - 'enabled' => false, - ]; + $paged_results = self::$api->getAll(null, null, null, 0, 2); + $this->assertCount(2, $paged_results); + + // Second page of 1 result. + $paged_results_2 = self::$api->getAll(null, null, null, 1, 1); + $this->assertCount(1, $paged_results_2); + $this->assertEquals($paged_results[1]['id'], $paged_results_2[0]['id']); } - protected function afterCreate($entity) + + /** + * Test that create, update, and delete methods work as expected. + * + * @return void + * + * @throws CoreException Thrown when there is a problem with parameters passed to the method. + * @throws \Exception Thrown by the HTTP client when there is a problem with the API call. + */ + public function testCreateUpdateDelete() { - $this->assertTrue($entity['enabled']); + $create_data = [ + 'name' => 'test-create-rule-'.rand(), + 'script' => 'function (user, context, callback) { callback(null, user, context); }', + 'enabled' => true, + ]; + + $create_result = self::$api->create($create_data); + $this->assertNotEmpty($create_result['id']); + $this->assertEquals($create_data['enabled'], $create_result['enabled']); + $this->assertEquals($create_data['name'], $create_result['name']); + $this->assertEquals($create_data['script'], $create_result['script']); + + $test_rule_id = $create_result['id']; + $update_data = [ + 'name' => 'test-create-rule-'.rand(), + 'script' => 'function (user, context, cb) { cb(null, user, context); }', + 'enabled' => false, + ]; + + $update_result = self::$api->update($test_rule_id, $update_data); + $this->assertEquals($update_data['enabled'], $update_result['enabled']); + $this->assertEquals($update_data['name'], $update_result['name']); + $this->assertEquals($update_data['script'], $update_result['script']); + + $delete_result = self::$api->delete($test_rule_id); + $this->assertNull($delete_result); } - protected function afterUpdate($entity) + + /** + * Test that exceptions are thrown for specific methods in specific cases. + * + * @return void + * + * @throws \Exception Thrown by the HTTP client when there is a problem with the API call. + */ + public function testExceptions() { - $this->assertNotTrue($entity['enabled']); + // Test that the get method throws an exception if the $id parameter is empty. + $caught_get_no_id_exception = false; + try { + self::$api->get(null); + } catch (CoreException $e) { + $caught_get_no_id_exception = $this->errorHasString($e, 'Empty or invalid "id" parameter'); + } + + $this->assertTrue($caught_get_no_id_exception); + + // Test that the delete method throws an exception if the $id parameter is empty. + $caught_delete_no_id_exception = false; + try { + self::$api->delete(null); + } catch (CoreException $e) { + $caught_delete_no_id_exception = $this->errorHasString($e, 'Empty or invalid "id" parameter'); + } + + $this->assertTrue($caught_delete_no_id_exception); + + // Test that the create method throws an exception if no "name" field is passed. + $caught_create_no_name_exception = false; + try { + self::$api->create(['script' => 'function(){}']); + } catch (CoreException $e) { + $caught_create_no_name_exception = $this->errorHasString($e, 'Missing required "name" field'); + } + + $this->assertTrue($caught_create_no_name_exception); + + // Test that the create method throws an exception if no "script" field is passed. + $caught_create_no_script_exception = false; + try { + self::$api->create(['name' => 'test-create-rule-'.rand()]); + } catch (CoreException $e) { + $caught_create_no_script_exception = $this->errorHasString($e, 'Missing required "script" field'); + } + + $this->assertTrue($caught_create_no_script_exception); + + // Test that the update method throws an exception if the $id parameter is empty. + $caught_update_no_id_exception = false; + try { + self::$api->update(null, []); + } catch (CoreException $e) { + $caught_update_no_id_exception = $this->errorHasString($e, 'Empty or invalid "id" parameter'); + } + + $this->assertTrue($caught_update_no_id_exception); + + // Test that the update method throws an exception if the $id parameter is empty. + $caught_update_no_data_exception = false; + try { + self::$api->update('rule_id', []); + } catch (CoreException $e) { + $caught_update_no_data_exception = $this->errorHasString($e, 'Empty "data" parameter; nothing to do'); + } + + $this->assertTrue($caught_update_no_data_exception); } } From bc74421af9ccac73614455a4150f10e68e2a25b0 Mon Sep 17 00:00:00 2001 From: Josh Cunningham Date: Fri, 6 Jul 2018 09:49:43 -0700 Subject: [PATCH 2/2] Fix error messages and test --- src/API/Management/Rules.php | 10 +++------- tests/API/Management/ClientGrantsTest.php | 2 +- tests/API/Management/RulesTest.php | 21 +++------------------ 3 files changed, 7 insertions(+), 26 deletions(-) diff --git a/src/API/Management/Rules.php b/src/API/Management/Rules.php index fab40868..6b55452e 100644 --- a/src/API/Management/Rules.php +++ b/src/API/Management/Rules.php @@ -78,7 +78,7 @@ public function getAll($enabled = null, $fields = null, $include_fields = null, public function get($id, $fields = null, $include_fields = null) { if (empty($id) || ! is_string($id)) { - throw new CoreException('Empty or invalid "id" parameter.'); + throw new CoreException('Invalid "id" parameter.'); } $params = []; @@ -113,7 +113,7 @@ public function get($id, $fields = null, $include_fields = null) public function delete($id) { if (empty($id) || ! is_string($id)) { - throw new CoreException('Empty or invalid "id" parameter.'); + throw new CoreException('Invalid "id" parameter.'); } return $this->apiClient->method('delete') @@ -166,11 +166,7 @@ public function create(array $data) public function update($id, array $data) { if (empty($id) || ! is_string($id)) { - throw new CoreException('Empty or invalid "id" parameter.'); - } - - if (empty($data)) { - throw new CoreException('Empty "data" parameter; nothing to do.'); + throw new CoreException('Invalid "id" parameter.'); } return $this->apiClient->method('patch') diff --git a/tests/API/Management/ClientGrantsTest.php b/tests/API/Management/ClientGrantsTest.php index e33f2c48..76a4d5dd 100644 --- a/tests/API/Management/ClientGrantsTest.php +++ b/tests/API/Management/ClientGrantsTest.php @@ -102,7 +102,7 @@ public function testGetWithPagination() */ public function testGetAllIncludeTotals() { - $expected_page = 1; + $expected_page = 0; $expected_count = 2; $results = self::$api->getAll(['include_totals' => true], $expected_page, $expected_count); diff --git a/tests/API/Management/RulesTest.php b/tests/API/Management/RulesTest.php index 5147043b..0fa68f28 100644 --- a/tests/API/Management/RulesTest.php +++ b/tests/API/Management/RulesTest.php @@ -168,9 +168,8 @@ public function testExceptions() try { self::$api->get(null); } catch (CoreException $e) { - $caught_get_no_id_exception = $this->errorHasString($e, 'Empty or invalid "id" parameter'); + $caught_get_no_id_exception = $this->errorHasString($e, 'Invalid "id" parameter'); } - $this->assertTrue($caught_get_no_id_exception); // Test that the delete method throws an exception if the $id parameter is empty. @@ -178,9 +177,8 @@ public function testExceptions() try { self::$api->delete(null); } catch (CoreException $e) { - $caught_delete_no_id_exception = $this->errorHasString($e, 'Empty or invalid "id" parameter'); + $caught_delete_no_id_exception = $this->errorHasString($e, 'Invalid "id" parameter'); } - $this->assertTrue($caught_delete_no_id_exception); // Test that the create method throws an exception if no "name" field is passed. @@ -190,7 +188,6 @@ public function testExceptions() } catch (CoreException $e) { $caught_create_no_name_exception = $this->errorHasString($e, 'Missing required "name" field'); } - $this->assertTrue($caught_create_no_name_exception); // Test that the create method throws an exception if no "script" field is passed. @@ -200,7 +197,6 @@ public function testExceptions() } catch (CoreException $e) { $caught_create_no_script_exception = $this->errorHasString($e, 'Missing required "script" field'); } - $this->assertTrue($caught_create_no_script_exception); // Test that the update method throws an exception if the $id parameter is empty. @@ -208,19 +204,8 @@ public function testExceptions() try { self::$api->update(null, []); } catch (CoreException $e) { - $caught_update_no_id_exception = $this->errorHasString($e, 'Empty or invalid "id" parameter'); + $caught_update_no_id_exception = $this->errorHasString($e, 'Invalid "id" parameter'); } - $this->assertTrue($caught_update_no_id_exception); - - // Test that the update method throws an exception if the $id parameter is empty. - $caught_update_no_data_exception = false; - try { - self::$api->update('rule_id', []); - } catch (CoreException $e) { - $caught_update_no_data_exception = $this->errorHasString($e, 'Empty "data" parameter; nothing to do'); - } - - $this->assertTrue($caught_update_no_data_exception); } }