Make WordPress Core

Ticket #55206: test-wp-memory-leaks.php

File test-wp-memory-leaks.php, 3.4 KB (added by sllimrovert, 4 years ago)

failing unit tests

Line 
1<?php
2
3/**
4 * Class WP_Memory_Leak_Tests
5 *
6 * This class tests two cases that cause memory leaks in WordPress that could
7 * lead to crashes, particularly in CLI jobs that work on larger batches.  For
8 * each of the cases ( one for the wpdb class and one for the global
9 * $wp_object_cache ), we perform some seemingly innocuous task many times -
10 * enough times to require that PHP allocate more memory because of a specific
11 * action.
12 *
13 * Neither of the tests here show a particularly large memory increase, but I've
14 * personally had both occur for me on large jobs hitting WP API functions.  The
15 * one with $wpdb->queries particularly has a tendency to blow up.
16 */
17class WP_Memory_Leak_Tests extends \WP_UnitTestCase {
18
19        /**
20         * This tests a condition which exposes a memory leak in the WPDB class.
21         * If 'SAVEQUERIES' is defined as truthy, then the $wpdb->queries property
22         * can grow indefinitely.
23         */
24        public function test_WPDB_Memory_Leak() {
25
26                // Once a constant is defined, it can't be undefined
27                define( 'SAVEQUERIES', true );
28
29                // I'll just start my cron job to read the import file I've got.  It's
30                // got a decent number of records.
31                $number_of_records = 1000;
32
33                global $wpdb;
34                $memory = memory_get_usage( true );
35                $peak   = memory_get_peak_usage( true );
36                foreach ( [ 'first', 'second' ] as $pass ) {
37                        // first pass through, we'll apply a fix for this memory leak.
38                        // second pass through, we'll bypass the fix and the tests will fail.
39                        for ( $i = 1; $i <= $number_of_records; $i ++ ) {
40                                if ( 'first' === $pass ) {
41                                        $wpdb->queries = [];
42                                }
43
44                                // for this test, we'll do direct calls to $wpdb
45                                $wpdb->query( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE ID = %d", $i ) );
46                        }
47                        $this->assertEquals( $memory, memory_get_usage( true ), "$pass pass" );
48                        $this->assertEquals( $peak, memory_get_peak_usage( true ), "$pass pass" );
49                }
50
51        }
52
53        /**
54         * This tests a condition which exposes a memory leak in wp cache API.  If
55         * a large batch job attempts to do a lot of something that ends up caching
56         * things ( like, for example, get_post or wp_insert_post ), then unless
57         * the cache is flushed regularly, the memory usage grows indefinitely.
58         */
59        public function test_WP_Cache_Memory_Leak() {
60
61                // I'll just start my cron job to read the import file I've got.  It's
62                // got a decent number of records.
63                $number_of_records = 1000;
64
65                global $wpdb;
66                $memory = memory_get_usage( true );
67                $peak   = memory_get_peak_usage( true );
68                foreach ( [ 'first', 'second' ] as $pass ) {
69                        // first pass through, we'll apply a fix for this memory leak.
70                        // second pass through, we'll bypass the fix and the tests will fail.
71                        for ( $i = 1; $i <= $number_of_records; $i ++ ) {
72                                if ( 'first' === $pass ) {
73                                        wp_cache_flush();
74                                }
75
76                                // Because our last test defined 'SAVEQUERIES', we need to
77                                // always apply this fix, otherwise that memory leak manifests.
78                                // With us doing a core API function `wp_insert_post`, the number
79                                // of queries is quite large and memory __really__ grows.
80                                $wpdb->queries = [];
81
82                                // let's say we're inserting posts, maybe from an excel file.
83                                // this caches some things, so $wp_object_cache grows.
84                                wp_insert_post([
85                                        'post_type' => 'post',
86                                        'post_title' => "post $i",
87                                        'post_content' => "pass $pass"
88                                ]);
89                        }
90                        $this->assertEquals( $memory, memory_get_usage( true ), "$pass pass" );
91                        $this->assertEquals( $peak, memory_get_peak_usage( true ), "$pass pass" );
92                }
93
94        }
95
96}