Completed
Push — renovate/wordpress-monorepo ( 8cdadc...6203b6 )
by
unknown
552:54 queued 542:45
created

HttpRequestCacheTrait::setup_http_request_cache()   D

Complexity

Conditions 16
Paths 4

Size

Total Lines 82

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 16
nc 4
nop 0
dl 0
loc 82
rs 4.846
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Trait to cache HTTP requests for unit tests.
4
 *
5
 * @package automattic/jetpack
6
 */
7
8
namespace Automattic\Jetpack\Tests;
9
10
use ReflectionClass;
11
use Requests_Utility_CaseInsensitiveDictionary;
12
use UnexpectedValueException;
13
14
/**
15
 * Trait to cache HTTP requests for unit tests.
16
 *
17
 * The trait can be used in two ways. By default, it reads the cache file.
18
 * If you create a static property `$update_cache` set to true, it will instead
19
 * write to the cache file.
20
 */
21
trait HttpRequestCacheTrait {
22
23
	/**
24
	 * Cache array.
25
	 *
26
	 * @var array
27
	 */
28
	protected static $request_cache = array();
29
30
	/**
31
	 * Args for WP_Http::request that we care about.
32
	 *
33
	 * @var array
34
	 */
35
	protected static $request_args = array( 'method', 'body' );
36
37
	/**
38
	 * Determine the cache filename.
39
	 *
40
	 * @return string
41
	 */
42
	private static function get_http_request_cache_filename() {
43
		$rc       = new ReflectionClass( static::class );
44
		$filename = $rc->getFileName();
45
		if ( substr( $filename, -4 ) === '.php' ) {
46
			$filename = substr( $filename, 0, -4 );
47
		}
48
		return $filename . '-HttpRequestCache.json';
49
	}
50
51
	/**
52
	 * Set up the test class.
53
	 *
54
	 * @beforeClass
55
	 */
56
	public static function setup_http_request_cache_before_class() {
57
		if ( empty( static::$update_cache ) ) {
58
			$filename = self::get_http_request_cache_filename();
59
			if ( file_exists( $filename ) ) {
60
				// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
61
				static::$request_cache = (array) json_decode( file_get_contents( $filename ), true );
62
			}
63
		}
64
	}
65
66
	/**
67
	 * Tear down the test class.
68
	 *
69
	 * @afterClass
70
	 */
71
	public static function teardown_http_request_cache_after_class() {
72
		if ( ! empty( static::$update_cache ) ) {
73
			$filename = self::get_http_request_cache_filename();
74
			if ( array() !== static::$request_cache ) {
75
				// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents
76
				file_put_contents(
77
					$filename,
78
					// phpcs:ignore WordPress.WP.AlternativeFunctions.json_encode_json_encode
79
					json_encode( static::$request_cache, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE )
80
				);
81
			} elseif ( file_exists( $filename ) ) {
82
				unlink( $filename );
83
			}
84
		}
85
	}
86
87
	/**
88
	 * Set up the test.
89
	 *
90
	 * @before
91
	 */
92
	public function setup_http_request_cache() {
93
		// This gets called before WP_UnitTestCase_Base::setUp(), so make sure the hooks are saved before we start adding some
94
		// so they'll get removed correctly by WP_UnitTestCase_Base::tearDown().
95
		if ( ! self::$hooks_saved ) {
96
			$this->_backup_hooks();
0 ignored issues
show
Bug introduced by
It seems like _backup_hooks() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
97
		}
98
99
		$request_args = array_flip( static::$request_args );
100
		if ( empty( static::$update_cache ) ) {
101
			add_filter(
102
				'pre_http_request',
103
				function ( $preempt, $parsed_args, $url ) use ( $request_args ) {
104
					if ( $preempt ) {
105
						// Something else already overrode it.
106
						return $preempt;
107
					}
108
					if ( ! isset( static::$request_cache[ $url ] ) ) {
109
						throw new UnexpectedValueException( "No cache for $url" );
110
					}
111
					$args = array_intersect_key( $parsed_args, $request_args );
112
					ksort( $args );
113
					foreach ( static::$request_cache[ $url ] as $data ) {
114
						if ( $data['args'] === $args ) {
115
							$ret = $data['response'];
116
							if ( is_string( $ret ) ) {
117
								// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize
118
								$ret = unserialize( $ret );
119
							} elseif ( is_array( $ret ) && isset( $ret['headers'] ) ) {
120
								$headers = new Requests_Utility_CaseInsensitiveDictionary();
121
								foreach ( $ret['headers'] as $k => $v ) {
122
									$headers[ $k ] = $v;
123
								}
124
								$ret['headers'] = $headers;
125
							}
126
							return $ret;
127
						}
128
					}
129
					// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_export
130
					throw new UnexpectedValueException( "No cache for $url with the specified arguments\n" . var_export( $args, 1 ) );
131
				},
132
				90,
133
				3
134
			);
135
		} else {
136
			add_action(
137
				'http_api_debug',
138
				function ( $response, $context, $class, $parsed_args, $url ) use ( $request_args ) {
139
					$args = array_intersect_key( $parsed_args, $request_args );
140
					ksort( $args );
141
142
					if ( is_object( $response ) ) {
143
						// Probably a WP_Error.
144
						// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
145
						$response = serialize( $response );
146
					} elseif ( is_array( $response ) ) {
147
						// We probably don't care about most of these fields. If it turns out you do, comment
148
						// out the appropriate lines temporarily (or just add them back to the json manually).
149
						$response['headers'] = iterator_to_array( $response['headers'] );
150
						unset( $response['http_response'] );
151
						unset( $response['cookies'] );
152
						unset( $response['headers'] );
153
						unset( $response['filename'] );
154
					}
155
156
					if ( isset( static::$request_cache[ $url ] ) ) {
157
						foreach ( static::$request_cache[ $url ] as $data ) {
158
							if ( $data['args'] === $args ) {
159
								// Duplicate. Hope the response is functionally the same.
160
								return;
161
							}
162
						}
163
					}
164
					static::$request_cache[ $url ][] = array(
165
						'args'     => $args,
166
						'response' => $response,
167
					);
168
				},
169
				10,
170
				5
171
			);
172
		}
173
	}
174
175
	/**
176
	 * Fail tests if `$update_cache` is set.
177
	 */
178
	public function test_update_cache_setting() {
179
		$this->assertTrue( empty( static::$update_cache ), __CLASS__ . '::$update_cache cannot be set for tests to pass' );
0 ignored issues
show
Bug introduced by
It seems like assertTrue() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
180
	}
181
}
182