1
|
|
|
<?php // phpcs:ignore WordPress.Files.FileName.NotHyphenatedLowercase |
2
|
|
|
/** |
3
|
|
|
* Connection Manager functionality testing. |
4
|
|
|
* |
5
|
|
|
* @package automattic/jetpack-connection |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
namespace Automattic\Jetpack\Connection; |
9
|
|
|
|
10
|
|
|
use WorDBless\BaseTestCase; |
11
|
|
|
|
12
|
|
|
/** |
13
|
|
|
* Connection Manager functionality testing. |
14
|
|
|
*/ |
15
|
|
|
class Error_Handler_Test extends BaseTestCase { |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Initialize tests |
19
|
|
|
*/ |
20
|
|
|
public function setUp() { |
21
|
|
|
parent::setUp(); |
22
|
|
|
$this->error_handler = Error_Handler::get_instance(); |
23
|
|
|
} |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* Generates a sample WP_Error object in the same format Manager class does for broken signatures |
27
|
|
|
* |
28
|
|
|
* @param string $error_code The error code you want the error to have. |
29
|
|
|
* @param string $user_id The user id you want the token to have. |
30
|
|
|
* @return \WP_Error |
31
|
|
|
*/ |
32
|
|
|
public function get_sample_error( $error_code, $user_id ) { |
33
|
|
|
|
34
|
|
|
$signature_details = array( |
35
|
|
|
'token' => 'dhj938djh938d:1:' . $user_id, |
36
|
|
|
'timestamp' => time(), |
37
|
|
|
'nonce' => 'asd3d32d', |
38
|
|
|
'body_hash' => 'dsf34frf', |
39
|
|
|
'method' => 'POST', |
40
|
|
|
'url' => 'https://example.org', |
41
|
|
|
'signature' => 'sdf234fe', |
42
|
|
|
); |
43
|
|
|
|
44
|
|
|
return new \WP_Error( |
45
|
|
|
$error_code, |
|
|
|
|
46
|
|
|
'An error was triggered', |
47
|
|
|
compact( 'signature_details' ) |
48
|
|
|
); |
49
|
|
|
|
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Test storing an error |
54
|
|
|
*/ |
55
|
|
|
public function test_store_error() { |
56
|
|
|
|
57
|
|
|
add_filter( 'jetpack_connection_bypass_error_reporting_gate', '__return_true' ); |
58
|
|
|
|
59
|
|
|
$error = $this->get_sample_error( 'invalid_token', 1 ); |
60
|
|
|
|
61
|
|
|
$this->error_handler->report_error( $error ); |
62
|
|
|
|
63
|
|
|
$stored_errors = $this->error_handler->get_stored_errors(); |
64
|
|
|
|
65
|
|
|
$this->assertEquals( 1, count( $stored_errors ) ); |
66
|
|
|
|
67
|
|
|
$this->arrayHasKey( 'invalid_token', $stored_errors ); |
68
|
|
|
|
69
|
|
|
$this->assertEquals( 1, count( $stored_errors['invalid_token'] ) ); |
70
|
|
|
|
71
|
|
|
$this->arrayHasKey( '1', $stored_errors['invalid_token'] ); |
72
|
|
|
|
73
|
|
|
$this->arrayHasKey( 'nonce', $stored_errors['invalid_token']['1'] ); |
74
|
|
|
$this->arrayHasKey( 'error_code', $stored_errors['invalid_token']['1'] ); |
75
|
|
|
$this->arrayHasKey( 'user_id', $stored_errors['invalid_token']['1'] ); |
76
|
|
|
$this->arrayHasKey( 'error_message', $stored_errors['invalid_token']['1'] ); |
77
|
|
|
$this->arrayHasKey( 'error_data', $stored_errors['invalid_token']['1'] ); |
78
|
|
|
$this->arrayHasKey( 'timestamp', $stored_errors['invalid_token']['1'] ); |
79
|
|
|
$this->arrayHasKey( 'nonce', $stored_errors['invalid_token']['1'] ); |
80
|
|
|
|
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Test storing errors |
85
|
|
|
*/ |
86
|
|
|
public function test_store_multiple_error_codes() { |
87
|
|
|
|
88
|
|
|
add_filter( 'jetpack_connection_bypass_error_reporting_gate', '__return_true' ); |
89
|
|
|
|
90
|
|
|
$error = $this->get_sample_error( 'invalid_token', 1 ); |
91
|
|
|
$error2 = $this->get_sample_error( 'unknown_user', 1 ); |
92
|
|
|
|
93
|
|
|
$this->error_handler->report_error( $error ); |
94
|
|
|
$this->error_handler->report_error( $error2 ); |
95
|
|
|
|
96
|
|
|
$stored_errors = $this->error_handler->get_stored_errors(); |
97
|
|
|
|
98
|
|
|
$this->assertEquals( 2, count( $stored_errors ) ); |
99
|
|
|
|
100
|
|
|
$this->arrayHasKey( 'invalid_token', $stored_errors ); |
101
|
|
|
|
102
|
|
|
$this->assertEquals( 1, count( $stored_errors['invalid_token'] ) ); |
103
|
|
|
$this->assertEquals( 1, count( $stored_errors['unknown_user'] ) ); |
104
|
|
|
|
105
|
|
|
$this->arrayHasKey( '1', $stored_errors['unknown_user'] ); |
106
|
|
|
|
107
|
|
|
$this->arrayHasKey( 'nonce', $stored_errors['unknown_user']['1'] ); |
108
|
|
|
$this->arrayHasKey( 'error_code', $stored_errors['unknown_user']['1'] ); |
109
|
|
|
$this->arrayHasKey( 'user_id', $stored_errors['unknown_user']['1'] ); |
110
|
|
|
$this->arrayHasKey( 'error_message', $stored_errors['unknown_user']['1'] ); |
111
|
|
|
$this->arrayHasKey( 'error_data', $stored_errors['unknown_user']['1'] ); |
112
|
|
|
$this->arrayHasKey( 'timestamp', $stored_errors['unknown_user']['1'] ); |
113
|
|
|
$this->arrayHasKey( 'nonce', $stored_errors['unknown_user']['1'] ); |
114
|
|
|
|
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* Test storing errors |
119
|
|
|
*/ |
120
|
|
|
public function test_store_multiple_error_codes_multiple_users() { |
121
|
|
|
|
122
|
|
|
add_filter( 'jetpack_connection_bypass_error_reporting_gate', '__return_true' ); |
123
|
|
|
|
124
|
|
|
$error = $this->get_sample_error( 'invalid_token', 1 ); |
125
|
|
|
$error2 = $this->get_sample_error( 'unknown_user', 1 ); |
126
|
|
|
$error3 = $this->get_sample_error( 'unknown_user', 2 ); |
127
|
|
|
|
128
|
|
|
$this->error_handler->report_error( $error ); |
129
|
|
|
$this->error_handler->report_error( $error2 ); |
130
|
|
|
$this->error_handler->report_error( $error3 ); |
131
|
|
|
|
132
|
|
|
$stored_errors = $this->error_handler->get_stored_errors(); |
133
|
|
|
|
134
|
|
|
$this->assertEquals( 2, count( $stored_errors ) ); |
135
|
|
|
|
136
|
|
|
$this->arrayHasKey( 'invalid_token', $stored_errors ); |
137
|
|
|
|
138
|
|
|
$this->assertEquals( 1, count( $stored_errors['invalid_token'] ) ); |
139
|
|
|
$this->assertEquals( 2, count( $stored_errors['unknown_user'] ) ); |
140
|
|
|
|
141
|
|
|
$this->arrayHasKey( '2', $stored_errors['unknown_user'] ); |
142
|
|
|
|
143
|
|
|
$this->arrayHasKey( 'nonce', $stored_errors['unknown_user']['2'] ); |
144
|
|
|
$this->arrayHasKey( 'error_code', $stored_errors['unknown_user']['2'] ); |
145
|
|
|
$this->arrayHasKey( 'user_id', $stored_errors['unknown_user']['2'] ); |
146
|
|
|
$this->arrayHasKey( 'error_message', $stored_errors['unknown_user']['2'] ); |
147
|
|
|
$this->arrayHasKey( 'error_data', $stored_errors['unknown_user']['2'] ); |
148
|
|
|
$this->arrayHasKey( 'timestamp', $stored_errors['unknown_user']['2'] ); |
149
|
|
|
$this->arrayHasKey( 'nonce', $stored_errors['unknown_user']['2'] ); |
150
|
|
|
|
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* Test gate |
155
|
|
|
*/ |
156
|
|
|
public function test_gate() { |
157
|
|
|
|
158
|
|
|
$error = $this->get_sample_error( 'invalid_token', 1 ); |
159
|
|
|
$error2 = $this->get_sample_error( 'invalid_token', 1 ); |
160
|
|
|
$error3 = $this->get_sample_error( 'unknown_user', 1 ); |
161
|
|
|
|
162
|
|
|
$this->assertTrue( $this->error_handler->should_report_error( $error ) ); |
163
|
|
|
$this->assertFalse( $this->error_handler->should_report_error( $error2 ), 'second attempt to report the same error code should be stopped by the gate' ); |
164
|
|
|
$this->assertTrue( $this->error_handler->should_report_error( $error3 ) ); |
165
|
|
|
|
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* Test 5 errors per code |
170
|
|
|
*/ |
171
|
|
|
public function test_max_five_errors_per_code() { |
172
|
|
|
|
173
|
|
|
add_filter( 'jetpack_connection_bypass_error_reporting_gate', '__return_true' ); |
174
|
|
|
|
175
|
|
|
$error = $this->get_sample_error( 'unknown_user', 3 ); |
176
|
|
|
$error2 = $this->get_sample_error( 'unknown_user', 4 ); |
177
|
|
|
$error3 = $this->get_sample_error( 'unknown_user', 5 ); |
178
|
|
|
$error4 = $this->get_sample_error( 'unknown_user', 6 ); |
179
|
|
|
$error5 = $this->get_sample_error( 'unknown_user', 7 ); |
180
|
|
|
$error6 = $this->get_sample_error( 'unknown_user', 8 ); |
181
|
|
|
|
182
|
|
|
$this->error_handler->report_error( $error ); |
183
|
|
|
$this->error_handler->report_error( $error2 ); |
184
|
|
|
$this->error_handler->report_error( $error3 ); |
185
|
|
|
$this->error_handler->report_error( $error4 ); |
186
|
|
|
$this->error_handler->report_error( $error5 ); |
187
|
|
|
$this->error_handler->report_error( $error6 ); |
188
|
|
|
|
189
|
|
|
$stored_errors = $this->error_handler->get_stored_errors(); |
190
|
|
|
|
191
|
|
|
$this->assertEquals( 5, count( $stored_errors['unknown_user'] ) ); |
192
|
|
|
|
193
|
|
|
$this->assertArrayNotHasKey( '3', $stored_errors['unknown_user'], 'first inserted error must have been excluded' ); |
194
|
|
|
$this->assertArrayHasKey( '8', $stored_errors['unknown_user'], 'sixth inserted error must be present' ); |
195
|
|
|
|
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* Data provider for test_get_user_id_from_token |
200
|
|
|
* |
201
|
|
|
* @return array |
202
|
|
|
*/ |
203
|
|
|
public function get_user_id_from_token_data() { |
204
|
|
|
return array( |
205
|
|
|
array( |
206
|
|
|
'token' => 'asdsaddasa:1:3', |
207
|
|
|
'expected' => 3, |
208
|
|
|
), |
209
|
|
|
array( |
210
|
|
|
'token' => 'asdsaddasa:1:2', |
211
|
|
|
'expected' => 2, |
212
|
|
|
), |
213
|
|
|
array( |
214
|
|
|
'token' => 'asdsaddasa:1', |
215
|
|
|
'expected' => 'invalid', |
216
|
|
|
), |
217
|
|
|
array( |
218
|
|
|
'token' => 'asdsaddasa:1:', |
219
|
|
|
'expected' => 'invalid', |
220
|
|
|
), |
221
|
|
|
array( |
222
|
|
|
'token' => 'asdsaddasa:1:asd', |
223
|
|
|
'expected' => 'invalid', |
224
|
|
|
), |
225
|
|
|
array( |
226
|
|
|
'token' => 'asdsaddasa:1:333', |
227
|
|
|
'expected' => 333, |
228
|
|
|
), |
229
|
|
|
); |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
/** |
233
|
|
|
* Test get_user_id_from_token |
234
|
|
|
* |
235
|
|
|
* @param string $token token. |
236
|
|
|
* @param string|integer $expected expected user_id. |
237
|
|
|
* |
238
|
|
|
* @dataProvider get_user_id_from_token_data |
239
|
|
|
*/ |
240
|
|
|
public function test_get_user_id_from_token( $token, $expected ) { |
241
|
|
|
$this->assertEquals( $expected, $this->error_handler->get_user_id_from_token( $token ) ); |
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
|
245
|
|
|
/** |
246
|
|
|
* Test get_error_by_nonce |
247
|
|
|
*/ |
248
|
|
|
public function test_get_error_by_nonce() { |
249
|
|
|
$error = $this->get_sample_error( 'unknown_user', 3 ); |
250
|
|
|
$error2 = $this->get_sample_error( 'invalid_token', 4 ); |
251
|
|
|
$error3 = $this->get_sample_error( 'no_user_tokens', 5 ); |
252
|
|
|
|
253
|
|
|
$this->error_handler->report_error( $error ); |
254
|
|
|
$this->error_handler->report_error( $error2 ); |
255
|
|
|
$this->error_handler->report_error( $error3 ); |
256
|
|
|
|
257
|
|
|
$stored_errors = $this->error_handler->get_stored_errors(); |
258
|
|
|
|
259
|
|
|
$error = $this->error_handler->get_error_by_nonce( $stored_errors['no_user_tokens']['5']['nonce'] ); |
260
|
|
|
|
261
|
|
|
$this->assertEquals( $error, $stored_errors['no_user_tokens']['5'] ); |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
/** |
265
|
|
|
* Test verify error |
266
|
|
|
*/ |
267
|
|
|
public function test_verify_error() { |
268
|
|
|
$error = $this->get_sample_error( 'unknown_user', 3 ); |
269
|
|
|
$this->error_handler->report_error( $error ); |
270
|
|
|
|
271
|
|
|
$stored_errors = $this->error_handler->get_stored_errors(); |
272
|
|
|
|
273
|
|
|
$this->error_handler->verify_error( $stored_errors['unknown_user']['3'] ); |
274
|
|
|
|
275
|
|
|
$verified_errors = $this->error_handler->get_verified_errors(); |
276
|
|
|
|
277
|
|
|
$this->assertEquals( $verified_errors['unknown_user']['3'], $stored_errors['unknown_user']['3'] ); |
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
/** |
281
|
|
|
* Test encryption available. |
282
|
|
|
*/ |
283
|
|
|
public function test_encryption() { |
284
|
|
|
$error = $this->get_sample_error( 'unknown_user', 3 ); |
285
|
|
|
$this->error_handler->report_error( $error ); |
286
|
|
|
|
287
|
|
|
$stored_errors = $this->error_handler->get_stored_errors(); |
288
|
|
|
|
289
|
|
|
$encrypted = $this->error_handler->encrypt_data_to_wpcom( $stored_errors['unknown_user']['3'] ); |
290
|
|
|
|
291
|
|
|
$this->assertInternalType( 'string', $encrypted ); |
292
|
|
|
$this->assertEquals( 472, strlen( $encrypted ) ); |
293
|
|
|
|
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
/** |
297
|
|
|
* Test Garbage collector. |
298
|
|
|
*/ |
299
|
|
|
public function test_garbage_collector() { |
300
|
|
|
$error = $this->get_sample_error( 'unknown_user', 3 ); |
301
|
|
|
$error2 = $this->get_sample_error( 'invalid_token', 4 ); |
302
|
|
|
$error3 = $this->get_sample_error( 'no_user_tokens', 5 ); |
303
|
|
|
$error4 = $this->get_sample_error( 'no_user_tokens', 6 ); |
304
|
|
|
|
305
|
|
|
$this->error_handler->report_error( $error ); |
306
|
|
|
$this->error_handler->report_error( $error2 ); |
307
|
|
|
$this->error_handler->report_error( $error3 ); |
308
|
|
|
$this->error_handler->report_error( $error4 ); |
309
|
|
|
|
310
|
|
|
// Manipulate the timestamps directly in the database. |
311
|
|
|
$saved_options = get_option( Error_Handler::STORED_ERRORS_OPTION ); |
312
|
|
|
$this->assertEquals( 3, count( $saved_options ) ); |
313
|
|
|
$this->assertEquals( 1, count( $saved_options['no_user_tokens'] ) ); |
314
|
|
|
$saved_options['invalid_token'][4]['timestamp'] = time() - DAY_IN_SECONDS * 4; |
315
|
|
|
$saved_options['no_user_tokens'][6]['timestamp'] = time() - DAY_IN_SECONDS * 4; |
316
|
|
|
update_option( Error_Handler::STORED_ERRORS_OPTION, $saved_options ); |
317
|
|
|
|
318
|
|
|
$errors = $this->error_handler->get_stored_errors(); |
319
|
|
|
|
320
|
|
|
$this->assertEquals( 2, count( $errors ) ); |
321
|
|
|
|
322
|
|
|
$this->assertArrayHasKey( 'unknown_user', $errors ); |
323
|
|
|
$this->assertArrayHasKey( 'no_user_tokens', $errors ); |
324
|
|
|
$this->assertArrayNotHasKey( 'invalid_token', $errors ); |
325
|
|
|
|
326
|
|
|
$this->assertEquals( 1, count( $errors['no_user_tokens'] ) ); |
327
|
|
|
|
328
|
|
|
} |
329
|
|
|
} |
330
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.