Completed
Push — master ( 8deb21...2e9082 )
by
unknown
10:27
created

Test_REST_Controller::set_up()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
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
			$_SERVER['REQUEST_METHOD']
57
		);
58
		// phpcs:enable WordPress.Security.NonceVerification.Recommended
59
60
		WorDBless_Options::init()->clear_options();
61
	}
62
63
	/**
64
	 * Testing the `POST /jetpack/v4/backup-helper-script` endpoint when the `helper` param is missing.
65
	 */
66 View Code Duplication
	public function test_install_backup_helper_script_missing_required_param() {
67
		$request  = new WP_REST_Request( 'POST', '/jetpack/v4/backup-helper-script' );
68
		$response = $this->server->dispatch( $request );
69
		$this->assertEquals( 400, $response->get_status() );
70
		$this->assertEquals( 'Missing parameter(s): helper', $response->get_data()['message'] );
71
	}
72
73
	/**
74
	 * Testing the `POST /jetpack/v4/backup-helper-script` endpoint with admin user.
75
	 */
76 View Code Duplication
	public function test_install_backup_helper_script_unauthorized() {
77
		$user = wp_get_current_user();
78
		$user->set_role( 'administrator' );
79
		$body    = array(
80
			'helper' => 'dummy',
81
		);
82
		$request = new WP_REST_Request( 'POST', '/jetpack/v4/backup-helper-script' );
83
		$request->set_header( 'content-type', 'application/json' );
84
		$request->set_body( wp_json_encode( $body ) );
85
		$response = $this->server->dispatch( $request );
86
		$this->assertEquals( 401, $response->get_status() );
87
		$this->assertEquals( 'You are not allowed to perform this action.', $response->get_data()['message'] );
88
89
		// Cleanup.
90
		$user->remove_role( 'administrator' );
91
	}
92
93
	/**
94
	 * Testing the `POST /jetpack/v4/backup-helper-script` endpoint on success.
95
	 */
96
	public function test_install_backup_helper_script_success() {
97
		wp_set_current_user( 0 );
98
		$body = array(
99
			// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
100
			'helper' => base64_encode( "<?php /* Jetpack Backup Helper Script */\n" ),
101
		);
102
103
		$request = new WP_REST_Request( 'POST', '/jetpack/v4/backup-helper-script' );
104
		$request->set_header( 'content-type', 'application/json' );
105
		$request->set_body( wp_json_encode( $body ) );
106
107
		$response = $this->dispatch_request_signed_with_blog_token( $request );
108
		$this->assertEquals( 200, $response->get_status() );
109
		$response_data = $response->get_data();
110
		$this->assertArrayHasKey( 'url', $response_data );
111
		$this->assertArrayHasKey( 'abspath', $response_data );
112
		$this->assertArrayHasKey( 'path', $response_data );
113
114
		// Cleanup.
115
		unlink( $response_data['path'] );
116
	}
117
118
	/**
119
	 * Testing the `DELETE /jetpack/v4/backup-helper-script` endpoint when the `path` param is missing.
120
	 */
121 View Code Duplication
	public function test_delete_backup_helper_script_missing_required_param() {
122
		$request  = new WP_REST_Request( 'DELETE', '/jetpack/v4/backup-helper-script' );
123
		$response = $this->server->dispatch( $request );
124
		$this->assertEquals( 400, $response->get_status() );
125
		$this->assertEquals( 'Missing parameter(s): path', $response->get_data()['message'] );
126
	}
127
128
	/**
129
	 * Testing the `DELETE /jetpack/v4/backup-helper-script` endpoint with admin user.
130
	 */
