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 Automattic\Jetpack\Constants; |
11
|
|
|
use PHPUnit\Framework\TestCase; |
12
|
|
|
use WorDBless\Users as WorDBless_Users; |
13
|
|
|
use WP_Error; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* Connection Manager functionality testing. |
17
|
|
|
*/ |
18
|
|
|
class ManagerTest extends TestCase { |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* Temporary stack for `wp_redirect`. |
22
|
|
|
* |
23
|
|
|
* @var array |
24
|
|
|
*/ |
25
|
|
|
protected $arguments_stack = array(); |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* User ID added for the test. |
29
|
|
|
* |
30
|
|
|
* @var int |
31
|
|
|
*/ |
32
|
|
|
protected $user_id; |
33
|
|
|
|
34
|
|
|
const DEFAULT_TEST_CAPS = array( 'default_test_caps' ); |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Initialize the object before running the test method. |
38
|
|
|
* |
39
|
|
|
* @before |
40
|
|
|
*/ |
41
|
|
|
public function set_up() { |
42
|
|
|
$this->manager = $this->getMockBuilder( 'Automattic\Jetpack\Connection\Manager' ) |
43
|
|
|
->setMethods( array( 'get_access_token', 'get_connection_owner_id' ) ) |
44
|
|
|
->getMock(); |
45
|
|
|
|
46
|
|
|
$this->user_id = wp_insert_user( |
47
|
|
|
array( |
48
|
|
|
'user_login' => 'test_is_user_connected_with_user_id_logged_in', |
49
|
|
|
'user_pass' => '123', |
50
|
|
|
) |
51
|
|
|
); |
52
|
|
|
wp_set_current_user( 0 ); |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* Clean up the testing environment. |
57
|
|
|
* |
58
|
|
|
* @after |
59
|
|
|
*/ |
60
|
|
|
public function tear_down() { |
61
|
|
|
wp_set_current_user( 0 ); |
62
|
|
|
WorDBless_Users::init()->clear_all_users(); |
63
|
|
|
unset( $this->manager ); |
64
|
|
|
Constants::clear_constants(); |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* Test the `is_active` functionality when connected. |
69
|
|
|
* |
70
|
|
|
* @covers Automattic\Jetpack\Connection\Manager::is_active |
71
|
|
|
*/ |
72
|
|
|
public function test_is_active_when_connected() { |
73
|
|
|
$access_token = (object) array( |
74
|
|
|
'secret' => 'abcd1234', |
75
|
|
|
'external_user_id' => 1, |
76
|
|
|
); |
77
|
|
|
$this->manager->expects( $this->once() ) |
78
|
|
|
->method( 'get_access_token' ) |
79
|
|
|
->will( $this->returnValue( $access_token ) ); |
80
|
|
|
|
81
|
|
|
$this->assertTrue( $this->manager->is_active() ); |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* Test the `is_active` functionality when not connected. |
86
|
|
|
* |
87
|
|
|
* @covers Automattic\Jetpack\Connection\Manager::is_active |
88
|
|
|
*/ |
89
|
|
|
public function test_is_active_when_not_connected() { |
90
|
|
|
$this->manager->expects( $this->once() ) |
91
|
|
|
->method( 'get_access_token' ) |
92
|
|
|
->will( $this->returnValue( false ) ); |
93
|
|
|
|
94
|
|
|
$this->assertFalse( $this->manager->is_active() ); |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* Test the `api_url` generation. |
99
|
|
|
* |
100
|
|
|
* @covers Automattic\Jetpack\Connection\Manager::api_url |
101
|
|
|
*/ |
102
|
|
|
public function test_api_url_defaults() { |
103
|
|
|
add_filter( 'jetpack_constant_default_value', array( $this, 'filter_api_constant' ), 10, 2 ); |
104
|
|
|
|
105
|
|
|
$this->assertEquals( |
106
|
|
|
'https://jetpack.wordpress.com/jetpack.something/1/', |
107
|
|
|
$this->manager->api_url( 'something' ) |
108
|
|
|
); |
109
|
|
|
$this->assertEquals( |
110
|
|
|
'https://jetpack.wordpress.com/jetpack.another_thing/1/', |
111
|
|
|
$this->manager->api_url( 'another_thing/' ) |
112
|
|
|
); |
113
|
|
|
|
114
|
|
|
remove_filter( 'jetpack_constant_default_value', array( $this, 'filter_api_constant' ), 10, 2 ); |
|
|
|
|
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* Testing the ability of the api_url method to follow set constants and filters. |
119
|
|
|
* |
120
|
|
|
* @covers Automattic\Jetpack\Connection\Manager::api_url |
121
|
|
|
*/ |
122
|
|
|
public function test_api_url_uses_constants_and_filters() { |
123
|
|
|
Constants::set_constant( 'JETPACK__API_BASE', 'https://example.com/api/base.' ); |
124
|
|
|
Constants::set_constant( 'JETPACK__API_VERSION', '1' ); |
125
|
|
|
$this->assertEquals( |
126
|
|
|
'https://example.com/api/base.something/1/', |
127
|
|
|
$this->manager->api_url( 'something' ) |
128
|
|
|
); |
129
|
|
|
|
130
|
|
|
Constants::set_constant( 'JETPACK__API_BASE', 'https://example.com/api/another.' ); |
131
|
|
|
Constants::set_constant( 'JETPACK__API_VERSION', '99' ); |
132
|
|
|
$this->assertEquals( |
133
|
|
|
'https://example.com/api/another.something/99/', |
134
|
|
|
$this->manager->api_url( 'something' ) |
135
|
|
|
); |
136
|
|
|
|
137
|
|
|
$overwrite_filter = function () { |
138
|
|
|
$this->arguments_stack['jetpack_api_url'][] = array_merge( array( 'jetpack_api_url' ), func_get_args() ); |
139
|
|
|
return 'completely overwrite'; |
140
|
|
|
}; |
141
|
|
|
add_filter( 'jetpack_api_url', $overwrite_filter, 10, 4 ); |
142
|
|
|
|
143
|
|
|
$this->assertEquals( |
144
|
|
|
'completely overwrite', |
145
|
|
|
$this->manager->api_url( 'something' ) |
146
|
|
|
); |
147
|
|
|
|
148
|
|
|
// The jetpack_api_url argument stack should not be empty, making sure the filter was |
149
|
|
|
// called with a proper name and arguments. |
150
|
|
|
$call_arguments = array_pop( $this->arguments_stack['jetpack_api_url'] ); |
151
|
|
|
$this->assertEquals( 'something', $call_arguments[2] ); |
152
|
|
|
$this->assertEquals( |
153
|
|
|
Constants::get_constant( 'JETPACK__API_BASE' ), |
154
|
|
|
$call_arguments[3] |
155
|
|
|
); |
156
|
|
|
$this->assertEquals( |
157
|
|
|
'/' . Constants::get_constant( 'JETPACK__API_VERSION' ) . '/', |
158
|
|
|
$call_arguments[4] |
159
|
|
|
); |
160
|
|
|
|
161
|
|
|
remove_filter( 'jetpack_api_url', $overwrite_filter, 10 ); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* Test the `is_user_connected` functionality. |
166
|
|
|
* |
167
|
|
|
* @covers Automattic\Jetpack\Connection\Manager::is_user_connected |
168
|
|
|
*/ |
169
|
|
|
public function test_is_user_connected_with_default_user_id_logged_out() { |
170
|
|
|
$this->assertFalse( $this->manager->is_user_connected() ); |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* Test the `is_user_connected` functionality. |
175
|
|
|
* |
176
|
|
|
* @covers Automattic\Jetpack\Connection\Manager::is_user_connected |
177
|
|
|
*/ |
178
|
|
|
public function test_is_user_connected_with_false_user_id_logged_out() { |
179
|
|
|
$this->assertFalse( $this->manager->is_user_connected( false ) ); |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* Test the `is_user_connected` functionality |
184
|
|
|
* |
185
|
|
|
* @covers Automattic\Jetpack\Connection\Manager::is_user_connected |
186
|
|
|
*/ |
187
|
|
|
public function test_is_user_connected_with_user_id_logged_out_not_connected() { |
188
|
|
|
$this->manager->expects( $this->once() ) |
189
|
|
|
->method( 'get_access_token' ) |
190
|
|
|
->will( $this->returnValue( false ) ); |
191
|
|
|
|
192
|
|
|
$this->assertFalse( $this->manager->is_user_connected( $this->user_id ) ); |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
/** |
196
|
|
|
* Test the `is_user_connected` functionality. |
197
|
|
|
* |
198
|
|
|
* @covers Automattic\Jetpack\Connection\Manager::is_user_connected |
199
|
|
|
*/ |
200
|
|
View Code Duplication |
public function test_is_user_connected_with_default_user_id_logged_in() { |
201
|
|
|
wp_set_current_user( $this->user_id ); |
202
|
|
|
|
203
|
|
|
$access_token = (object) array( |
204
|
|
|
'secret' => 'abcd1234', |
205
|
|
|
'external_user_id' => 1, |
206
|
|
|
); |
207
|
|
|
$this->manager->expects( $this->once() ) |
208
|
|
|
->method( 'get_access_token' ) |
209
|
|
|
->will( $this->returnValue( $access_token ) ); |
210
|
|
|
|
211
|
|
|
$this->assertTrue( $this->manager->is_user_connected() ); |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* Test the `is_user_connected` functionality. |
216
|
|
|
* |
217
|
|
|
* @covers Automattic\Jetpack\Connection\Manager::is_user_connected |
218
|
|
|
*/ |
219
|
|
View Code Duplication |
public function test_is_user_connected_with_user_id_logged_in() { |
220
|
|
|
$access_token = (object) array( |
221
|
|
|
'secret' => 'abcd1234', |
222
|
|
|
'external_user_id' => 1, |
223
|
|
|
); |
224
|
|
|
$this->manager->expects( $this->once() ) |
225
|
|
|
->method( 'get_access_token' ) |
226
|
|
|
->will( $this->returnValue( $access_token ) ); |
227
|
|
|
|
228
|
|
|
$this->assertTrue( $this->manager->is_user_connected( $this->user_id ) ); |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
/** |
232
|
|
|
* Unit test for the "Delete all tokens" functionality. |
233
|
|
|
* |
234
|
|
|
* @covers Automattic\Jetpack\Connection\Manager::delete_all_connection_tokens |
235
|
|
|
*/ |
236
|
|
View Code Duplication |
public function test_delete_all_connection_tokens() { |
237
|
|
|
( new Plugin( 'plugin-slug-1' ) )->add( 'Plugin Name 1' ); |
238
|
|
|
|
239
|
|
|
( new Plugin( 'plugin-slug-2' ) )->add( 'Plugin Name 2' ); |
240
|
|
|
|
241
|
|
|
$stub = $this->createMock( Plugin::class ); |
242
|
|
|
$stub->method( 'is_only' ) |
243
|
|
|
->willReturn( false ); |
244
|
|
|
$manager = ( new Manager() )->set_plugin_instance( $stub ); |
245
|
|
|
|
246
|
|
|
$this->assertFalse( $manager->delete_all_connection_tokens() ); |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
/** |
250
|
|
|
* Unit test for the "Disconnect from WP" functionality. |
251
|
|
|
* |
252
|
|
|
* @covers Automattic\Jetpack\Connection\Manager::disconnect_site_wpcom |
253
|
|
|
*/ |
254
|
|
View Code Duplication |
public function test_disconnect_site_wpcom() { |
255
|
|
|
( new Plugin( 'plugin-slug-1' ) )->add( 'Plugin Name 1' ); |
256
|
|
|
|
257
|
|
|
( new Plugin( 'plugin-slug-2' ) )->add( 'Plugin Name 2' ); |
258
|
|
|
|
259
|
|
|
$stub = $this->createMock( Plugin::class ); |
260
|
|
|
$stub->method( 'is_only' ) |
261
|
|
|
->willReturn( false ); |
262
|
|
|
$manager = ( new Manager() )->set_plugin_instance( $stub ); |
263
|
|
|
|
264
|
|
|
$this->assertFalse( $manager->disconnect_site_wpcom() ); |
265
|
|
|
} |
266
|
|
|
|
267
|
|
|
/** |
268
|
|
|
* Test the `jetpack_connection_custom_caps' method. |
269
|
|
|
* |
270
|
|
|
* @covers Automattic\Jetpack\Connection\Manager::jetpack_connection_custom_caps |
271
|
|
|
* @dataProvider jetpack_connection_custom_caps_data_provider |
272
|
|
|
* |
273
|
|
|
* @param bool $in_offline_mode Whether offline mode is active. |
274
|
|
|
* @param string $custom_cap The custom capability that is being tested. |
275
|
|
|
* @param array $expected_caps The expected output. |
276
|
|
|
*/ |
277
|
|
|
public function test_jetpack_connection_custom_caps( $in_offline_mode, $custom_cap, $expected_caps ) { |
278
|
|
|
// Mock the apply_filters( 'jetpack_offline_mode', ) call in Status::is_offline_mode. |
279
|
|
|
add_filter( |
280
|
|
|
'jetpack_offline_mode', |
281
|
|
|
function () use ( $in_offline_mode ) { |
282
|
|
|
return $in_offline_mode; |
283
|
|
|
} |
284
|
|
|
); |
285
|
|
|
|
286
|
|
|
$caps = $this->manager->jetpack_connection_custom_caps( self::DEFAULT_TEST_CAPS, $custom_cap, 1, array() ); |
287
|
|
|
$this->assertEquals( $expected_caps, $caps ); |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
/** |
291
|
|
|
* Data provider test_jetpack_connection_custom_caps. |
292
|
|
|
* |
293
|
|
|
* Structure of the test data arrays: |
294
|
|
|
* [0] => 'in_offline_mode' boolean Whether offline mode is active. |
295
|
|
|
* [1] => 'custom_cap' string The custom capability that is being tested. |
296
|
|
|
* [2] => 'expected_caps' array The expected output of the call to jetpack_connection_custom_caps. |
297
|
|
|
*/ |
298
|
|
|
public function jetpack_connection_custom_caps_data_provider() { |
299
|
|
|
|
300
|
|
|
return array( |
301
|
|
|
'offline mode, jetpack_connect' => array( true, 'jetpack_connect', array( 'do_not_allow' ) ), |
302
|
|
|
'offline mode, jetpack_reconnect' => array( true, 'jetpack_reconnect', array( 'do_not_allow' ) ), |
303
|
|
|
'offline mode, jetpack_disconnect' => array( true, 'jetpack_disconnect', array( 'manage_options' ) ), |
304
|
|
|
'offline mode, jetpack_connect_user' => array( true, 'jetpack_connect_user', array( 'do_not_allow' ) ), |
305
|
|
|
'offline mode, unknown cap' => array( true, 'unknown_cap', self::DEFAULT_TEST_CAPS ), |
306
|
|
|
'not offline mode, jetpack_connect' => array( false, 'jetpack_connect', array( 'manage_options' ) ), |
307
|
|
|
'not offline mode, jetpack_reconnect' => array( false, 'jetpack_reconnect', array( 'manage_options' ) ), |
308
|
|
|
'not offline mode, jetpack_disconnect' => array( false, 'jetpack_disconnect', array( 'manage_options' ) ), |
309
|
|
|
'not offline mode, jetpack_connect_user' => array( false, 'jetpack_connect_user', array( 'read' ) ), |
310
|
|
|
'not offline mode, unknown cap' => array( false, 'unknown_cap', self::DEFAULT_TEST_CAPS ), |
311
|
|
|
); |
312
|
|
|
} |
313
|
|
|
|
314
|
|
|
/** |
315
|
|
|
* Test the `get_signed_token` functionality. |
316
|
|
|
* |
317
|
|
|
* @covers Automattic\Jetpack\Connection\Manager::get_signed_token |
318
|
|
|
*/ |
319
|
|
|
public function test_get_signed_token() { |
320
|
|
|
$access_token = (object) array( |
321
|
|
|
'external_user_id' => 1, |
322
|
|
|
); |
323
|
|
|
|
324
|
|
|
$manager = ( new Manager() ); |
325
|
|
|
// Missing secret. |
326
|
|
|
$invalid_token_error = new WP_Error( 'invalid_token' ); |
|
|
|
|
327
|
|
|
$this->assertEquals( $invalid_token_error, $manager->get_signed_token( $access_token ) ); |
328
|
|
|
// Secret is null. |
329
|
|
|
$access_token->secret = null; |
330
|
|
|
$this->assertEquals( $invalid_token_error, $manager->get_signed_token( $access_token ) ); |
331
|
|
|
// Secret is empty. |
332
|
|
|
$access_token->secret = ''; |
333
|
|
|
$this->assertEquals( $invalid_token_error, $manager->get_signed_token( $access_token ) ); |
334
|
|
|
// Valid secret. |
335
|
|
|
$access_token->secret = 'abcd.1234'; |
336
|
|
|
|
337
|
|
|
$signed_token = $manager->get_signed_token( $access_token ); |
338
|
|
|
$this->assertTrue( strpos( $signed_token, 'token' ) !== false ); |
339
|
|
|
$this->assertTrue( strpos( $signed_token, 'timestamp' ) !== false ); |
340
|
|
|
$this->assertTrue( strpos( $signed_token, 'nonce' ) !== false ); |
341
|
|
|
$this->assertTrue( strpos( $signed_token, 'signature' ) !== false ); |
342
|
|
|
} |
343
|
|
|
|
344
|
|
|
/** |
345
|
|
|
* Filter to set the default constant values. |
346
|
|
|
* |
347
|
|
|
* @param string $value Existing value (empty and ignored). |
348
|
|
|
* @param string $name Constant name. |
349
|
|
|
* |
350
|
|
|
* @see Utils::DEFAULT_JETPACK__API_BASE |
351
|
|
|
* @see Utils::DEFAULT_JETPACK__API_VERSION |
352
|
|
|
* |
353
|
|
|
* @return string |
354
|
|
|
*/ |
355
|
|
|
public function filter_api_constant( $value, $name ) { |
356
|
|
|
return constant( __NAMESPACE__ . "\Utils::DEFAULT_$name" ); |
357
|
|
|
} |
358
|
|
|
|
359
|
|
|
} |
360
|
|
|
|
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.