Completed
Push — update/backup-v4-endpoints ( 8ea944 )
by
unknown
11:43
created

Test_REST_Controller   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 231
Duplicated Lines 25.54 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
dl 59
loc 231
rs 10
c 0
b 0
f 0
wmc 12
lcom 1
cbo 1

10 Methods

Rating   Name   Duplication   Size   Complexity  
A set_up() 0 11 1
A tear_down() 0 14 1
A test_backup_helper_script_missing_required_param() 6 6 1
A test_backup_helper_script_unauthorized() 16 16 1
A test_backup_helper_script_success() 0 21 1
A test_delete_backup_helper_script_missing_required_param() 6 6 1
A test_delete_backup_helper_script_unauthorized() 16 16 1
A test_delete_backup_helper_script_success() 15 15 1
A dispatch_request_signed_with_blog_token() 0 49 1
A mock_jetpack_site_connection_options() 0 10 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
3
namespace Automattic\Jetpack\Backup;
4
5
use Automattic\Jetpack\Connection\Rest_Authentication as Connection_Rest_Authentication;
6
use PHPUnit\Framework\TestCase;
7
use WorDBless\Options as WorDBless_Options;
8
use WP_REST_Request;
9
use WP_REST_Server;
10
11
/**
12
 * Unit tests for the REST_Controller class.
13
 *
14
 * @package automattic/jetpack-backup
15
 */