131 View Code Duplication
	public function test_delete_backup_helper_script_unauthorized() {
132
		$user = wp_get_current_user();
133
		$user->set_role( 'administrator' );
134
		$body = array(
135
			'path' => 'dummy',
136
		);
137
138
		$request = new WP_REST_Request( 'DELETE', '/jetpack/v4/backup-helper-script' );
139
		$request->set_header( 'content-type', 'application/json' );
140
		$request->set_body( wp_json_encode( $body ) );
141
		$response = $this->server->dispatch( $request );
142
143
		$this->assertEquals( 401, $response->get_status() );
144
		$this->assertEquals( 'You are not allowed to perform this action.', $response->get_data()['message'] );
145
146
		// Cleanup.
147
		$user->remove_role( 'administrator' );
148
	}
149
150
	/**
151
	 * Testing the `DELETE /jetpack/v4/backup-helper-script` endpoint on success.
152
	 */
153 View Code Duplication
	public function test_delete_backup_helper_script_success() {
154
		wp_set_current_user( 0 );
155
		$body = array(
156
			'path' => 'dummy',
157
		);
158
159
		$request = new WP_REST_Request( 'DELETE', '/jetpack/v4/backup-helper-script' );
160
		$request->set_header( 'content-type', 'application/json' );
161
		$request->set_body( wp_json_encode( $body ) );
162
163
		$response = $this->dispatch_request_signed_with_blog_token( $request );
164
		$this->assertEquals( 200, $response->get_status() );
165
166
		$this->assertTrue( $response->get_data()['success'] );
167
	}
168
169
	/**
170
	 * Signs a request with a blog token before dispatching it.
171
	 *
172
	 * Ensures that these tests pass through Connection_Rest_Authentication::wp_rest_authenticate,
173
	 * because WP_REST_Server::dispatch doesn't call any auth logic (in a real
174
	 * request, this would all happen earlier).
175
	 *
176
	 * @param WP_REST_Request $request The request to sign before dispatching.
177
	 * @return WP_REST_Response
178
	 */
179
	private function dispatch_request_signed_with_blog_token( $request ) {
180
		add_filter( 'jetpack_options', array( $this, 'mock_jetpack_site_connection_options' ), 10, 2 );
181
182
		$token     = 'new:1:0';
183
		$timestamp = (string) time();
184
		$nonce     = 'testing123';
185
		$body_hash = '';
186
187
		$_SERVER['REQUEST_METHOD'] = 'POST';
188
189
		$_GET['_for']      = 'jetpack';
190
		$_GET['token']     = $token;
191
		$_GET['timestamp'] = $timestamp;
192
		$_GET['nonce']     = $nonce;
193
		$_GET['body-hash'] = $body_hash;
194
		// This is intentionally using base64_encode().
195
		// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
196
		$_GET['signature'] = base64_encode(
197
			hash_hmac(
198
				'sha1',
199
				implode(
200
					"\n",
201
					array(
202
						$token,
203
						$timestamp,
204
						$nonce,
205
						$body_hash,
206
						'POST',
207
						'anything.example',
208
						'80',
209
						'',
210
					)
211
				) . "\n",
212
				'blogtoken',
213
				true
214
			)
215
		);
216
217
		$jp_connection_auth = Connection_Rest_Authentication::init();
218
		$jp_connection_auth->wp_rest_authenticate( false );
219
220
		$response = $this->server->dispatch( $request );
221
222
		$jp_connection_auth->reset_saved_auth_state();
223
224
		remove_filter( 'jetpack_options', array( $this, 'mock_jetpack_site_connection_options' ) );
225
226
		return $response;
227
	}
228
229
	/**
230
	 * Intercept the `Jetpack_Options` call and mock the values.
231
	 * Site level / user-less connection set-up.
232
	 *
233
	 * @param mixed  $value The current option value.
234
	 * @param string $name Option name.
235
	 *
236
	 * @return mixed
237
	 */
238
	public function mock_jetpack_site_connection_options( $value, $name ) {
239
		switch ( $name ) {
240
			case 'blog_token':
241
				return 'new.blogtoken';
242
			case 'id':
243
				return '999';
244
		}
245
246
		return $value;
247
	}
248
249
}
250