REST API: Improve test coverage of single user endpoint for public data.

Add test coverage for requests of a single user resource for authors of post types registered as:

- public = true, show_in_rest = true: success without auth.
- public = true, show_in_rest = false: fail without auth.
- public = false, show_in_rest = true: success without auth.
- public = false, show_in_rest = false: fail without auth.

See #38878.
Fixes #39546.


git-svn-id: https://develop.svn.wordpress.org/trunk@39913 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
James Nylen 2017-01-16 16:21:00 +00:00
parent 14e5a08f5c
commit 79589f4195
5 changed files with 133 additions and 90 deletions

View File

@ -184,8 +184,10 @@ class WP_UnitTestCase extends PHPUnit_Framework_TestCase {
* it has a chance to do so.
*/
protected function reset_post_types() {
foreach ( get_post_types() as $pt ) {
_unregister_post_type( $pt );
foreach ( get_post_types( array(), 'objects' ) as $pt ) {
if ( empty( $pt->tests_no_auto_unregister ) ) {
_unregister_post_type( $pt->name );
}
}
create_initial_post_types();
}

View File

@ -76,7 +76,9 @@ class WP_Test_REST_Comments_Controller extends WP_Test_REST_Controller_Testcase
}
public static function wpTearDownAfterClass() {
self::delete_user( self::$superadmin_id );
self::delete_user( self::$admin_id );
self::delete_user( self::$editor_id );
self::delete_user( self::$subscriber_id );
self::delete_user( self::$author_id );

View File

@ -57,6 +57,7 @@ class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te
wp_delete_post( self::$post_id, true );
self::delete_user( self::$superadmin_id );
self::delete_user( self::$editor_id );
self::delete_user( self::$author_id );
self::delete_user( self::$contributor_id );

View File

@ -35,7 +35,9 @@ class WP_Test_REST_Tags_Controller extends WP_Test_REST_Controller_Testcase {
}
public static function wpTearDownAfterClass() {
self::delete_user( self::$superadmin );
self::delete_user( self::$administrator );
self::delete_user( self::$editor );
self::delete_user( self::$subscriber );
}

View File

@ -13,9 +13,9 @@ class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase {
protected static $superadmin;
protected static $user;
protected static $editor;
protected static $editor2;
protected static $secret_editor;
protected static $secret_editor2;
protected static $draft_editor;
protected static $authors = array();
protected static $posts = array();
protected static $site;
public static function wpSetUpBeforeClass( $factory ) {
@ -30,17 +30,38 @@ class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase {
'role' => 'editor',
'user_email' => 'editor@example.com',
) );
self::$editor2 = $factory->user->create( array(
self::$draft_editor = $factory->user->create( array(
'role' => 'editor',
'user_email' => 'editor2@example.com',
'user_email' => 'draft-editor@example.com',
) );
self::$secret_editor = $factory->user->create( array(
'role' => 'editor',
'user_email' => 'secret_editor@example.com',
foreach ( array( true, false ) as $show_in_rest ) {
foreach ( array( true, false ) as $public ) {
$post_type_name = 'r_' . json_encode( $show_in_rest ) . '_p_' . json_encode( $public );
register_post_type( $post_type_name, array(
'public' => $public,
'show_in_rest' => $show_in_rest,
'tests_no_auto_unregister' => true,
) );
self::$authors[ $post_type_name ] = $factory->user->create( array(
'role' => 'editor',
'user_email' => 'author_' . $post_type_name . '@example.com',
) );
self::$posts[ $post_type_name ] = $factory->post->create( array(
'post_type' => $post_type_name,
'post_author' => self::$authors[ $post_type_name ],
) );
}
}
self::$posts['post'] = $factory->post->create( array(
'post_type' => 'post',
'post_author' => self::$editor,
) );
self::$secret_editor2 = $factory->user->create( array(
'role' => 'editor',
'user_email' => 'secret_editor2@example.com',
self::$posts['r_true_p_true_DRAFT'] = $factory->post->create( array(
'post_type' => 'r_true_p_true',
'post_author' => self::$draft_editor,
'post_status' => 'draft',
) );
if ( is_multisite() ) {
@ -52,9 +73,18 @@ class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase {
public static function wpTearDownAfterClass() {
self::delete_user( self::$user );
self::delete_user( self::$editor );
self::delete_user( self::$editor2 );
self::delete_user( self::$secret_editor );
self::delete_user( self::$secret_editor2 );
self::delete_user( self::$draft_editor );
foreach ( self::$posts as $post ) {
wp_delete_post( $post, true );
}
foreach ( self::$authors as $author ) {
self::delete_user( $author );
}
_unregister_post_type( 'r_true_p_true' );
_unregister_post_type( 'r_true_p_false' );
_unregister_post_type( 'r_false_p_true' );
_unregister_post_type( 'r_false_p_false' );
if ( is_multisite() ) {
wpmu_delete_blog( self::$site, true );
@ -66,12 +96,6 @@ class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase {
*/
public function setUp() {
parent::setUp();
register_post_type( 'rest_public', array( 'public' => true, 'show_in_rest' => true ) );
register_post_type( 'secret_public', array( 'public' => true, 'show_in_rest' => false ) );
register_post_type( 'secret_hidden', array( 'public' => false, 'show_in_rest' => false ) );
register_post_type( 'rest_hidden', array( 'public' => false, 'show_in_rest' => true ) );
$this->endpoint = new WP_REST_Users_Controller();
}
@ -169,36 +193,14 @@ class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase {
}
public function test_get_items_unauthenticated_includes_authors_of_post_types_shown_in_rest() {
$created_posts = array();
$created_posts[] = $this->factory->post->create( array(
'post_author' => self::$user,
'post_status' => 'publish',
) );
// Expose authors if show_in_rest is true, even if the post_type is not public.
$created_posts[] = $this->factory->post->create( array(
'post_type' => 'rest_hidden',
'post_author' => self::$editor,
'post_status' => 'publish',
) );
$created_posts[] = $this->factory->post->create( array(
'post_type' => 'rest_public',
'post_author' => self::$editor2,
'post_status' => 'publish',
) );
$created_posts[] = $this->factory->post->create( array(
'post_type' => 'rest_public',
'post_author' => self::$secret_editor,
'post_status' => 'draft',
) );
$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
$response = $this->server->dispatch( $request );
$users = $response->get_data();
$public_post_types = array_values( get_post_types( array( 'show_in_rest' => true ), 'names' ) );
$rest_post_types = array_values( get_post_types( array( 'show_in_rest' => true ), 'names' ) );
foreach ( $users as $user ) {
$this->assertTrue( count_user_posts( $user['id'], $public_post_types ) > 0 );
$this->assertTrue( count_user_posts( $user['id'], $rest_post_types ) > 0 );
// Ensure we don't expose non-public data.
$this->assertArrayNotHasKey( 'capabilities', $user );
@ -213,55 +215,45 @@ class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase {
$this->assertArrayNotHasKey( 'locale', $user );
}
$this->assertTrue( in_array( self::$user, wp_list_pluck( $users, 'id' ), true ) );
$this->assertTrue( in_array( self::$editor, wp_list_pluck( $users, 'id' ), true ) );
$this->assertTrue( in_array( self::$editor2, wp_list_pluck( $users, 'id' ), true ) );
$user_ids = wp_list_pluck( $users, 'id' );
// Do not include authors of unpublished posts.
$this->assertFalse( in_array( self::$secret_editor, wp_list_pluck( $users, 'id' ), true ) );
foreach ( $created_posts as $post_id ) {
wp_delete_post( $post_id, true );
}
$this->assertTrue( in_array( self::$editor , $user_ids, true ) );
$this->assertTrue( in_array( self::$authors['r_true_p_true'] , $user_ids, true ) );
$this->assertTrue( in_array( self::$authors['r_true_p_false'], $user_ids, true ) );
$this->assertCount( 3, $user_ids );
}
public function test_get_items_unauthenticated_does_not_include_authors_of_post_types_not_shown_in_rest() {
$created_posts = array();
$created_posts[] = $this->factory->post->create( array(
'post_type' => 'secret_hidden',
'post_author' => self::$secret_editor,
'post_status' => 'publish',
) );
$created_posts[] = $this->factory->post->create( array(
'post_type' => 'secret_public',
'post_author' => self::$secret_editor2,
'post_status' => 'publish',
) );
$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$users = $response->get_data();
$user_ids = wp_list_pluck( $users, 'id' );
$this->assertFalse( in_array( self::$secret_editor, wp_list_pluck( $data, 'id' ), true ) );
$this->assertFalse( in_array( self::$secret_editor2, wp_list_pluck( $data, 'id' ), true ) );
$this->assertFalse( in_array( self::$authors['r_false_p_true'] , $user_ids, true ) );
$this->assertFalse( in_array( self::$authors['r_false_p_false'], $user_ids, true ) );
}
foreach ( $created_posts as $post_id ) {
wp_delete_post( $post_id, true );
}
public function test_get_items_unauthenticated_does_not_include_users_without_published_posts() {
$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
$response = $this->server->dispatch( $request );
$users = $response->get_data();
$user_ids = wp_list_pluck( $users, 'id' );
$this->assertFalse( in_array( self::$draft_editor, $user_ids, true ) );
$this->assertFalse( in_array( self::$user , $user_ids, true ) );
}
public function test_get_items_pagination_headers() {
wp_set_current_user( self::$user );
// Start of the index, including the six existing users.
for ( $i = 0; $i < 44; $i++ ) {
$this->factory->user->create( array(
'name' => "User {$i}",
) );
'name' => "User {$i}",
) );
}
$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
$response = $this->server->dispatch( $request );
$headers = $response->get_headers();
$this->assertEquals( 51, $headers['X-WP-Total'] );
$this->assertEquals( 53, $headers['X-WP-Total'] );
$this->assertEquals( 6, $headers['X-WP-TotalPages'] );
$next_link = add_query_arg( array(
'page' => 2,
@ -276,7 +268,7 @@ class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase {
$request->set_param( 'page', 3 );
$response = $this->server->dispatch( $request );
$headers = $response->get_headers();
$this->assertEquals( 52, $headers['X-WP-Total'] );
$this->assertEquals( 54, $headers['X-WP-Total'] );
$this->assertEquals( 6, $headers['X-WP-TotalPages'] );
$prev_link = add_query_arg( array(
'page' => 2,
@ -291,7 +283,7 @@ class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase {
$request->set_param( 'page', 6 );
$response = $this->server->dispatch( $request );
$headers = $response->get_headers();
$this->assertEquals( 52, $headers['X-WP-Total'] );
$this->assertEquals( 54, $headers['X-WP-Total'] );
$this->assertEquals( 6, $headers['X-WP-TotalPages'] );
$prev_link = add_query_arg( array(
'page' => 5,
@ -303,7 +295,7 @@ class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase {
$request->set_param( 'page', 8 );
$response = $this->server->dispatch( $request );
$headers = $response->get_headers();
$this->assertEquals( 52, $headers['X-WP-Total'] );
$this->assertEquals( 54, $headers['X-WP-Total'] );
$this->assertEquals( 6, $headers['X-WP-TotalPages'] );
$prev_link = add_query_arg( array(
'page' => 6,
@ -474,12 +466,12 @@ class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase {
public function test_get_items_offset() {
wp_set_current_user( self::$user );
// 5 users created in __construct(), plus default user.
// 7 users created in wpSetUpBeforeClass(), plus default user.
$this->factory->user->create();
$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
$request->set_param( 'offset', 1 );
$response = $this->server->dispatch( $request );
$this->assertCount( 7, $response->get_data() );
$this->assertCount( 9, $response->get_data() );
// 'offset' works with 'per_page'
$request->set_param( 'per_page', 2 );
$response = $this->server->dispatch( $request );
@ -530,6 +522,7 @@ class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase {
$id1 = $this->factory->user->create();
$id2 = $this->factory->user->create();
$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
$request->set_param( 'per_page', 20 ); // there are >10 users at this point
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertTrue( in_array( $id1, wp_list_pluck( $data, 'id' ), true ) );
@ -688,15 +681,63 @@ class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase {
$this->assertEquals( $data['extra_capabilities'], new stdClass() );
}
public function test_get_item_without_permission() {
public function test_cannot_get_item_without_permission() {
wp_set_current_user( self::$editor );
$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$user ) );
$response = $this->server->dispatch( $request );
$this->assertErrorResponse( 'rest_user_cannot_view', $response, 403 );
}
public function test_can_get_item_author_of_rest_true_public_true_unauthenticated() {
$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$authors['r_true_p_true'] ) );
$response = $this->server->dispatch( $request );
$this->assertEquals( 200, $response->get_status() );
}
public function test_can_get_item_author_of_rest_true_public_true_authenticated() {
wp_set_current_user( self::$editor );
$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$authors['r_true_p_true'] ) );
$response = $this->server->dispatch( $request );
$this->assertEquals( 200, $response->get_status() );
}
public function test_can_get_item_author_of_rest_true_public_false() {
$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$authors['r_true_p_false'] ) );
$response = $this->server->dispatch( $request );
$this->assertEquals( 200, $response->get_status() );
}
public function test_cannot_get_item_author_of_rest_false_public_true_unauthenticated() {
$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$authors['r_false_p_true'] ) );
$response = $this->server->dispatch( $request );
$this->assertErrorResponse( 'rest_user_cannot_view', $response, 401 );
}
public function test_cannot_get_item_author_of_rest_false_public_true_without_permission() {
wp_set_current_user( self::$editor );
$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$authors['r_false_p_true'] ) );
$response = $this->server->dispatch( $request );
$this->assertErrorResponse( 'rest_user_cannot_view', $response, 403 );
}
public function test_cannot_get_item_author_of_rest_false_public_false() {
$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$authors['r_false_p_false'] ) );
$response = $this->server->dispatch( $request );
$this->assertErrorResponse( 'rest_user_cannot_view', $response, 401 );
}
public function test_can_get_item_author_of_post() {
$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$editor ) );
$response = $this->server->dispatch( $request );
$this->assertEquals( 200, $response->get_status() );
}
public function test_cannot_get_item_author_of_draft() {
$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$draft_editor ) );
$response = $this->server->dispatch( $request );
$this->assertErrorResponse( 'rest_user_cannot_view', $response, 401 );
}
public function test_get_item_published_author_post() {
$this->author_id = $this->factory->user->create( array(
'role' => 'author',
@ -2166,11 +2207,6 @@ class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase {
}
public function tearDown() {
_unregister_post_type( 'rest_public' );
_unregister_post_type( 'secret_public' );
_unregister_post_type( 'secret_hidden' );
_unregister_post_type( 'rest_hidden' );
parent::tearDown();
}