Completed
Push — add/rna-connection-in-place ( d17300...c4ab4e )
by
unknown
151:44 queued 141:08
created

wpSetupBeforeClass()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
3
use Automattic\Jetpack\Connection\Tokens;
4
5
class WP_Test_Jetpack_XMLRPC_Server extends WP_UnitTestCase {
6
	static $xmlrpc_admin = 0;
7
8
	public static function wpSetupBeforeClass( $factory ) {
9
		$user_id = $factory->user->create();
10
		$user = get_user_by( 'ID', $user_id );
11
		$user->set_role( 'administrator' );
12
		( new Tokens() )->update_user_token( $user_id, sprintf( '%s.%s.%d', 'key', 'private', $user_id ), false );
13
14
		self::$xmlrpc_admin = $user_id;
15
	}
16
17
	function test_xmlrpc_features_available() {
18
		$server = new Jetpack_XMLRPC_Server();
19
		$response = $server->features_available();
20
21
		// trivial assertion
22
		$this->assertTrue( in_array( 'publicize', $response ) );
23
	}
24
25 View Code Duplication
	function test_xmlrpc_get_user_by_id() {
26
		$user = get_user_by( 'id', self::$xmlrpc_admin );
27
		$server = new Jetpack_XMLRPC_Server();
28
29
		$response = $server->get_user( $user->ID );
30
		$this->assertGetUserEqual( $user, $response );
31
		$this->assertEquals( 'key', $response['token_key'] );
32
	}
33
34 View Code Duplication
	function test_xmlrpc_get_user_by_user_login() {
35
		$user = get_user_by( 'id', self::$xmlrpc_admin );
36
		$server = new Jetpack_XMLRPC_Server();
37
38
		$response = $server->get_user( $user->user_login );
39
		$this->assertGetUserEqual( $user, $response );
40
		$this->assertEquals( 'key', $response['token_key'] );
41
	}
42
43 View Code Duplication
	function test_xmlrpc_get_user_by_user_email() {
44
		$user = get_user_by( 'id', self::$xmlrpc_admin );
45
		$server = new Jetpack_XMLRPC_Server();
46
47
		$response = $server->get_user( $user->user_email );
48
		$this->assertGetUserEqual( $user, $response );
49
		$this->assertEquals( 'key', $response['token_key'] );
50
	}
51
52 View Code Duplication
	function test_xmlrpc_get_user_invalid_input() {
53
		$server = new Jetpack_XMLRPC_Server();
54
55
		$missing_response = $server->get_user( '' );
56
57
		$this->assertEquals( 'IXR_Error', get_class( $missing_response ) );
58
		$this->assertEquals( 400, $missing_response->code );
59
		$this->assertEquals( 'Jetpack: [invalid_user] Invalid user identifier.', $missing_response->message );
60
	}
61
62 View Code Duplication
	function test_xmlrpc_get_user_no_matching_user() {
63
		$server = new Jetpack_XMLRPC_Server();
64
65
		$missing_response = $server->get_user( '[email protected]' );
66
67
		$this->assertEquals( 'IXR_Error', get_class( $missing_response ) );
68
		$this->assertEquals( 404, $missing_response->code );
69
		$this->assertEquals( 'Jetpack: [user_unknown] User not found.', $missing_response->message );
70
	}
71
72
	protected function assertGetUserEqual( $user, $response ) {
73
		$this->assertEquals( $user->ID, $response['id'] );
74
		$this->assertEquals( md5( strtolower( trim( $user->user_email ) ) ), $response['email_hash'] );
75
		$this->assertEquals( $user->user_login, $response['login'] );
76
		$this->assertEquals( sort( $user->roles ), sort( $response['roles'] ) );
77
		$this->assertEquals( sort( $user->caps ), sort( $response['caps'] ) );
78
		$this->assertEquals( sort( $user->allcaps ), sort( $response['allcaps'] ) );
79
	}
80
81 View Code Duplication
	function test_xmlrpc_remote_register_fails_no_nonce() {
82
		$server = new Jetpack_XMLRPC_Server();
83
84
		$response = $server->remote_register( array( 'local_user' => '1' ) );
85
		$this->assertInstanceOf( 'IXR_Error', $response );
86
		$this->assertEquals( 400, $response->code );
87
		$this->assertContains( '[nonce_missing]', $response->message );
88
	}
89
90 View Code Duplication
	function test_xmlrpc_remote_provision_fails_no_local_user() {
91
		$server = new Jetpack_XMLRPC_Server();
92
		$response = $server->remote_provision( array( 'nonce' => '12345' ) );
93
		$this->assertInstanceOf( 'IXR_Error', $response );
94
		$this->assertEquals( 400, $response->code );
95
		$this->assertContains( '[local_user_missing]', $response->message );
96
	}
97
98
	function test_xmlrpc_remote_register_nonce_validation() {
99
		$server = new Jetpack_XMLRPC_Server();
100
		$filters = array(
101
			'return_invalid_nonce_status' => array(
102
				'code' => 400,
103
				'message' => 'invalid_nonce',
104
			),
105
			'return_nonce_404_status'     => array(
106
				'code' => 400,
107
				'message' => 'invalid_nonce',
108
			),
109
		);
110
111
		foreach ( $filters as $filter => $expected ) {
112
			add_filter( 'pre_http_request', array( $this, $filter ) );
113
			$response = $server->remote_register( array( 'nonce' => '12345', 'local_user' => '1' ) );
114
			remove_filter( 'pre_http_request', array( $this, $filter ) );
115
116
			$this->assertInstanceOf( 'IXR_Error', $response );
117
			$this->assertEquals( $expected['code'], $response->code );
118
			$this->assertContains( sprintf( '[%s]', $expected['message'] ), $response->message );
119
		}
120
	}
121
122
	function test_successful_remote_register_return() {
123
		$server = new Jetpack_XMLRPC_Server();
124
125
		$blog_token = Jetpack_Options::get_option( 'blog_token' );
0 ignored issues
show
Unused Code introduced by
$blog_token is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
126
		$id         = Jetpack_Options::get_option( 'id' );
0 ignored issues
show
Unused Code introduced by
$id is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
127
128
		// Set these so that we don't try to register unnecessarily.
129
		Jetpack_Options::update_option( 'blog_token', 1 );
130
		Jetpack_Options::update_option( 'id', 1001 );
131
132
		add_filter( 'pre_http_request', array( $this, 'return_ok_status' ) );
133
		$response = $server->remote_register( array( 'nonce' => '12345', 'local_user' => '1' ) );
134
		remove_filter( 'pre_http_request', array( $this, 'return_ok_status' ) );
135
136
		$this->assertInternalType( 'array', $response );
137
		$this->assertArrayHasKey( 'client_id', $response );
138
		$this->assertEquals( 1001, $response['client_id'] );
139
	}
140
141 View Code Duplication
	function test_remote_provision_error_nonexistent_user() {
142
		$server = new Jetpack_XMLRPC_Server();
143
		$response = $server->remote_provision( array() );
144
145
		$this->assertInstanceOf( 'IXR_Error', $response );
146
		$this->assertContains( 'local_user_missing', $response->message );
147
148
		$response = $server->remote_provision( array( 'local_user' => 'nonexistent' ) );
149
150
		$this->assertInstanceOf( 'IXR_Error', $response );
151
		$this->assertEquals( 'Jetpack: [input_error] Valid user is required', $response->message );
152
	}
153
154
	function test_remote_provision_success() {
155
		$server = new Jetpack_XMLRPC_Server();
156
		$response = $server->remote_provision( array( 'local_user' => 1 ) );
157
158
		$this->assertInternalType( 'array', $response );
159
160
		$expected_keys = array(
161
			'jp_version',
162
			'redirect_uri',
163
			'user_id',
164
			'user_email',
165
			'user_login',
166
			'scope',
167
			'secret',
168
			'is_active',
169
		);
170
171
		foreach ( $expected_keys as $key ) {
172
			$this->assertArrayHasKey( $key, $response );
173
		}
174
	}
175
176
	public function test_remote_connect_error_when_site_active() {
177
		// Simulate the site being active.
178
		Jetpack_Options::update_options( array(
179
			'blog_token'  => 1,
180
			'id'          => 1001,
181
		) );
182
		( new Tokens() )->update_user_token( 1, sprintf( '%s.%d', 'token', 1 ), true );
183
184
		$server = new Jetpack_XMLRPC_Server();
185
186
		$response = $server->remote_connect( array(
187
			'nonce'      => '1234',
188
			'local_user' => '1',
189
		) );
190
191
		$this->assertInstanceOf( 'IXR_Error', $response );
192
		$this->assertObjectHasAttribute( 'code', $response );
193
		$this->assertObjectHasAttribute( 'message', $response );
194
		$this->assertEquals( 400, $response->code );
195
		$this->assertEquals(
196
			'Jetpack: [token_fetch_failed] Failed to fetch user token from WordPress.com.',
197
			$response->message
198
		);
199
200
		foreach ( array( 'blog_token', 'id','master_user', 'user_tokens' ) as $option_name ) {
201
			Jetpack_Options::delete_option( $option_name );
202
		}
203
	}
204
205 View Code Duplication
	public function test_remote_connect_error_invalid_user() {
206
		$server = new Jetpack_XMLRPC_Server();
207
		$response = $server->remote_connect( array(
208
			'nonce'      => '1234',
209
			'local_user' => '100000000',
210
		) );
211
212
		$this->assertInstanceOf( 'IXR_Error', $response );
213
		$this->assertObjectHasAttribute( 'code', $response );
214
		$this->assertObjectHasAttribute( 'message', $response );
215
		$this->assertEquals( 400, $response->code );
216
		$this->assertEquals(
217
			'Jetpack: [input_error] Valid user is required.',
218
			$response->message
219
		);
220
	}
221
222
	public function test_remote_connect_empty_nonce() {
223
		$server = new Jetpack_XMLRPC_Server();
224
		$response = $server->remote_connect( array(
225
			'local_user' => '1',
226
		) );
227
228
		$this->assertInstanceOf( 'IXR_Error', $response );
229
		$this->assertObjectHasAttribute( 'code', $response );
230
		$this->assertObjectHasAttribute( 'message', $response );
231
		$this->assertEquals( 400, $response->code );
232
		$this->assertEquals(
233
			'Jetpack: [input_error] A non-empty nonce must be supplied.',
234
			$response->message
235
		);
236
	}
237
238
	public function test_remote_connect_fails_no_blog_token() {
239
		Jetpack_Options::delete_option( 'blog_token' );
240
241
		$server = new Jetpack_XMLRPC_Server();
242
243
		add_filter( 'pre_http_request', array( $this, '__return_token' ) );
244
		$response = $server->remote_connect( array(
245
			'nonce'      => '1234',
246
			'local_user' => '1',
247
		) );
248
249
		$this->assertInstanceOf( 'IXR_Error', $response );
250
		$this->assertObjectHasAttribute( 'code', $response );
251
		$this->assertObjectHasAttribute( 'message', $response );
252
		$this->assertEquals( 400, $response->code );
253
		$this->assertEquals(
254
			'Jetpack: [token_fetch_failed] Failed to fetch user token from WordPress.com.',
255
			$response->message
256
		);
257
	}
258
259
	public function test_remote_connect_nonce_validation_error() {
260
		Jetpack_Options::update_options( array(
261
			'id'         => 1001,
262
			'blog_token' =>  '123456.123456',
263
		) );
264
265
		$server = $this->get_mocked_xmlrpc_server();
266
		$response = $server->remote_connect( array(
267
			'nonce'      => '1234',
268
			'local_user' => '1',
269
		), $this->get_mocked_ixr_client( true, false ) );
270
271
		$this->assertInstanceOf( 'IXR_Error', $response );
272
		$this->assertObjectHasAttribute( 'code', $response );
273
		$this->assertObjectHasAttribute( 'message', $response );
274
		$this->assertEquals( 400, $response->code );
275
		$this->assertEquals(
276
			'Jetpack: [token_fetch_failed] Failed to fetch user token from WordPress.com.',
277
			$response->message
278
		);
279
	}
280
281
	public function test_remote_connect_success() {
282
		Jetpack_Options::update_options( array(
283
			'id'         => 1001,
284
			'blog_token' =>  '123456.123456',
285
		) );
286
287
		$server = $this->get_mocked_xmlrpc_server();
288
		$response = $server->remote_connect( array(
289
			'nonce'      => '1234',
290
			'local_user' => '1',
291
		), $this->get_mocked_ixr_client( true, 'this_is.a_token' ) );
292
293
		$this->assertTrue( $response );
294
	}
295
296
	/*
297
	 * Helpers
298
	 */
299
300
	/**
301
	 * Return an "ok" status.
302
	 *
303
	 * @return array
304
	 */
305
	public function return_ok_status() {
306
		return array(
307
			'body'     => 'OK',
308
			'response' => array(
309
				'code'    => 200,
310
				'message' => '',
311
			),
312
		);
313
	}
314
315
	/**
316
	 * Return an "invalid nonce" status.
317
	 *
318
	 * @return array
319
	 */
320
	public function return_invalid_nonce_status() {
321
		return array(
322
			'body'     => 'FAIL: NOT OK',
323
			'response' => array(
324
				'code'    => 200,
325
				'message' => '',
326
			),
327
		);
328
	}
329
330
	/**
331
	 * Return an "nonce 404" status.
332
	 *
333
	 * @return array
334
	 */
335
	public function return_nonce_404_status() {
336
		return array(
337
			'body'     => '',
338
			'response' => array(
339
				'code'    => 404,
340
				'message' => '',
341
			),
342
		);
343
	}
344
345
	/**
346
	 * Get a mocked IXR client.
347
	 *
348
	 * @param bool   $query_called Whether `query` should be called.
349
	 * @param string $response Return value for `getResponse`.
350
	 * @param bool   $query_return Return value for `query`.
351
	 * @param string $error Return value for `isError`.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $error not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
352
	 * @return Jetpack_IXR_Client
353
	 */
354
	protected function get_mocked_ixr_client( $query_called = false, $response = '', $query_return = true, $error = null ) {
355
		$xml = $this->getMockBuilder( 'Jetpack_IXR_Client' )
356
			->setMethods(
357
				array(
358
					'query',
359
					'isError',
360
					'getResponse',
361
				)
362
			)
363
			->getMock();
364
365
		$xml->expects( $this->exactly( $query_called ? 1 : 0 ) )
366
			->method( 'query' )
367
			->will( $this->returnValue( $query_return ) );
368
369
		$xml->expects( $this->exactly( $query_called ? 1 : 0 ) )
370
			->method( 'isError' )
371
			->will( $this->returnValue( empty( $error ) ? false : true ) );
372
373
		$xml->expects( $this->exactly( empty( $error ) ? 1 : 0 ) )
374
			->method( 'getResponse' )
375
			->will( $this->returnValue( $response ) );
376
377
		return $xml;
378
	}
379
380
	/**
381
	 * Get a mocked XMLRPC server.
382
	 *
383
	 * @return Jetpack_XMLRPC_Server
384
	 */
385
	protected function get_mocked_xmlrpc_server() {
386
		$server = $this->getMockBuilder( 'Jetpack_XMLRPC_Server' )
387
			->setMethods(
388
				array(
389
					'do_post_authorization',
390
				)
391
			)
392
			->getMock();
393
394
		$server->expects( $this->any() )
395
			->method( 'do_post_authorization' )
396
			->will( $this->returnValue( true ) );
397
398
		return $server;
399
	}
400
}
401