16
class Test_REST_Controller extends TestCase {
17
18
	/**
19
	 * REST Server object.
20
	 *
21
	 * @var WP_REST_Server
22
	 */
23
	private $server;
24
25
	/**
26
	 * Setting up the test.
27
	 *
28
	 * @before
29
	 */
30
	public function set_up() {
31
		global $wp_rest_server;
32
33
		$wp_rest_server = new WP_REST_Server();
34
		$this->server   = $wp_rest_server;
35
36
		// Register REST routes.
37
		add_action( 'rest_api_init', array( 'Automattic\\Jetpack\\Backup\\REST_Controller', 'register_rest_routes' ) );
38
39
		do_action( 'rest_api_init' );
40
	}
41
42
	/**
43
	 * Returning the environment into its initial state.
44
	 *
45
	 * @after
46
	 */
47
	public function tear_down() {
48
		// phpcs:disable WordPress.Security.NonceVerification.Recommended
49
		unset(
50
			$_GET['_for'],
51
			$_GET['token'],
52
			$_GET['timestamp'],
53
			$_GET['nonce'],
54
			$_GET['body-hash'],
55
			$_GET['signature']
56
		);
57
		// phpcs:enable WordPress.Security.NonceVerification.Recommended
58
59
		WorDBless_Options::init()->clear_options();
60
	}
61
62
	/**
63
	 * Testing the `/jetpack/v4/backup-helper-script` endpoint when the `helper` param is missing.
64
	 */
65 View Code Duplication
	public function test_backup_helper_script_missing_required_param() {
66
		$request  = new WP_REST_Request( 'POST', '/jetpack/v4/backup-helper-script' );
67
		$response = $this->server->dispatch( $request );
68
		$this->assertEquals( 400, $response->get_status() );
69
		$this->assertEquals( 'Missing parameter(s): helper', $response->get_data()['message'] );
70
	}
71
72
	/**
73
	 * Testing the `/jetpack/v4/backup-helper-script` endpoint with admin user.
74
	 */
75 View Code Duplication
	public function test_backup_helper_script_unauthorized() {
76
		$user = wp_get_current_user();
77
		$user->set_role( 'administrator' );
78
		$body    = array(
79
			'helper' => 'dummy',
80
		);
81
		$request = new WP_REST_Request( 'POST', '/jetpack/v4/backup-helper-script' );
82
		$request->set_header( 'content-type', 'application/json' );
83
		$request->set_body( wp_json_encode( $body ) );
84
		$response = $this->server->dispatch( $request );
85
		$this->assertEquals( 401, $response->get_status() );
86
		$this->assertEquals( 'You are not allowed to perform this action.', $response->get_data()['message'] );
87
88
		// Cleanup.
89
		$user->remove_role( 'administrator' );
90
	}
91
92
	/**
93
	 * Testing the `/jetpack/v4/backup-helper-script` endpoint on success.
94
	 */
95
	public function test_backup_helper_script_success() {
96
		wp_set_current_user( 0 );
97
		$body = array(
98
			// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
99
			'helper' => base64_encode( "<?php /* Jetpack Backup Helper Script */\n" ),
100
		);
101
102
		$request = new WP_REST_Request( 'POST', '/jetpack/v4/backup-helper-script' );
103
		$request->set_header( 'content-type', 'application/json' );
104
		$request->set_body( wp_json_encode( $body ) );
105
106
		$response = $this->dispatch_request_signed_with_blog_token( $request );
107
		$this->assertEquals( 200, $response->get_status() );
108
		$response_data = $response->get_data();
109
		$this->assertArrayHasKey( 'url', $response_data );
110
		$this->assertArrayHasKey( 'abspath', $response_data );
111
		$this->assertArrayHasKey( 'path', $response_data );
112
113
		// Cleanup.
114
		unlink( $response_data['path'] );
115
	}
116
117
	/**
118
	 * Testing the `/jetpack/v4/delete-backup-helper-script` endpoint when the `path` param is missing.
119
	 */
120 View Code Duplication
	public function test_delete_backup_helper_script_missing_required_param() {
121
		$request  = new WP_REST_Request( 'POST', '/jetpack/v4/delete-backup-helper-script' );
122
		$response = $this->server->dispatch( $request );
123
		$this->assertEquals( 400, $response->get_status() );
124
		$this->assertEquals( 'Missing parameter(s): path', $response->get_data()['message'] );
125
	}
126
127
	/**
128
	 * Testing the `/jetpack/v4/delete-backup-helper-script` endpoint with admin user.
129
	 */
130 View Code Duplication
	public function test_delete_backup_helper_script_unauthorized() {
131
		$user = wp_get_current_user();
132
		$user->set_role( 'administrator' );
133
		$body    = array(
134
			'path' => 'dummy',
135
		);
136
		$request = new WP_REST_Request( 'POST', '/jetpack/v4/delete-backup-helper-script' );
137
		$request->set_header( 'content-type', 'application/json' );
138
		$request->set_body( wp_json_encode( $body ) );
139
		$response = $this->server->dispatch( $request );
140
		$this->assertEquals( 401, $response->get_status() );
141
		$this->assertEquals( 'You are not allowed to perform this action.', $response->get_data()['message'] );
142
143
		// Cleanup.
144
		$user->remove_role( 'administrator' );
145
	}
146
147
	/**
148
	 * Testing the `/jetpack/v4/delete-backup-helper-script` endpoint on success.
149
	 */
150 View Code Duplication
	public function test_delete_backup_helper_script_success() {
151
		wp_set_current_user( 0 );
152
		$body = array(
153
			'path' => 'dummy',
154
		);
155
156
		$request = new WP_REST_Request( 'POST', '/jetpack/v4/delete-backup-helper-script' );
157
		$request->set_header( 'content-type', 'application/json' );
158
		$request->set_body( wp_json_encode( $body ) );
159
160
		$response = $this->dispatch_request_signed_with_blog_token( $request );
161
		$this->assertEquals( 200, $response->get_status() );
162
163
		$this->assertTrue( $response->get_data()['success'] );
164
	}
165
166
	/**
167
	 * Signs a request with a blog token before dispatching it.
168
	 *
169
	 * Ensures that these tests pass through Connection_Rest_Authentication::wp_rest_authenticate,
170
	 * because WP_REST_Server::dispatch doesn't call any auth logic (in a real
171
	 * request, this would all happen earlier).
172
	 *
173
	 * @param WP_REST_Request $request The request to sign before dispatching.
174
	 * @return WP_REST_Response
175
	 */
176
	private function dispatch_request_signed_with_blog_token( $request ) {
177
		add_filter( 'jetpack_options', array( $this, 'mock_jetpack_site_connection_options' ), 10, 2 );
178
179
		$token     = 'new:1:0';
180
		$timestamp = (string) time();
181
		$nonce     = 'testing123';
182
		$body_hash = '';
183
184
		$_SERVER['REQUEST_METHOD'] = 'POST';
185
186
		$_GET['_for']      = 'jetpack';
187
		$_GET['token']     = $token;
188
		$_GET['timestamp'] = $timestamp;
189
		$_GET['nonce']     = $nonce;
190
		$_GET['body-hash'] = $body_hash;
191
		// This is intentionally using base64_encode().
192
		// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
193
		$_GET['signature'] = base64_encode(
194
			hash_hmac(
195
				'sha1',
196
				implode(
197
					"\n",
198
					$data  = array(
199
						$token,
200
						$timestamp,
201
						$nonce,
202
						$body_hash,
203
						'POST',
204
						'anything.example',
205
						'80',
206
						'',
207
					)
208
				) . "\n",
209
				'blogtoken',
210
				true
211
			)
212
		);
213
214
		$jp_connection_auth = Connection_Rest_Authentication::init();
215
		$jp_connection_auth->wp_rest_authenticate( false );
216
217
		$response = $this->server->dispatch( $request );
218
219
		$jp_connection_auth->reset_saved_auth_state();
220
221
		remove_filter( 'jetpack_options', array( $this, 'mock_jetpack_site_connection_options' ) );
222
223
		return $response;
224
	}
225
226
	/**
227
	 * Intercept the `Jetpack_Options` call and mock the values.
228
	 * Site level / user-less connection set-up.
229
	 *
230
	 * @param mixed  $value The current option value.
231
	 * @param string $name Option name.
232
	 *
233
	 * @return mixed
234
	 */
235
	public function mock_jetpack_site_connection_options( $value, $name ) {
236
		switch ( $name ) {
237
			case 'blog_token':
238
				return 'new.blogtoken';
239
			case 'id':
240
				return '999';
241
		}
242
243
		return $value;
244
	}
245
246
}
247