Privacy: Add unit tests for exporting and erasing personal data.
Props birgire, garrett-eclipse, desrosj. Fixes #43438. git-svn-id: https://develop.svn.wordpress.org/trunk@44909 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
40ff06c083
commit
152e9d2b8f
@ -119,6 +119,8 @@ abstract class WP_Ajax_UnitTestCase extends WP_UnitTestCase {
|
|||||||
'delete-theme',
|
'delete-theme',
|
||||||
'install-theme',
|
'install-theme',
|
||||||
'get-post-thumbnail-html',
|
'get-post-thumbnail-html',
|
||||||
|
'wp-privacy-export-personal-data',
|
||||||
|
'wp-privacy-erase-personal-data',
|
||||||
);
|
);
|
||||||
|
|
||||||
public static function setUpBeforeClass() {
|
public static function setUpBeforeClass() {
|
||||||
|
814
tests/phpunit/tests/ajax/PrivacyErasePersonalData.php
Executable file
814
tests/phpunit/tests/ajax/PrivacyErasePersonalData.php
Executable file
@ -0,0 +1,814 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Testing Ajax handler for erasing personal data.
|
||||||
|
*
|
||||||
|
* @package WordPress\UnitTests
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests_Ajax_PrivacyExportPersonalData class.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @group ajax
|
||||||
|
* @group privacy
|
||||||
|
*
|
||||||
|
* @covers ::wp_ajax_wp_privacy_erase_personal_data
|
||||||
|
*/
|
||||||
|
class Tests_Ajax_PrivacyErasePersonalData extends WP_Ajax_UnitTestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User Request ID.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var int $request_id
|
||||||
|
*/
|
||||||
|
protected static $request_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User Request Email.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var string $request_email
|
||||||
|
*/
|
||||||
|
protected static $request_email;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ajax Action.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var string $action
|
||||||
|
*/
|
||||||
|
protected static $action;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Eraser Index.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var int $eraser
|
||||||
|
*/
|
||||||
|
protected static $eraser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Eraser Key.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var string $eraser_key
|
||||||
|
*/
|
||||||
|
protected static $eraser_key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Eraser Friendly Name.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var string $eraser_friendly_name
|
||||||
|
*/
|
||||||
|
protected static $eraser_friendly_name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page Index.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var int $page
|
||||||
|
*/
|
||||||
|
protected static $page;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last response parsed.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var array $_last_response_parsed
|
||||||
|
*/
|
||||||
|
protected $_last_response_parsed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array key in the test eraser to unset.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var string $key_to_unset
|
||||||
|
*/
|
||||||
|
protected $key_to_unset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A value to change the test eraser callback to.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var string $new_callback_value
|
||||||
|
*/
|
||||||
|
protected $new_callback_value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create user erase request fixtures.
|
||||||
|
*
|
||||||
|
* @param WP_UnitTest_Factory $factory Factory.
|
||||||
|
*/
|
||||||
|
public static function wpSetUpBeforeClass( $factory ) {
|
||||||
|
self::$request_email = 'requester@example.com';
|
||||||
|
self::$request_id = wp_create_user_request( self::$request_email, 'remove_personal_data' );
|
||||||
|
self::$action = 'wp-privacy-erase-personal-data';
|
||||||
|
self::$eraser = 1;
|
||||||
|
self::$eraser_key = 'custom-eraser';
|
||||||
|
self::$eraser_friendly_name = 'Custom Eraser';
|
||||||
|
self::$page = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a custom personal data eraser.
|
||||||
|
*/
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->key_to_unset = '';
|
||||||
|
|
||||||
|
// Make sure the erasers response is not modified and avoid sending emails.
|
||||||
|
remove_all_filters( 'wp_privacy_personal_data_erasure_page' );
|
||||||
|
remove_all_actions( 'wp_privacy_personal_data_erased' );
|
||||||
|
|
||||||
|
// Only use our custom privacy personal data eraser.
|
||||||
|
remove_all_filters( 'wp_privacy_personal_data_erasers' );
|
||||||
|
add_filter( 'wp_privacy_personal_data_erasers', array( $this, 'register_custom_personal_data_eraser' ) );
|
||||||
|
|
||||||
|
$this->_setRole( 'administrator' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up after each test method.
|
||||||
|
*/
|
||||||
|
public function tearDown() {
|
||||||
|
remove_filter( 'wp_privacy_personal_data_erasers', array( $this, 'register_custom_personal_data_eraser' ) );
|
||||||
|
$this->new_callback_value = '';
|
||||||
|
|
||||||
|
parent::tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method for changing the test eraser's callback function.
|
||||||
|
*
|
||||||
|
* @param string|array $callback New test eraser callback index value.
|
||||||
|
*/
|
||||||
|
protected function _set_eraser_callback( $callback ) {
|
||||||
|
$this->new_callback_value = $callback;
|
||||||
|
add_filter( 'wp_privacy_personal_data_erasers', array( $this, 'filter_eraser_callback_value' ), 20 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the test eraser callback to a specified value.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @param array $erasers List of data erasers.
|
||||||
|
*
|
||||||
|
* @return array $erasersList of data erasers.
|
||||||
|
*/
|
||||||
|
public function filter_eraser_callback_value( $erasers ) {
|
||||||
|
$erasers[ self::$eraser_key ]['callback'] = $this->new_callback_value;
|
||||||
|
|
||||||
|
return $erasers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method for unsetting an array index in the test eraser.
|
||||||
|
*
|
||||||
|
* @param string|bool $key Test eraser key to unset.
|
||||||
|
*/
|
||||||
|
protected function _unset_eraser_key( $key ) {
|
||||||
|
$this->key_to_unset = $key;
|
||||||
|
add_filter( 'wp_privacy_personal_data_erasers', array( $this, 'filter_unset_eraser_index' ), 20 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsets an array key in the test eraser.
|
||||||
|
*
|
||||||
|
* If the key is false, the eraser is set to false.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @param array $erasers Erasers.
|
||||||
|
*
|
||||||
|
* @return array $erasers Erasers.
|
||||||
|
*/
|
||||||
|
public function filter_unset_eraser_index( $erasers ) {
|
||||||
|
if ( false === $this->key_to_unset ) {
|
||||||
|
$erasers[ self::$eraser_key ] = false;
|
||||||
|
} elseif ( ! empty( $this->key_to_unset ) ) {
|
||||||
|
unset( $erasers[ self::$eraser_key ][ $this->key_to_unset ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $erasers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method for erasing a key from the eraser response.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @param array $key Response key to unset.
|
||||||
|
*/
|
||||||
|
protected function _unset_response_key( $key ) {
|
||||||
|
$this->key_to_unset = $key;
|
||||||
|
$this->_set_eraser_callback( array( $this, 'filter_unset_response_index' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsets an array index in a response.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @param string $email_address The requester's email address.
|
||||||
|
* @param int $page Page number.
|
||||||
|
*
|
||||||
|
* @return array $return Export data.
|
||||||
|
*/
|
||||||
|
public function filter_unset_response_index( $email_address, $page = 1 ) {
|
||||||
|
$response = $this->callback_personal_data_eraser( $email_address, $page );
|
||||||
|
|
||||||
|
if ( ! empty( $this->key_to_unset ) ) {
|
||||||
|
unset( $response[ $this->key_to_unset ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the request ID is missing.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @ticket 43438
|
||||||
|
*/
|
||||||
|
public function test_error_when_missing_request_id() {
|
||||||
|
$this->assertNotWPError( self::$request_id );
|
||||||
|
|
||||||
|
// Set up a request.
|
||||||
|
$this->_make_ajax_call(
|
||||||
|
array(
|
||||||
|
'id' => null, // Missing request ID.
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'Missing request ID.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the request ID is less than 1.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @ticket 43438
|
||||||
|
*/
|
||||||
|
public function test_error_when_request_id_invalid() {
|
||||||
|
$this->assertNotWPError( self::$request_id );
|
||||||
|
|
||||||
|
// Set up a request.
|
||||||
|
$this->_make_ajax_call(
|
||||||
|
array(
|
||||||
|
'id' => -1, // Invalid request ID.
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'Invalid request ID.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the current user is missing required capabilities.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @ticket 43438
|
||||||
|
*/
|
||||||
|
public function test_error_when_current_user_missing_required_capabilities() {
|
||||||
|
$this->_setRole( 'author' );
|
||||||
|
|
||||||
|
$this->assertFalse( current_user_can( 'erase_others_personal_data' ) );
|
||||||
|
$this->assertFalse( current_user_can( 'delete_users' ) );
|
||||||
|
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'Sorry, you are not allowed to perform this action.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the nonce does not validate.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_failure_with_invalid_nonce() {
|
||||||
|
$this->setExpectedException( 'WPAjaxDieStopException', '-1' );
|
||||||
|
|
||||||
|
$this->_make_ajax_call(
|
||||||
|
array(
|
||||||
|
'security' => 'invalid-nonce',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the request type is incorrect.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_incorrect_request_type() {
|
||||||
|
$request_id = wp_create_user_request(
|
||||||
|
'export-request@example.com',
|
||||||
|
'export_personal_data' // Incorrect request type, expects 'remove_personal_data'.
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->_make_ajax_call(
|
||||||
|
array(
|
||||||
|
'security' => wp_create_nonce( 'wp-privacy-erase-personal-data-' . $request_id ),
|
||||||
|
'id' => $request_id,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'Invalid request type.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the request email is invalid.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_invalid_email() {
|
||||||
|
wp_update_post(
|
||||||
|
array(
|
||||||
|
'ID' => self::$request_id,
|
||||||
|
'post_title' => '', // Invalid requester's email address.
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'Invalid email address in request.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the eraser index is missing.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_missing_eraser_index() {
|
||||||
|
$this->_make_ajax_call(
|
||||||
|
array(
|
||||||
|
'eraser' => null, // Missing eraser index.
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'Missing eraser index.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the page index is missing.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_missing_page_index() {
|
||||||
|
$this->_make_ajax_call(
|
||||||
|
array(
|
||||||
|
'page' => null, // Missing page index.
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'Missing page index.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the eraser index is negative.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_negative_eraser_index() {
|
||||||
|
$this->_make_ajax_call(
|
||||||
|
array(
|
||||||
|
'eraser' => -1, // Negative eraser index.
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'Eraser index cannot be less than one.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the eraser index is out of range.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_eraser_index_out_of_range() {
|
||||||
|
$this->_make_ajax_call(
|
||||||
|
array(
|
||||||
|
'eraser' => PHP_INT_MAX, // Out of range eraser index.
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'Eraser index is out of range.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the page index is less than one.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_page_index_less_than_one() {
|
||||||
|
$this->_make_ajax_call(
|
||||||
|
array(
|
||||||
|
'page' => 0, // Page index less than one.
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'Page index cannot be less than one.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when an eraser is not an array.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_eraser_not_array() {
|
||||||
|
$this->_unset_eraser_key( false );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame(
|
||||||
|
sprintf(
|
||||||
|
'Expected an array describing the eraser at index %s.',
|
||||||
|
self::$eraser
|
||||||
|
),
|
||||||
|
$this->_last_response_parsed['data']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when an eraser is missing a friendly name.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_eraser_missing_friendly_name() {
|
||||||
|
$this->_unset_eraser_key( 'eraser_friendly_name' );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame(
|
||||||
|
sprintf(
|
||||||
|
'Eraser array at index %s does not include a friendly name.',
|
||||||
|
self::$eraser
|
||||||
|
),
|
||||||
|
$this->_last_response_parsed['data']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when an eraser is missing a callback.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_eraser_missing_callback() {
|
||||||
|
$this->_unset_eraser_key( 'callback' );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame(
|
||||||
|
sprintf(
|
||||||
|
'Eraser does not include a callback: %s.',
|
||||||
|
self::$eraser_friendly_name
|
||||||
|
),
|
||||||
|
$this->_last_response_parsed['data']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when an eraser, at a given index, has an invalid callback.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_eraser_index_invalid_callback() {
|
||||||
|
$this->_set_eraser_callback( false );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame(
|
||||||
|
sprintf(
|
||||||
|
'Eraser callback is not valid: %s.',
|
||||||
|
self::$eraser_friendly_name
|
||||||
|
),
|
||||||
|
$this->_last_response_parsed['data']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when an eraser, at a given index, is missing an array response.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_eraser_index_invalid_response() {
|
||||||
|
$this->_set_eraser_callback( '__return_null' );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame(
|
||||||
|
sprintf(
|
||||||
|
'Did not receive array from %1$s eraser (index %2$d).',
|
||||||
|
self::$eraser_friendly_name,
|
||||||
|
self::$eraser
|
||||||
|
),
|
||||||
|
$this->_last_response_parsed['data']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when missing an items_removed index.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_eraser_items_removed_missing() {
|
||||||
|
$this->_unset_response_key( 'items_removed' );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame(
|
||||||
|
sprintf(
|
||||||
|
'Expected items_removed key in response array from %1$s eraser (index %2$d).',
|
||||||
|
self::$eraser_friendly_name,
|
||||||
|
self::$eraser
|
||||||
|
),
|
||||||
|
$this->_last_response_parsed['data']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when missing an items_retained index.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_eraser_items_retained_missing() {
|
||||||
|
$this->_unset_response_key( 'items_retained' );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame(
|
||||||
|
sprintf(
|
||||||
|
'Expected items_retained key in response array from %1$s eraser (index %2$d).',
|
||||||
|
self::$eraser_friendly_name,
|
||||||
|
self::$eraser
|
||||||
|
),
|
||||||
|
$this->_last_response_parsed['data']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when missing a messages index.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_eraser_messages_missing() {
|
||||||
|
$this->_unset_response_key( 'messages' );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame(
|
||||||
|
sprintf(
|
||||||
|
'Expected messages key in response array from %1$s eraser (index %2$d).',
|
||||||
|
self::$eraser_friendly_name,
|
||||||
|
self::$eraser
|
||||||
|
),
|
||||||
|
$this->_last_response_parsed['data']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the messages index is not an array.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_eraser_messages_not_array() {
|
||||||
|
$this->_set_eraser_callback( array( $this, 'filter_response_messages_invalid' ) );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame(
|
||||||
|
sprintf(
|
||||||
|
'Expected messages key to reference an array in response array from %1$s eraser (index %2$d).',
|
||||||
|
self::$eraser_friendly_name,
|
||||||
|
self::$eraser
|
||||||
|
),
|
||||||
|
$this->_last_response_parsed['data']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the messages index to an invalid value (not an array).
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @param string $email_address The requester's email address.
|
||||||
|
* @param int $page Page number.
|
||||||
|
*
|
||||||
|
* @return array $return Export data.
|
||||||
|
*/
|
||||||
|
public function filter_response_messages_invalid( $email_address, $page = 1 ) {
|
||||||
|
$response = $this->callback_personal_data_eraser( $email_address, $page );
|
||||||
|
$response['messages'] = true;
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when an eraser is missing 'done' in array response.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_eraser_missing_done_response() {
|
||||||
|
$this->_unset_response_key( 'done' );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame(
|
||||||
|
sprintf(
|
||||||
|
'Expected done flag in response array from %1$s eraser (index %2$d).',
|
||||||
|
self::$eraser_friendly_name,
|
||||||
|
self::$eraser
|
||||||
|
),
|
||||||
|
$this->_last_response_parsed['data']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should successfully send erasers response data when the current user has the required
|
||||||
|
* capabilities.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @ticket 43438
|
||||||
|
*/
|
||||||
|
public function test_success_when_current_user_has_required_capabilities() {
|
||||||
|
$this->assertTrue( current_user_can( 'erase_others_personal_data' ) );
|
||||||
|
$this->assertTrue( current_user_can( 'delete_users' ) );
|
||||||
|
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertSame(
|
||||||
|
sprintf( 'A message regarding retained data for %s.', self::$request_email ),
|
||||||
|
$this->_last_response_parsed['data']['messages'][0]
|
||||||
|
);
|
||||||
|
$this->assertTrue( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertTrue( $this->_last_response_parsed['data']['items_removed'] );
|
||||||
|
$this->assertTrue( $this->_last_response_parsed['data']['items_retained'] );
|
||||||
|
$this->assertTrue( $this->_last_response_parsed['data']['done'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should successfully send erasers response data when no items to erase.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @ticket 43438
|
||||||
|
*/
|
||||||
|
public function test_success_when_no_items_to_erase() {
|
||||||
|
|
||||||
|
$this->_make_ajax_call( array( 'page' => 2 ) );
|
||||||
|
|
||||||
|
$this->assertTrue( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['data']['items_removed'] );
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['data']['items_retained'] );
|
||||||
|
$this->assertEmpty( $this->_last_response_parsed['data']['messages'] );
|
||||||
|
$this->assertTrue( $this->_last_response_parsed['data']['done'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that the function's output should be filterable with the `wp_privacy_personal_data_erasure_page` filter.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_output_should_be_filterable() {
|
||||||
|
add_filter( 'wp_privacy_personal_data_erasure_page', array( $this, 'filter_eraser_data_response' ), 20, 6 );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$expected_new_index = self::$request_email . '-' . self::$request_id . '-' . self::$eraser_key;
|
||||||
|
|
||||||
|
$this->assertTrue( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'filtered removed', $this->_last_response_parsed['data']['items_removed'] );
|
||||||
|
$this->assertSame( 'filtered retained', $this->_last_response_parsed['data']['items_retained'] );
|
||||||
|
$this->assertSame( array( 'filtered messages' ), $this->_last_response_parsed['data']['messages'] );
|
||||||
|
$this->assertSame( 'filtered done', $this->_last_response_parsed['data']['done'] );
|
||||||
|
$this->assertSame( $expected_new_index, $this->_last_response_parsed['data']['new_index'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the eraser response.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @param array $response The personal data for the given eraser and page.
|
||||||
|
* @param int $eraser_index The index of the eraser that provided this data.
|
||||||
|
* @param string $email_address The email address associated with this personal data.
|
||||||
|
* @param int $page The page for this response.
|
||||||
|
* @param int $request_id The privacy request post ID associated with this request.
|
||||||
|
* @param string $eraser_key The key (slug) of the eraser that provided this data.
|
||||||
|
*
|
||||||
|
* @return array Filtered erase response.
|
||||||
|
*/
|
||||||
|
public function filter_eraser_data_response( $response, $eraser_index, $email_address, $page, $request_id, $eraser_key ) {
|
||||||
|
$response['items_removed'] = 'filtered removed';
|
||||||
|
$response['items_retained'] = 'filtered retained';
|
||||||
|
$response['messages'] = array( 'filtered messages' );
|
||||||
|
$response['done'] = 'filtered done';
|
||||||
|
$response['new_index'] = $email_address . '-' . $request_id . '-' . $eraser_key;
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register handler for a custom personal data eraser.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @param array $erasers An array of personal data erasers.
|
||||||
|
*
|
||||||
|
* @return array $erasers An array of personal data erasers.
|
||||||
|
*/
|
||||||
|
public function register_custom_personal_data_eraser( $erasers ) {
|
||||||
|
$erasers[ self::$eraser_key ] = array(
|
||||||
|
'eraser_friendly_name' => self::$eraser_friendly_name,
|
||||||
|
'callback' => array( $this, 'callback_personal_data_eraser' ),
|
||||||
|
);
|
||||||
|
return $erasers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom Personal Data Eraser.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @param string $email_address The comment author email address.
|
||||||
|
* @param int $page Page number.
|
||||||
|
*
|
||||||
|
* @return array $return Erase data.
|
||||||
|
*/
|
||||||
|
public function callback_personal_data_eraser( $email_address, $page = 1 ) {
|
||||||
|
if ( 1 === $page ) {
|
||||||
|
return array(
|
||||||
|
'items_removed' => true,
|
||||||
|
'items_retained' => true,
|
||||||
|
'messages' => array( sprintf( 'A message regarding retained data for %s.', $email_address ) ),
|
||||||
|
'done' => true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'items_removed' => false,
|
||||||
|
'items_retained' => false,
|
||||||
|
'messages' => array(),
|
||||||
|
'done' => true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function for ajax handler.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @param array $args Ajax request arguments.
|
||||||
|
*/
|
||||||
|
protected function _make_ajax_call( $args = array() ) {
|
||||||
|
$this->_last_response_parsed = null;
|
||||||
|
$this->_last_response = '';
|
||||||
|
|
||||||
|
$defaults = array(
|
||||||
|
'action' => self::$action,
|
||||||
|
'security' => wp_create_nonce( self::$action . '-' . self::$request_id ),
|
||||||
|
'page' => self::$page,
|
||||||
|
'id' => self::$request_id,
|
||||||
|
'eraser' => self::$eraser,
|
||||||
|
);
|
||||||
|
|
||||||
|
$_POST = wp_parse_args( $args, $defaults );
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->_handleAjax( self::$action );
|
||||||
|
} catch ( WPAjaxDieContinueException $e ) {
|
||||||
|
unset( $e );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $this->_last_response ) {
|
||||||
|
$this->_last_response_parsed = json_decode( $this->_last_response, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
818
tests/phpunit/tests/ajax/PrivacyExportPersonalData.php
Executable file
818
tests/phpunit/tests/ajax/PrivacyExportPersonalData.php
Executable file
@ -0,0 +1,818 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Testing Ajax handler for exporting personal data.
|
||||||
|
*
|
||||||
|
* @package WordPress\UnitTests
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests_Ajax_PrivacyExportPersonalData class.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @group ajax
|
||||||
|
* @group privacy
|
||||||
|
*
|
||||||
|
* @covers ::wp_ajax_wp_privacy_export_personal_data
|
||||||
|
*/
|
||||||
|
class Tests_Ajax_PrivacyExportPersonalData extends WP_Ajax_UnitTestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User Request ID.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var int $request_id
|
||||||
|
*/
|
||||||
|
protected static $request_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User Request Email.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var string $request_email
|
||||||
|
*/
|
||||||
|
protected static $request_email;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ajax Action.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var string $action
|
||||||
|
*/
|
||||||
|
protected static $action;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exporter Index.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var int $exporter
|
||||||
|
*/
|
||||||
|
protected static $exporter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exporter Key.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var string $exporter_key
|
||||||
|
*/
|
||||||
|
protected static $exporter_key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exporter Friendly Name.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var string $exporter_friendly_name
|
||||||
|
*/
|
||||||
|
protected static $exporter_friendly_name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page Index.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var int $page
|
||||||
|
*/
|
||||||
|
protected static $page;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send As Email.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var bool $send_as_email
|
||||||
|
*/
|
||||||
|
protected static $send_as_email;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last response parsed.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var array $_last_response_parsed
|
||||||
|
*/
|
||||||
|
protected $_last_response_parsed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array key in the test exporter to unset.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var string $key_to_unset
|
||||||
|
*/
|
||||||
|
protected $key_to_unset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A value to change the test exporter callback to.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @var string $new_callback_value
|
||||||
|
*/
|
||||||
|
protected $new_callback_value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create user export request fixtures.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @param WP_UnitTest_Factory $factory Factory.
|
||||||
|
*/
|
||||||
|
public static function wpSetUpBeforeClass( $factory ) {
|
||||||
|
self::$request_email = 'requester@example.com';
|
||||||
|
self::$request_id = wp_create_user_request( self::$request_email, 'export_personal_data' );
|
||||||
|
self::$action = 'wp-privacy-export-personal-data';
|
||||||
|
self::$exporter = 1;
|
||||||
|
self::$exporter_key = 'custom-exporter';
|
||||||
|
self::$exporter_friendly_name = 'Custom Exporter';
|
||||||
|
self::$page = 1;
|
||||||
|
self::$send_as_email = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup before each test method.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->key_to_unset = '';
|
||||||
|
$this->new_callback_value = '';
|
||||||
|
|
||||||
|
// Make sure the exporter response is not modified and avoid e.g. writing export file to disk.
|
||||||
|
remove_all_filters( 'wp_privacy_personal_data_export_page' );
|
||||||
|
|
||||||
|
// Only use our custom privacy personal data exporter.
|
||||||
|
remove_all_filters( 'wp_privacy_personal_data_exporters' );
|
||||||
|
add_filter( 'wp_privacy_personal_data_exporters', array( $this, 'filter_register_custom_personal_data_exporter' ) );
|
||||||
|
|
||||||
|
$this->_setRole( 'administrator' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up after each test method.
|
||||||
|
*/
|
||||||
|
public function tearDown() {
|
||||||
|
remove_filter( 'wp_privacy_personal_data_exporters', array( $this, 'filter_register_custom_personal_data_exporter' ) );
|
||||||
|
|
||||||
|
parent::tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method for changing the test exporter's callback function.
|
||||||
|
*
|
||||||
|
* @param string|array $callback New test exporter callback function.
|
||||||
|
*/
|
||||||
|
protected function _set_exporter_callback( $callback ) {
|
||||||
|
$this->new_callback_value = $callback;
|
||||||
|
add_filter( 'wp_privacy_personal_data_exporters', array( $this, 'filter_exporter_callback_value' ), 20 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the test exporter callback to a specified value.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @param array $exporters List of data exporters.
|
||||||
|
* @return array $exporters List of data exporters.
|
||||||
|
*/
|
||||||
|
public function filter_exporter_callback_value( $exporters ) {
|
||||||
|
$exporters[ self::$exporter_key ]['callback'] = $this->new_callback_value;
|
||||||
|
|
||||||
|
return $exporters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method for unsetting an array index in the test exporter.
|
||||||
|
*
|
||||||
|
* @param string $key Test exporter key to unset.
|
||||||
|
*/
|
||||||
|
protected function _unset_exporter_key( $key ) {
|
||||||
|
$this->key_to_unset = $key;
|
||||||
|
add_filter( 'wp_privacy_personal_data_exporters', array( $this, 'filter_unset_exporter_key' ), 20 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unset a specified key in the test exporter array.
|
||||||
|
*
|
||||||
|
* @param array $exporters List of data exporters.
|
||||||
|
*
|
||||||
|
* @return array $exporters List of data exporters.
|
||||||
|
*/
|
||||||
|
public function filter_unset_exporter_key( $exporters ) {
|
||||||
|
if ( false === $this->key_to_unset ) {
|
||||||
|
$exporters[ self::$exporter_key ] = false;
|
||||||
|
} elseif ( ! empty( $this->key_to_unset ) ) {
|
||||||
|
unset( $exporters[ self::$exporter_key ][ $this->key_to_unset ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $exporters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the request ID is missing.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_missing_request_id() {
|
||||||
|
$this->_make_ajax_call(
|
||||||
|
array(
|
||||||
|
'id' => null, // Missing request ID.
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'Missing request ID.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the request ID is less than 1.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_invalid_id() {
|
||||||
|
$this->_make_ajax_call(
|
||||||
|
array(
|
||||||
|
'id' => -1, // Invalid request ID, less than 1.
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'Invalid request ID.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the current user is missing the required capability.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_current_user_missing_required_capability() {
|
||||||
|
$this->_setRole( 'author' );
|
||||||
|
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertFalse( current_user_can( 'export_others_personal_data' ) );
|
||||||
|
$this->assertSame( 'Sorry, you are not allowed to perform this action.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the nonce does not validate.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_failure_with_invalid_nonce() {
|
||||||
|
$this->setExpectedException( 'WPAjaxDieStopException', '-1' );
|
||||||
|
|
||||||
|
$this->_make_ajax_call(
|
||||||
|
array(
|
||||||
|
'security' => 'invalid-nonce',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the request type is incorrect.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_incorrect_request_type() {
|
||||||
|
$request_id = wp_create_user_request(
|
||||||
|
'erase-request@example.com',
|
||||||
|
'remove_personal_data' // Incorrect request type, expects 'export_personal_data'.
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->_make_ajax_call(
|
||||||
|
array(
|
||||||
|
'security' => wp_create_nonce( 'wp-privacy-export-personal-data-' . $request_id ),
|
||||||
|
'id' => $request_id,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'Invalid request type.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the requester's email address is invalid.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_invalid_email_address() {
|
||||||
|
wp_update_post(
|
||||||
|
array(
|
||||||
|
'ID' => self::$request_id,
|
||||||
|
'post_title' => '', // Invalid requester's email address.
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'A valid email address must be given.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the exporter index is missing.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_missing_exporter_index() {
|
||||||
|
$this->_make_ajax_call(
|
||||||
|
array(
|
||||||
|
'exporter' => null, // Missing exporter index.
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'Missing exporter index.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the page index is missing.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_missing_page_index() {
|
||||||
|
$this->_make_ajax_call(
|
||||||
|
array(
|
||||||
|
'page' => null, // Missing page index.
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'Missing page index.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when an exporter has improperly used the `wp_privacy_personal_data_exporters` filter.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_exporter_has_improperly_used_exporters_filter() {
|
||||||
|
// Improper filter usage: returns false instead of an expected array.
|
||||||
|
add_filter( 'wp_privacy_personal_data_exporters', '__return_false', 999 );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'An exporter has improperly used the registration filter.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the exporter index is negative.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_negative_exporter_index() {
|
||||||
|
$this->_make_ajax_call(
|
||||||
|
array(
|
||||||
|
'exporter' => -1, // Negative exporter index.
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'Exporter index cannot be negative.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the exporter index is out of range.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_exporter_index_out_of_range() {
|
||||||
|
$this->_make_ajax_call(
|
||||||
|
array(
|
||||||
|
'exporter' => PHP_INT_MAX, // Out of range exporter index.
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'Exporter index is out of range.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when the page index is less than one.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_page_index_less_than_one() {
|
||||||
|
$this->_make_ajax_call(
|
||||||
|
array(
|
||||||
|
'page' => 0, // Page index less than one.
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'Page index cannot be less than one.', $this->_last_response_parsed['data'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when an exporter is not an array.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_exporter_not_array() {
|
||||||
|
$this->_unset_exporter_key( false );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame(
|
||||||
|
sprintf(
|
||||||
|
'Expected an array describing the exporter at index %s.',
|
||||||
|
self::$exporter_key
|
||||||
|
),
|
||||||
|
$this->_last_response_parsed['data']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when an exporter is missing a friendly name.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_exporter_missing_friendly_name() {
|
||||||
|
$this->_unset_exporter_key( 'exporter_friendly_name' );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame(
|
||||||
|
sprintf(
|
||||||
|
'Exporter array at index %s does not include a friendly name.',
|
||||||
|
self::$exporter_key
|
||||||
|
),
|
||||||
|
$this->_last_response_parsed['data']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when an exporter is missing a callback.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_exporter_missing_callback() {
|
||||||
|
$this->_unset_exporter_key( 'callback' );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame(
|
||||||
|
sprintf(
|
||||||
|
'Exporter does not include a callback: %s.',
|
||||||
|
self::$exporter_friendly_name
|
||||||
|
),
|
||||||
|
$this->_last_response_parsed['data']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when an exporter, at a given index, has an invalid callback.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_exporter_index_invalid_callback() {
|
||||||
|
$this->_set_exporter_callback( false );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame(
|
||||||
|
sprintf(
|
||||||
|
'Exporter callback is not a valid callback: %s.',
|
||||||
|
self::$exporter_friendly_name
|
||||||
|
),
|
||||||
|
$this->_last_response_parsed['data']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When an exporter callback returns a WP_Error, it should be passed as the error.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_exporter_callback_returns_wp_error() {
|
||||||
|
$this->_set_exporter_callback( array( $this, 'callback_return_wp_error' ) );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'passed_message', $this->_last_response_parsed['data'][0]['code'] );
|
||||||
|
$this->assertSame( 'This is a WP_Error message.', $this->_last_response_parsed['data'][0]['message'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for exporter's response.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @param string $email_address The requester's email address.
|
||||||
|
* @param int $page Page number.
|
||||||
|
* @return WP_Error WP_Error instance.
|
||||||
|
*/
|
||||||
|
public function callback_return_wp_error( $email_address, $page = 1 ) {
|
||||||
|
return new WP_Error( 'passed_message', 'This is a WP_Error message.' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when an exporter, at a given index, is missing an array response.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_exporter_index_invalid_response() {
|
||||||
|
$this->_set_exporter_callback( '__return_null' );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame(
|
||||||
|
sprintf(
|
||||||
|
'Expected response as an array from exporter: %s.',
|
||||||
|
self::$exporter_friendly_name
|
||||||
|
),
|
||||||
|
$this->_last_response_parsed['data']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when an exporter is missing data in array response.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_exporter_missing_data_response() {
|
||||||
|
$this->_set_exporter_callback( array( $this, 'callback_missing_data_response' ) );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame(
|
||||||
|
sprintf(
|
||||||
|
'Expected data in response array from exporter: %s.',
|
||||||
|
self::$exporter_friendly_name
|
||||||
|
),
|
||||||
|
$this->_last_response_parsed['data']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for exporter's response.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @param string $email_address The requester's email address.
|
||||||
|
* @param int $page Page number.
|
||||||
|
*
|
||||||
|
* @return array $return Export data.
|
||||||
|
*/
|
||||||
|
public function callback_missing_data_response( $email_address, $page = 1 ) {
|
||||||
|
$response = $this->callback_custom_personal_data_exporter( $email_address, $page );
|
||||||
|
unset( $response['data'] ); // Missing data part of response.
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when an exporter is missing 'data' array in array response.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_function_should_error_when_exporter_missing_data_array_response() {
|
||||||
|
$this->_set_exporter_callback( array( $this, 'callback_missing_data_array_response' ) );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame(
|
||||||
|
sprintf(
|
||||||
|
'Expected data array in response array from exporter: %s.',
|
||||||
|
self::$exporter_friendly_name
|
||||||
|
),
|
||||||
|
$this->_last_response_parsed['data']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for exporter's response.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @param string $email_address The requester's email address.
|
||||||
|
* @param int $page Page number.
|
||||||
|
*
|
||||||
|
* @return array $return Export data.
|
||||||
|
*/
|
||||||
|
public function callback_missing_data_array_response( $email_address, $page = 1 ) {
|
||||||
|
$response = $this->callback_custom_personal_data_exporter( $email_address, $page );
|
||||||
|
$response['data'] = false; // Not an array.
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should send an error when an exporter is missing 'done' in array response.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_error_when_exporter_missing_done_response() {
|
||||||
|
$this->_set_exporter_callback( array( $this, 'callback_missing_done_response' ) );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertFalse( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame(
|
||||||
|
sprintf(
|
||||||
|
'Expected done (boolean) in response array from exporter: %s.',
|
||||||
|
self::$exporter_friendly_name
|
||||||
|
),
|
||||||
|
$this->_last_response_parsed['data']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the response's done flag.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @param string $email_address The requester's email address.
|
||||||
|
* @param int $page Page number.
|
||||||
|
*
|
||||||
|
* @return array $return Export data.
|
||||||
|
*/
|
||||||
|
public function callback_missing_done_response( $email_address, $page = 1 ) {
|
||||||
|
$response = $this->callback_custom_personal_data_exporter( $email_address, $page );
|
||||||
|
unset( $response['done'] );
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should successfully send exporter data response when the current user has the required capability.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_succeeds_when_current_user_has_required_capability() {
|
||||||
|
$this->assertTrue( current_user_can( 'export_others_personal_data' ) );
|
||||||
|
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$this->assertTrue( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( 'custom-exporter-item-id', $this->_last_response_parsed['data']['data']['item_id'] );
|
||||||
|
$this->assertSame( 'Email', $this->_last_response_parsed['data']['data']['data'][0]['name'] );
|
||||||
|
$this->assertSame( self::$request_email, $this->_last_response_parsed['data']['data']['data'][0]['value'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should successfully send exporter data response when no items to export.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_success_when_no_items_to_export() {
|
||||||
|
|
||||||
|
$this->_make_ajax_call( array( 'page' => 2 ) );
|
||||||
|
|
||||||
|
$this->assertTrue( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertEmpty( $this->_last_response_parsed['data']['data'] );
|
||||||
|
$this->assertTrue( $this->_last_response_parsed['data']['done'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function's output should be filterable with the `wp_privacy_personal_data_export_page` filter.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*/
|
||||||
|
public function test_output_should_be_filterable() {
|
||||||
|
add_filter( 'wp_privacy_personal_data_export_page', array( $this, 'filter_exporter_data_response' ), 20, 7 );
|
||||||
|
$this->_make_ajax_call();
|
||||||
|
|
||||||
|
$expected_group_label = sprintf(
|
||||||
|
'%s-%s-%s-%s-%s-%s',
|
||||||
|
self::$exporter,
|
||||||
|
self::$page,
|
||||||
|
self::$request_email,
|
||||||
|
self::$request_id,
|
||||||
|
self::$send_as_email,
|
||||||
|
self::$exporter_key
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertTrue( $this->_last_response_parsed['success'] );
|
||||||
|
$this->assertSame( $expected_group_label, $this->_last_response_parsed['data']['group_label'] );
|
||||||
|
$this->assertSame( 'filtered_group_id', $this->_last_response_parsed['data']['group_id'] );
|
||||||
|
$this->assertSame( 'filtered_item_id', $this->_last_response_parsed['data']['item_id'] );
|
||||||
|
$this->assertSame( 'filtered_name', $this->_last_response_parsed['data']['data'][0]['name'] );
|
||||||
|
$this->assertSame( 'filtered_value', $this->_last_response_parsed['data']['data'][0]['value'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter exporter's data response.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @param array $response The personal data for the given exporter and page.
|
||||||
|
* @param int $exporter_index The index of the exporter that provided this data.
|
||||||
|
* @param string $email_address The email address associated with this personal data.
|
||||||
|
* @param int $page The page for this response.
|
||||||
|
* @param int $request_id The privacy request post ID associated with this request.
|
||||||
|
* @param bool $send_as_email Whether the final results of the export should be emailed to the user.
|
||||||
|
* @param string $exporter_key The key (slug) of the exporter that provided this data.
|
||||||
|
*
|
||||||
|
* @return array $response The personal data for the given exporter and page.
|
||||||
|
*/
|
||||||
|
public function filter_exporter_data_response( $response, $exporter_index, $email_address, $page, $request_id, $send_as_email, $exporter_key ) {
|
||||||
|
$group_label = sprintf(
|
||||||
|
'%s-%s-%s-%s-%s-%s',
|
||||||
|
$exporter_index,
|
||||||
|
$page,
|
||||||
|
$email_address,
|
||||||
|
$request_id,
|
||||||
|
$send_as_email,
|
||||||
|
$exporter_key
|
||||||
|
);
|
||||||
|
$response['group_label'] = $group_label;
|
||||||
|
$response['group_id'] = 'filtered_group_id';
|
||||||
|
$response['item_id'] = 'filtered_item_id';
|
||||||
|
$response['data'][0]['name'] = 'filtered_name';
|
||||||
|
$response['data'][0]['value'] = 'filtered_value';
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter to register a custom personal data exporter.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @param array $exporters An array of personal data exporters.
|
||||||
|
*
|
||||||
|
* @return array $exporters An array of personal data exporters.
|
||||||
|
*/
|
||||||
|
public function filter_register_custom_personal_data_exporter( $exporters ) {
|
||||||
|
$exporters[ self::$exporter_key ] = array(
|
||||||
|
'exporter_friendly_name' => self::$exporter_friendly_name,
|
||||||
|
'callback' => array( $this, 'callback_custom_personal_data_exporter' ),
|
||||||
|
);
|
||||||
|
return $exporters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for a custom personal data exporter.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @param string $email_address The requester's email address.
|
||||||
|
* @param int $page Page number.
|
||||||
|
*
|
||||||
|
* @return array $response Export data response.
|
||||||
|
*/
|
||||||
|
public function callback_custom_personal_data_exporter( $email_address, $page = 1 ) {
|
||||||
|
$data_to_export = array();
|
||||||
|
|
||||||
|
if ( 1 === $page ) {
|
||||||
|
$data_to_export = array(
|
||||||
|
'group_id' => self::$exporter_key . '-group-id',
|
||||||
|
'group_label' => self::$exporter_key . '-group-label',
|
||||||
|
'item_id' => self::$exporter_key . '-item-id',
|
||||||
|
'data' => array(
|
||||||
|
array(
|
||||||
|
'name' => 'Email',
|
||||||
|
'value' => $email_address,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'data' => $data_to_export,
|
||||||
|
'done' => true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function for ajax handler.
|
||||||
|
*
|
||||||
|
* @since 5.2.0
|
||||||
|
*
|
||||||
|
* @param array $args Ajax request arguments.
|
||||||
|
*/
|
||||||
|
protected function _make_ajax_call( $args = array() ) {
|
||||||
|
$this->_last_response_parsed = null;
|
||||||
|
$this->_last_response = '';
|
||||||
|
|
||||||
|
$defaults = array(
|
||||||
|
'action' => self::$action,
|
||||||
|
'security' => wp_create_nonce( self::$action . '-' . self::$request_id ),
|
||||||
|
'exporter' => self::$exporter,
|
||||||
|
'page' => self::$page,
|
||||||
|
'sendAsEmail' => self::$send_as_email,
|
||||||
|
'id' => self::$request_id,
|
||||||
|
);
|
||||||
|
|
||||||
|
$_POST = wp_parse_args( $args, $defaults );
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->_handleAjax( self::$action );
|
||||||
|
} catch ( WPAjaxDieContinueException $e ) {
|
||||||
|
unset( $e );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $this->_last_response ) {
|
||||||
|
$this->_last_response_parsed = json_decode( $this->_last_response, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user