Make WordPress Core

Ticket #44233: 43546.wpPrivacyGeneratePersonalDataExportFile.diff

File 43546.wpPrivacyGeneratePersonalDataExportFile.diff, 9.0 KB (added by allendav, 7 years ago)

Covers everything coverable

  • tests/phpunit/tests/privacy/wpPrivacyGeneratePersonalDataExportFile.php

     
     1<?php
     2/**
     3 * Define a class to test `wp_privacy_generate_personal_data_export_file()`.
     4 *
     5 * @package WordPress
     6 * @subpackage UnitTests
     7 * @since 4.9.6
     8 */
     9
     10/**
     11 * Test cases for `wp_privacy_generate_personal_data_export_file()`.
     12 *
     13 * @group privacy
     14 * @covers wp_privacy_generate_personal_data_export_file
     15 *
     16 * @since 4.9.6
     17 */
     18class Tests_Privacy_wpPrivacyGeneratePersonalDataExportFile extends WP_UnitTestCase {
     19        /**
     20         * An Export Request ID
     21         *
     22         * @since 4.9.6
     23         *
     24         * @var int $export_request_id
     25         */
     26        protected static $export_request_id;
     27
     28        /**
     29         * Create fixtures that are shared by multiple test cases.
     30         *
     31         * @param WP_UnitTest_Factory $factory The base factory object.
     32         */
     33        public static function wpSetUpBeforeClass( $factory ) {
     34                self::$export_request_id = wp_create_user_request( 'export-requester@example.com', 'export_personal_data' );
     35                update_post_meta( self::$export_request_id, '_export_data_grouped', array() );
     36        }
     37
     38        /**
     39         * Set up the test fixture.
     40         * Override wp_die(), pretend to be ajax, and suppress E_WARNINGs
     41         */
     42        public function setUp() {
     43                parent::setUp();
     44
     45                // We need to override the die handler because otherwise our unit test will die too
     46                add_filter( 'wp_die_ajax_handler', array( $this, 'getDieHandler' ), 1, 1 );
     47                add_filter( 'wp_doing_ajax', '__return_true' );
     48
     49                // Suppress warnings from "Cannot modify header information - headers already sent by"
     50                $this->_error_level = error_reporting();
     51        error_reporting( $this->_error_level & ~E_WARNING );
     52       
     53        // Delete the wp-personal-data-exports folder before each test
     54        $wp_privacy_exports_dir = wp_privacy_exports_dir();
     55        if ( empty( $wp_privacy_exports_dir ) ) {
     56            $this->markTestSkipped( 'Exports directory unclear. Skipping test to avoid loss of data.' );
     57        } else {
     58            @chmod( $wp_privacy_exports_dir, 0755 );
     59
     60            if ( ! is_dir( $wp_privacy_exports_dir ) ) {
     61                @unlink( untrailingslashit( $wp_privacy_exports_dir ) );
     62            } else {
     63                if ( 'Windows' === PHP_OS ) {
     64                    exec( sprintf( "rd /s /q %s", escapeshellarg( $wp_privacy_exports_dir ) ) );
     65                } else {
     66                    exec( sprintf( "rm -rf %s", escapeshellarg( $wp_privacy_exports_dir ) ) );
     67                }
     68            }
     69        }
     70        }
     71
     72        /**
     73         * Tear down the test fixture.
     74         * Remove the wp_die() override, restore error reporting
     75         */
     76        public function tearDown() {
     77                remove_filter( 'wp_die_ajax_handler', array( $this, 'getDieHandler' ), 1, 1 );
     78                error_reporting( $this->_error_level );
     79                parent::tearDown();
     80        }
     81
     82        /**
     83         * Return our callback handler
     84         *
     85         * @return callback
     86         */
     87        public function getDieHandler() {
     88                return array( $this, 'dieHandler' );
     89        }
     90
     91        /**
     92         * Handler for wp_die()
     93         * Don't die, throw.
     94         *
     95         * @param string $message (Unfortunately, always empty)
     96         */
     97        public function dieHandler( $message ) {
     98                throw new Exception();
     99        }
     100
     101    public function test_wp_privacy_generate_personal_data_export_file_can_succeed() {
     102                $exception_was_thrown = false;
     103
     104                try {
     105                        wp_privacy_generate_personal_data_export_file( self::$export_request_id );
     106                } catch( Exception $e ) {
     107                        $exception_was_thrown = true;
     108                }
     109
     110                $this->assertFalse( $exception_was_thrown );
     111    }
     112
     113        public function test_wp_privacy_generate_personal_data_export_file_rejects_remove_requests() {
     114                $exception_was_thrown = false;
     115                $request_id = wp_create_user_request( 'removal-requester@example.com', 'remove_personal_data' );
     116
     117                try {
     118                        $this->expectOutputString( '{"success":false,"data":"Invalid request ID when generating export file."}' );
     119                        wp_privacy_generate_personal_data_export_file( $request_id );
     120                } catch( Exception $e ) {
     121                        $exception_was_thrown = true;
     122                }
     123
     124                $this->assertTrue( $exception_was_thrown );
     125        }
     126
     127        public function test_wp_privacy_generate_personal_data_export_file_rejects_requests_with_bad_email_addresses() {
     128                $exception_was_thrown = false;
     129                $request_id = wp_create_user_request( 'bad-email-requester@example.com', 'export_personal_data' );
     130
     131                wp_update_post(
     132                        array(
     133                                'ID' => $request_id,
     134                                'post_title' => 'not-a-valid-email-address'
     135                        )
     136                );
     137
     138                try {
     139                        $this->expectOutputString( '{"success":false,"data":"Invalid email address when generating export file."}' );
     140                        wp_privacy_generate_personal_data_export_file( $request_id );
     141                } catch( Exception $e ) {
     142                        $exception_was_thrown = true;
     143                }
     144
     145                $this->assertTrue( $exception_was_thrown );
     146        }
     147
     148    public function test_wp_privacy_generate_personal_data_export_file_detects_cannot_create_folder() {
     149                $exception_was_thrown = false;
     150                $index_html_path = wp_privacy_exports_dir();
     151        touch( untrailingslashit( $index_html_path ) ); // creates a file with our folder name, thereby blocking the folder creation
     152
     153                try {
     154                        $this->expectOutputString( '{"success":false,"data":"Unable to create export folder."}' );
     155                        wp_privacy_generate_personal_data_export_file( self::$export_request_id );
     156                } catch( Exception $e ) {
     157                        $exception_was_thrown = true;
     158                }
     159
     160                $this->assertTrue( $exception_was_thrown );
     161        }
     162   
     163    public function test_wp_privacy_generate_personal_data_export_file_creates_index_in_export_folder() {
     164                $exception_was_thrown = false;
     165
     166                try {
     167                        $this->expectOutputString( '' );
     168                        wp_privacy_generate_personal_data_export_file( self::$export_request_id );
     169                } catch( Exception $e ) {
     170                        $exception_was_thrown = true;
     171                }
     172
     173                $this->assertFalse( $exception_was_thrown );
     174
     175                $index_html_path = wp_privacy_exports_dir() . 'index.html';
     176        $this->assertTrue( file_exists( $index_html_path ) );
     177    }
     178
     179    public function test_wp_privacy_generate_personal_data_export_file_detects_cannot_create_index() {
     180                $exception_was_thrown = false;
     181
     182                $exports_dir = wp_privacy_exports_dir();
     183                mkdir( $exports_dir );
     184                chmod( $exports_dir, 0444 ); // make it read only so protection will fail
     185
     186                try {
     187                        $this->expectOutputString( '{"success":false,"data":"Unable to protect export folder from browsing."}' );
     188                        wp_privacy_generate_personal_data_export_file( self::$export_request_id );
     189                } catch( Exception $e ) {
     190                        $exception_was_thrown = true;
     191                }
     192
     193                $this->assertTrue( $exception_was_thrown );
     194        }
     195
     196    public function test_wp_privacy_generate_personal_data_export_file_detects_cannot_write_html() {
     197                $exception_was_thrown = false;
     198
     199                $exports_dir = wp_privacy_exports_dir();
     200                mkdir( $exports_dir );
     201                $index_html_path = wp_privacy_exports_dir() . 'index.html';
     202                touch( $index_html_path );
     203                chmod( $exports_dir, 0555 ); // make the folder read only so html writing will fail
     204
     205                try {
     206                        $this->expectOutputString( '{"success":false,"data":"Unable to open export file (HTML report) for writing."}' );
     207                        wp_privacy_generate_personal_data_export_file( self::$export_request_id );
     208                } catch( Exception $e ) {
     209                        $exception_was_thrown = true;
     210                }
     211
     212                $this->assertTrue( $exception_was_thrown );
     213        }
     214
     215    public function test_wp_privacy_generate_personal_data_export_file_contents() {
     216                $exception_was_thrown = false;
     217
     218                try {
     219                        $this->expectOutputString( '' );
     220                        wp_privacy_generate_personal_data_export_file( self::$export_request_id );
     221                } catch( Exception $e ) {
     222                        $exception_was_thrown = true;
     223                }
     224
     225                if ( ! $exception_was_thrown ) {
     226                        $archive_pathname = get_post_meta( self::$export_request_id, '_export_file_path', true );
     227                        $temp_dir = trailingslashit( wp_privacy_exports_dir() . 'tempdir' );
     228                        mkdir( $temp_dir );
     229                        $zip = new ZipArchive;
     230                        $res = $zip->open( $archive_pathname );
     231
     232                        $this->assertTrue( $res );
     233
     234                        $zip->extractTo( $temp_dir );
     235                        $zip->close();
     236                               
     237                        $this->assertTrue( file_exists( $temp_dir . 'index.html' ) );
     238
     239                        $report_contents = file_get_contents( $temp_dir . 'index.html' );
     240
     241                        $this->assertContains( '<h1>Personal Data Export</h1>', $report_contents );
     242                        $this->assertContains( '<h2>About</h2>', $report_contents );
     243
     244                        $request = wp_get_user_request_data( self::$export_request_id );
     245                        $this->assertContains( $request->email, $report_contents );
     246                }
     247
     248                $this->assertFalse( $exception_was_thrown );
     249        }
     250
     251        // TODO - Come up with tests for the following, if even possible (might require changes to function)
     252        // 1. ziparchive not available
     253        // 2. cannot create zip file (and intermediate HTML report file should also be removed)
     254    // 3. unable to add data to zip file (and intermediate HTML report file should also be removed)
     255}