Completed
Push — ignore/lazy-images-linting-pac... ( 3c044f...b5c515 )
by Jeremy
367:06 queued 352:42
created

WP_Test_iJetpack_Sync_Replicastore::setUp()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
nc 4
nop 0
dl 0
loc 17
rs 9.3888
c 0
b 0
f 0
1
<?php
2
3
use Automattic\Jetpack\Sync\Replicastore;
4
5 View Code Duplication
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
6
	require_once ABSPATH . 'wp-content/mu-plugins/jetpack/sync/class.jetpack-sync-test-object-factory.php';
7
} else {
8
	// is running in jetpack
9
	require_once dirname( __FILE__ ) . '/server/class.jetpack-sync-test-object-factory.php';
10
}
11
12
/*
13
 * Tests all known implementations of the replicastore
14
 */
15
16
class WP_Test_iJetpack_Sync_Replicastore extends PHPUnit_Framework_TestCase {
17
	/** @var JetpackSyncTestObjectFactory $factory */
18
	static $factory;
19
	static $token;
20
	static $all_replicastores;
21
22
	public static function setUpBeforeClass() {
23
		parent::setUpBeforeClass();
24
25
		self::$token = (object) array(
26
			'blog_id'          => 101881278, //newsite16.goldsounds.com
27
			'user_id'          => 282285,   //goldsounds
28
			'external_user_id' => 2,
29
			'role'             => 'administrator'
30
		);
31
32
		self::$factory = new JetpackSyncTestObjectFactory();
33
	}
34
35
	public function setUp() {
36
		parent::setUp();
37
38
		if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
39
			switch_to_blog( self::$token->blog_id );
40
		}
41
42
		// this is a hack so that our setUp method can access the $store instance and call reset()
43
		$prop = new ReflectionProperty( 'PHPUnit_Framework_TestCase', 'data' );
44
		$prop->setAccessible( true );
45
		$test_data = $prop->getValue( $this );
46
47
		if ( isset( $test_data[0] ) && $test_data[0] ) {
48
			$store = $test_data[0];
49
			$store->reset();
50
		}
51
	}
52
53
	public function tearDown() {
54
		parent::tearDown();
55
56
		if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
57
			restore_current_blog();
58
		}
59
	}
60
61
	/**
62
	 * Test that the checksum values between implementations are the same
63
	 */
64
	function test_all_checksums_match() {
65
		$this->markTestSkipped( 'Not a Valid E2E test.' );
66
		$post           = self::$factory->post( 5 );
67
		$second_post    = self::$factory->post( 10 );
68
		$comment        = self::$factory->comment( 3, $post->ID );
69
		$second_comment = self::$factory->comment( 6, $second_post->ID );
70
71
		// create an instance of each type of replicastore
72
		$all_replicastores = array();
73
		foreach ( get_declared_classes() as $className ) {
74
			if ( in_array( 'Automattic\\Jetpack\\Sync\\Replicastore_Interface', class_implements( $className ) ) ) {
75
				if ( method_exists( $className, 'getInstance' ) ) {
76
					$all_replicastores[] = call_user_func( array( $className, 'getInstance' ) );
77
				} else {
78
					$all_replicastores[] = new $className();
79
				}
80
			}
81
		}
82
83
		// insert the same data into all of them
84
		foreach ( $all_replicastores as $replicastore ) {
85
			$replicastore->upsert_post( $post );
86
			$replicastore->upsert_metadata( 'post', $post->ID, 'imagedata', 'bar', 1 );
87
			$replicastore->upsert_metadata( 'post', $post->ID, 'publicize_results', 'baz', 2 );
88
			$replicastore->upsert_post( $second_post );
89
			$replicastore->upsert_metadata( 'post', $second_post->ID, 'imagedata', 'bar', 5 );
90
			$replicastore->upsert_metadata( 'post', $second_post->ID, 'publicize_results', 'baz', 10 );
91
			$replicastore->upsert_comment( $comment );
92
			$replicastore->upsert_metadata( 'comment', $comment->comment_ID, 'hc_avatar', 'bar', 1 );
93
			$replicastore->upsert_metadata( 'comment', $comment->comment_ID, 'hc_post_as', 'baz', 4 );
94
			$replicastore->upsert_comment( $second_comment );
95
			$replicastore->upsert_metadata( 'comment', $second_comment->comment_ID, 'hc_avatar', 'boo', 7 );
96
			$replicastore->upsert_metadata( 'comment', $second_comment->comment_ID, 'hc_post_as', 'bee', 10 );
97
		}
98
99
		// ensure the checksums are the same
100
		$checksums = array_map( array( $this, 'get_all_checksums' ), $all_replicastores );
101
102
		// for helpful debug output in case they don't match
103
		$labelled_checksums = array_combine( array_map( 'get_class', $all_replicastores ), $checksums );
104
105
		// find unique checksums - if all checksums are the same, there should be only one element
106
		$unique_checksums_count = count( array_unique( array_map( 'serialize', array_values( $checksums ) ) ) );
107
108
		$this->assertEquals( 1, $unique_checksums_count, 'Checksums do not match: ' . print_r( $labelled_checksums, 1 ) );
109
110
		// compare post histograms
111
		$histograms              = array_map( array( $this, 'get_all_post_histograms' ), $all_replicastores );
112
		$labelled_histograms     = array_combine( array_map( 'get_class', $all_replicastores ), $histograms );
113
		$unique_histograms_count = count( array_unique( array_map( 'serialize', $histograms ) ) );
114
		$this->assertEquals( 1, $unique_histograms_count, 'Post histograms do not match: ' . print_r( $labelled_histograms, 1 ) );
115
116
		$histograms              = array_map( array( $this, 'get_all_post_meta_histograms' ), $all_replicastores );
117
		$labelled_histograms     = array_combine( array_map( 'get_class', $all_replicastores ), $histograms );
118
		$unique_histograms_count = count( array_unique( array_map( 'serialize', $histograms ) ) );
119
		$this->assertEquals( 1, $unique_histograms_count, 'Post meta histograms do not match: ' . print_r( $labelled_histograms, 1 ) );
120
121
		// compare comment histograms
122
		$histograms              = array_map( array( $this, 'get_all_comment_histograms' ), $all_replicastores );
123
		$labelled_histograms     = array_combine( array_map( 'get_class', $all_replicastores ), $histograms );
124
		$unique_histograms_count = count( array_unique( array_map( 'serialize', $histograms ) ) );
125
		$this->assertEquals( 1, $unique_histograms_count, 'Comment histograms do not match: ' . print_r( $labelled_histograms, 1 ) );
126
127
		$histograms              = array_map( array( $this, 'get_all_comment_meta_histograms' ), $all_replicastores );
128
		$labelled_histograms     = array_combine( array_map( 'get_class', $all_replicastores ), $histograms );
129
		$unique_histograms_count = count( array_unique( array_map( 'serialize', $histograms ) ) );
130
		$this->assertEquals( 1, $unique_histograms_count, 'Comment meta histograms do not match: ' . print_r( $labelled_histograms, 1 ) );
131
	}
132
133
	function get_all_checksums( $replicastore ) {
134
		return $replicastore->checksum_all();
135
	}
136
137
	function get_all_post_histograms( $replicastore ) {
138
		return $replicastore->checksum_histogram( 'posts', 10 );
139
	}
140
141
	function get_all_post_meta_histograms( $replicastore ) {
142
		return $replicastore->checksum_histogram( 'post_meta', 10 );
143
	}
144
145
	function get_all_comment_histograms( $replicastore ) {
146
		return $replicastore->checksum_histogram( 'comments', 10 );
147
	}
148
149
	function get_all_comment_meta_histograms( $replicastore ) {
150
		return $replicastore->checksum_histogram( 'comment_meta', 10 );
151
	}
152
153
	/**
154
	 * @dataProvider store_provider
155
	 */
156
	function test_checksum_with_id_range( $store ) {
157
		$post           = self::$factory->post( 5 );
158
		$second_post    = self::$factory->post( 10 );
159
		$comment        = self::$factory->comment( 3, $post->ID );
160
		$second_comment = self::$factory->comment( 6, $second_post->ID );
161
162
		$store->upsert_post( $post );
163
		$store->upsert_metadata( 'post', $post->ID, 'imagedata', 'bar', 1 );
164
		$store->upsert_metadata( 'post', $post->ID, 'publicize_results', 'baz', 2 );
165
		$store->upsert_post( $second_post );
166
		$store->upsert_metadata( 'post', $second_post->ID, 'imagedata', 'bar', 5 );
167
		$store->upsert_metadata( 'post', $second_post->ID, 'publicize_results', 'baz', 10 );
168
		$store->upsert_comment( $comment );
169
		$store->upsert_metadata( 'comment', $comment->comment_ID, 'hc_avatar', 'bar', 1 );
170
		$store->upsert_metadata( 'comment', $comment->comment_ID, 'hc_post_as', 'baz', 4 );
171
		$store->upsert_comment( $second_comment );
172
		$store->upsert_metadata( 'comment', $second_comment->comment_ID, 'hc_avatar', 'boo', 7 );
173
		$store->upsert_metadata( 'comment', $second_comment->comment_ID, 'hc_post_as', 'bee', 10 );
174
175
		// test posts checksum with ID range
176
		$histogram = $store->checksum_histogram( 'posts', 2 );
177
		$this->assertEquals( $store->posts_checksum( 0, 5 ), $histogram['5'] );
178
		$this->assertEquals( $store->posts_checksum( 6, 10 ), $histogram['10'] );
179
180
		// test postmeta checksum with ID range
181
		$histogram = $store->checksum_histogram( 'post_meta', 2 );
182
183
		// temporary hack due to missing post_meta_checksum implementation in the test replicastore
184 View Code Duplication
		if ( 'Jetpack_Sync_Test_Replicastore' != get_class( $store ) ) {
185
			$this->assertEquals( $store->post_meta_checksum( 1, 2 ), $histogram['1-2'] );
186
			$this->assertEquals( $store->post_meta_checksum( 5, 10 ), $histogram['5-10'] );
187
		}
188
189
		// test comments checksum with ID range
190
		$histogram = $store->checksum_histogram( 'comments', 2 );
191
		$this->assertEquals( $store->comments_checksum( 0, 5 ), $histogram['3'] );
192
		$this->assertEquals( $store->comments_checksum( 6, 10 ), $histogram['6'] );
193
194
		// test commentmeta checksum with ID range
195
		$histogram = $store->checksum_histogram( 'comment_meta', 2 );
196
197
		// temporary hack due to missing comment_meta_checksum implementation in the test replicastore
198 View Code Duplication
		if ( 'Jetpack_Sync_Test_Replicastore' != get_class( $store ) ) {
199
			$this->assertEquals( $store->comment_meta_checksum( 1, 4 ), $histogram['1-4'] );
200
			$this->assertEquals( $store->comment_meta_checksum( 7, 10 ), $histogram['7-10'] );
201
		}
202
	}
203
204
	/**
205
	 * @dataProvider store_provider
206
	 */
207
	function test_does_not_checksum_spam_comments( $store ) {
208
		$comment        = self::$factory->comment( 3, 1 );
209
		$spam_comment = self::$factory->comment( 6, 1, array( 'comment_approved' => 'spam' ) );
210
		$trash_comment = self::$factory->comment( 9, 1, array( 'comment_approved' => 'trash' )  );
211
212
		$store->upsert_comment( $comment );
213
		$store->upsert_comment( $trash_comment );
214
215
		$checksum = $store->comments_checksum();
216
217
		// add a spam comment and assert that checksum didn't change
218
		$store->upsert_comment( $spam_comment );
219
220
		$this->assertEquals( $checksum, $store->comments_checksum() );
221
	}
222
223
	/**
224
	 * @dataProvider store_provider
225
	 */
226
	function test_strips_non_ascii_chars_for_checksum( $store ) {
227
		$utf8_post = self::$factory->post( 1, array( 'post_content' => 'Panamá' ) );
228
		$ascii_post = self::$factory->post( 1, array( 'post_content' => 'Panam' ) );
229
		$utf8_comment = self::$factory->comment( 1, 1, array( 'comment_content' => 'Panamá' ) );
230
		$ascii_comment = self::$factory->comment( 1, 1, array( 'comment_content' => 'Panam' ) );
231
232
		// generate checksums just for utf8 content
233
		$store->upsert_post( $utf8_post );
234
		$store->upsert_comment( $utf8_comment );
235
236
		$utf8_post_checksum = $store->posts_checksum();
237
		$utf8_comment_checksum = $store->comments_checksum();
238
239
		// generate checksums just for ascii content
240
		$store->upsert_post( $ascii_post );
241
		$store->upsert_comment( $ascii_comment );
242
243
		$this->assertEquals( $utf8_post_checksum, $store->posts_checksum() );
244
		$this->assertEquals( $utf8_comment_checksum, $store->comments_checksum() );
245
	}
246
247
	/**
248
	 * Histograms
249
	 **/
250
251
	/**
252
	 * @dataProvider store_provider
253
	 */
254
	function test_checksum_histogram( $store ) {
255
256
		$min_post_id           = 1000000;
257
		$max_post_id           = 1;
258
		$min_comment_id        = 1000000;
259
		$max_comment_id        = 1;
260
		$generated_post_ids    = array();
261
		$generated_comment_ids = array();
262
263
		for ( $i = 1; $i <= 20; $i += 1 ) {
264
			do {
265
				$post_id = rand( 1, 1000000 );
266
			} while ( in_array( $post_id, $generated_post_ids ) );
267
268
			$generated_post_ids[] = $post_id;
269
270
			$post = self::$factory->post( $post_id, array( 'post_content' => "Test post $i" ) );
271
			$store->upsert_post( $post );
272
			if ( $min_post_id > $post_id ) {
273
				$min_post_id = $post_id;
274
			}
275
276
			if ( $max_post_id < $post_id ) {
277
				$max_post_id = $post_id;
278
			}
279
280
			do {
281
				$comment_id = rand( 1, 1000000 );
282
			} while ( in_array( $post_id, $generated_comment_ids ) );
283
284
			$generated_comment_ids[] = $comment_id;
285
286
			$comment = self::$factory->comment( $comment_id, $post_id, array( 'comment_content' => "Test comment $i" ) );
287
			$store->upsert_comment( $comment );
288
289
			if ( $min_comment_id > $comment_id ) {
290
				$min_comment_id = $comment_id;
291
			}
292
293
			if ( $max_comment_id < $comment_id ) {
294
				$max_comment_id = $comment_id;
295
			}
296
297
		}
298
299
		foreach ( array( 'posts', 'comments' ) as $object_type ) {
300
			$histogram = $store->checksum_histogram( $object_type, 10, 0, 0 );
301
			$this->assertEquals( 10, count( $histogram ) );
302
303
			// histogram bucket should equal entire histogram of just the ID range for that bucket
304
			foreach ( $histogram as $range => $checksum ) {
305
				list( $min_id, $max_id ) = explode( '-', $range );
306
307
				$range_histogram = $store->checksum_histogram( $object_type, 1, (int) $min_id, (int) $max_id );
308
				$range_checksum  = array_pop( $range_histogram );
309
310
				$this->assertEquals( $checksum, $range_checksum );
311
			}
312
		}
313
314
		// histogram with one bucket should equal checksum of corresponding object type
315
		$histogram = $store->checksum_histogram( 'posts', 1, 0, 0 );
316
		$this->assertEquals( $store->posts_checksum(), $histogram["$min_post_id-$max_post_id"] );
317
318
		$histogram = $store->checksum_histogram( 'comments', 1, 0, 0 );
319
		$this->assertEquals( $store->comments_checksum(), $histogram["$min_comment_id-$max_comment_id"] );
320
	}
321
322
	/**
323
	 * @dataProvider store_provider
324
	 */
325
	function test_replica_checksum_posts_return_different_values_on_enej_case( $store ) {
326
		$store->reset();
327
		$post = self::$factory->post( 807 );
328
		$store->upsert_post( $post );
329
		$post = self::$factory->post( 811 );
330
		$store->upsert_post( $post );
331
		$post = self::$factory->post( 816 );
332
		$store->upsert_post( $post );
333
		$before_checksum = $store->posts_checksum();
334
		$post = self::$factory->post( 812 );
335
		$store->upsert_post( $post );
336
		$post = self::$factory->post( 813 );
337
		$store->upsert_post( $post );
338
		$post = self::$factory->post( 814 );
339
		$store->upsert_post( $post );
340
		$post = self::$factory->post( 815 );
341
		$store->upsert_post( $post );
342
		$after_checksum = $store->posts_checksum();
343
		$this->assertNotEquals( $before_checksum, $after_checksum );
344
	}
345
346
	/**
347
	 * @dataProvider store_provider
348
	 */
349
	function test_histogram_accepts_columns( $store ) {
350
		for ( $i = 1; $i <= 20; $i += 1 ) {
351
			$post = self::$factory->post( $i, array( 'post_content' => "Test post $i" ) );
352
			$store->upsert_post( $post );
353
354
			$comment = self::$factory->comment( $i, $i, array( 'comment_content' => "Test comment $i" ) );
355
			$store->upsert_comment( $comment );
356
		}
357
358
		$histogram = $store->checksum_histogram( 'posts', 20, 0, 0, array( 'post_content' ) );
359
360
		$post_checksum = $histogram['1'];
361
362
		$this->assertEquals( $post_checksum, (string) crc32( implode( '#', array( '' ,"Test post 1"  ) ) ) );
363
	}
364
365
	/**
366
	 * @dataProvider store_provider
367
	 */
368
	function test_histogram_detects_missing_columns( $store ) {
369
		global $wpdb;
370
		$suppressed = $wpdb->suppress_errors;
371
		$wpdb->suppress_errors = true;
372
373
374
		if ( $store instanceof Jetpack_Sync_Test_Replicastore ) {
375
			$this->markTestIncomplete( "The Test replicastore doesn't support detecting missing columns" );
376
		}
377
378
		// check what happens when we pass in an invalid column
379
		$histogram = $store->checksum_histogram( 'posts', 20, 0, 0, array( 'this_column_doesnt_exist' ) );
380
381
		if ( ! empty( $histogram ) ) {
382
			$this->assertTrue( is_wp_error( $histogram ) );
383
		} else {
384
			$this->assertTrue( is_array( $histogram ) );
385
		}
386
387
388
		$wpdb->suppress_errors = $suppressed;
389
	}
390
391
	/**
392
	 * Posts
393
	 */
394
395
	/**
396
	 * @dataProvider store_provider
397
	 */
398
	function test_replica_upsert_post( $store ) {
399
		$this->assertEquals( 0, $store->post_count() );
400
401
		$post = self::$factory->post( 5 );
402
403
		$store->upsert_post( $post );
404
405
		$retrieved_post = $store->get_post( $post->ID );
406
407
		// author is modified on save by the wpcom shadow replicastore
408
		unset( $post->post_author );
409
		unset( $retrieved_post->post_author );
410
411
		$this->assertEquals( $post, $retrieved_post );
412
413
		// assert the DB has one post
414
		$this->assertEquals( 1, $store->post_count() );
415
416
		// test that re-upserting doesn't add a new post, but modifies existing one
417
		$post->post_title = "A whole new title";
418
		$store->upsert_post( $post );
419
		$replica_post = $store->get_post( $post->ID );
420
421
		$this->assertEquals( "A whole new title", $replica_post->post_title );
422
	}
423
424
	/**
425
	 * @dataProvider store_provider
426
	 */
427
	function test_replica_get_posts( $store ) {
428
		$store->upsert_post( self::$factory->post( 1, array( 'post_status' => 'draft' ) ) );
429
		$store->upsert_post( self::$factory->post( 2, array( 'post_status' => 'publish' ) ) );
430
		$store->upsert_post( self::$factory->post( 3, array( 'post_status' => 'trash' ) ) );
431
		$store->upsert_post( self::$factory->post( 4, array( 'post_status' => 'trash' ) ) );
432
433
		$this->assertEquals( 1, $store->post_count( 'draft' ) );
434
		$this->assertEquals( 1, $store->post_count( 'publish' ) );
435
		$this->assertEquals( 2, $store->post_count( 'trash' ) );
436
437
		$trash_posts = $store->get_posts( 'trash' );
438
439
		$this->assertEquals( 2, count( $trash_posts ) );
440
441
		// now let's delete a post
442
		$store->delete_post( 3 );
443
444
		$this->assertEquals( null, $store->get_post( 3 ) );
445
		$this->assertEquals( 1, $store->post_count( 'trash' ) );
446
	}
447
448
	/**
449
	 * @dataProvider store_provider
450
	 */
451
	function test_replica_checksum_posts( $store ) {
452
		$before_checksum = $store->posts_checksum();
453
454
		$post = self::$factory->post( 5 );
455
456
		$store->upsert_post( $post );
457
458
		$this->assertNotEquals( $before_checksum, $store->posts_checksum() );
459
	}
460
461
	/**
462
	 * Comments
463
	 */
464
465
	/**
466
	 * @dataProvider store_provider
467
	 */
468
	function test_replica_upsert_comment( $store ) {
469
		$this->assertEquals( 0, $store->comment_count() );
470
471
		$comment = self::$factory->comment( 3, 2 );
472
473
		$store->upsert_comment( $comment );
474
475
		$this->assertEquals( 1, $store->comment_count() );
476
477
		$retrieved_comment = $store->get_comment( $comment->comment_ID );
478
479
		// insane hack because sometimes MySQL retrurns dates that are off by a second or so. WTF?
480
		unset( $comment->comment_date );
481
		unset( $comment->comment_date_gmt );
482
		unset( $retrieved_comment->comment_date );
483
		unset( $retrieved_comment->comment_date_gmt );
484
485
		if ( $store instanceof Replicastore ) {
486
			$this->markTestIncomplete( "The WP replicastore doesn't support setting comments post_fields" );
487
		}
488
489
		$this->assertEquals( $comment, $retrieved_comment );
490
	}
491
492
	/**
493
	 * @dataProvider store_provider
494
	 */
495
	function test_replica_checksum_comments( $store ) {
496
		$before_checksum = $store->comments_checksum();
497
498
		$comment = self::$factory->comment( 3, 2 );
499
500
		$store->upsert_comment( $comment );
501
502
		$this->assertNotEquals( $before_checksum, $store->comments_checksum() );
503
	}
504
505
	/**
506
	 * @dataProvider store_provider
507
	 */
508
	function test_replica_get_comments( $store ) {
509
		$post_id = 1;
510
		self::$factory->post( $post_id, array( 'post_status' => 'publish' ) );
511
		$store->upsert_comment( self::$factory->comment( 1, $post_id, array( 'comment_approved' => '0' ) ) );
512
		$store->upsert_comment( self::$factory->comment( 2, $post_id, array( 'comment_approved' => '1' ) ) );
513
		$store->upsert_comment( self::$factory->comment( 3, $post_id, array( 'comment_approved' => 'spam' ) ) );
514
		$store->upsert_comment( self::$factory->comment( 4, $post_id, array( 'comment_approved' => 'spam' ) ) );
515
		$store->upsert_comment( self::$factory->comment( 5, $post_id, array( 'comment_approved' => 'trash' ) ) );
516
517
		$this->assertEquals( 1, $store->comment_count( 'hold' ) );
518
		$this->assertEquals( 1, $store->comment_count( 'approve' ) );
519
		$this->assertEquals( 1, $store->comment_count( 'trash' ) );
520
		$this->assertEquals( 2, $store->comment_count( 'spam' ) );
521
	}
522
523
	/**
524
	 * Options
525
	 */
526
527
	/**
528
	 * @dataProvider store_provider
529
	 */
530
	function test_replica_update_option( $store ) {
531
		$option_name  = 'blogdescription';
532
		$option_value = (string) rand();
533
		$store->update_option( $option_name, $option_value );
534
		$replica_option_value = $store->get_option( $option_name );
535
536
		$this->assertEquals( $option_value, $replica_option_value );
537
	}
538
539
	/**
540
	 * @dataProvider store_provider
541
	 */
542
	function test_replica_delete_option( $store ) {
543
		$option_name  = 'test_replicastore_' . rand();
544
		$option_value = (string) rand();
545
		$store->update_option( $option_name, $option_value );
546
		$store->delete_option( $option_name );
547
		$replica_option_value = $store->get_option( $option_name );
548
549
		$this->assertFalse( $replica_option_value );
550
	}
551
552
	/**
553
	 * @dataProvider store_provider
554
	 */
555
	function test_replica_set_theme_support( $store ) {
556
557
		if ( $store instanceof Replicastore ) {
558
			$this->markTestIncomplete( "The WP replicastore doesn't support setting theme options directly" );
559
		}
560
561
		$theme_features = array(
562
			'automatic-feed-links'      => true,
563
			'title-tag'                 => true,
564
			'post-thumbnails'           => true,
565
			'menus'                     => true,
566
			'html5'                     =>
567
				array(
568
					0 =>
569
						array(
570
							0 => 'search-form',
571
							1 => 'comment-form',
572
							2 => 'comment-list',
573
							3 => 'gallery',
574
							4 => 'caption',
575
						),
576
				),
577
			'post-formats'              =>
578
				array(
579
					0 =>
580
						array(
581
							0 => 'aside',
582
							1 => 'image',
583
							2 => 'video',
584
							3 => 'quote',
585
							4 => 'link',
586
							5 => 'gallery',
587
							6 => 'status',
588
							7 => 'audio',
589
							8 => 'chat',
590
						),
591
				),
592
			'custom-background'         =>
593
				array(
594
					0 =>
595
						array(
596
							'default-image'          => '',
597
							'default-repeat'         => 'repeat',
598
							'default-position-x'     => 'left',
599
							'default-attachment'     => 'fixed',
600
							'default-color'          => 'f1f1f1',
601
							'wp-head-callback'       => '_custom_background_cb',
602
							'admin-head-callback'    => '',
603
							'admin-preview-callback' => '',
604
						),
605
				),
606
			'editor-style'              => true,
607
			'custom-header'             =>
608
				array(
609
					0 =>
610
						array(
611
							'default-image'          => '',
612
							'random-default'         => false,
613
							'width'                  => 954,
614
							'height'                 => 1300,
615
							'flex-height'            => false,
616
							'flex-width'             => false,
617
							'default-text-color'     => '333333',
618
							'header-text'            => true,
619
							'uploads'                => true,
620
							'wp-head-callback'       => 'twentyfifteen_header_style',
621
							'admin-head-callback'    => '',
622
							'admin-preview-callback' => '',
623
						),
624
				),
625
			'jetpack-responsive-videos' => true,
626
			'site-logo'                 =>
627
				array(
628
					0 =>
629
						array(
630
							'size' => 'twentyfifteen-logo',
631
						),
632
				),
633
			'infinite-scroll'           =>
634
				array(
635
					0 =>
636
						array(
637
							'container' => 'main',
638
							'footer'    => 'page',
639
						),
640
				),
641
			'widgets'                   => true,
642
			'custom_colors_extra_css'   =>
643
				array(
644
					0 => 'twentyfifteen_extra_css',
645
				),
646
		);
647
648
		$store->set_callable( 'theme_support', $theme_features );
649
650
		// the "current_theme_supports" API is only supposed to return "true" if there's a setting
651
		foreach ( $theme_features as $theme_feature => $theme_feature_value ) {
652
			$replica_theme_support_value = $store->current_theme_supports( $theme_feature );
653
			$this->assertEquals( $theme_feature_value || false, $replica_theme_support_value );
654
		}
655
	}
656
657
	/**
658
	 * Meta
659
	 */
660
661
	/**
662
	 * @dataProvider store_provider
663
	 */
664
	function test_replica_reset_preserves_internal_keys( $store ) {
665
		if ( $store instanceof Jetpack_Sync_Test_Replicastore ) {
666
			$this->markTestIncomplete( "Test replicastore resets fully every time - this is only necessary on WPCOM" );
667
		}
668
669
		$store->upsert_post( self::$factory->post( 1 ) );
670
671
		$store->upsert_metadata( 'post', 1, 'foo', 'bar', 3 );
672
		$store->upsert_metadata( 'post', 1, '_fee', 'baz', 4 );
673
674
		$store->reset();
675
676
		// sadly this is still necessary since we're bulk deleting post meta
677
		// but not bulk-cache-invalidating it
678
		wp_cache_delete( 1, 'post_meta' );
679
680
		$this->assertEquals( null, $store->get_metadata( 'post', 1, 'foo', true ) );
681
		$this->assertEquals( 'baz', $store->get_metadata( 'post', 1, '_fee', true ) );
682
	}
683
684
	/**
685
	 * @dataProvider store_provider
686
	 */
687
	function test_replica_update_meta( $store ) {
688
		$store->upsert_post( self::$factory->post( 1 ) );
689
690
		$store->upsert_metadata( 'post', 1, 'foo', 'bar', 3 );
691
692
		$this->assertEquals( array( 'bar' ), $store->get_metadata( 'post', 1, 'foo' ) );
693
694
		$store->delete_metadata( 'post', 1, array( 3 ) );
695
696
		$this->assertEquals( array(), $store->get_metadata( 'post', 1, 'foo' ) );
697
	}
698
699
	/**
700
	 * @dataProvider store_provider
701
	 */
702
	function test_replica_update_meta_array( $store ) {
703
		$meta_array = array( 'trees' => 'green', 'ocean' => 'blue' );
704
705
		$store->upsert_post( self::$factory->post( 1 ) );
706
		$store->upsert_metadata( 'post', 1, 'colors', $meta_array, 3 );
707
708
		$color_meta = $store->get_metadata( 'post', 1, 'colors' );
709
710
		$this->assertTrue( $this->arrays_are_similar( $meta_array, $color_meta[0] ) );
711
	}
712
713
	/**
714
	 * Determine if two associative arrays are similar
715
	 *
716
	 * Both arrays must have the same indexes with identical values
717
	 * without respect to key ordering
718
	 *
719
	 * @param array $a
720
	 * @param array $b
721
	 *
722
	 * @return bool
723
	 */
724
	function arrays_are_similar( $a, $b ) {
725
		// if the indexes don't match, return immediately
726
		if ( count( array_diff_assoc( $a, $b ) ) ) {
727
			return false;
728
		}
729
		// we know that the indexes, but maybe not values, match.
730
		// compare the values between the two arrays
731
		foreach ( $a as $k => $v ) {
732
			if ( $v !== $b[ $k ] ) {
733
				return false;
734
			}
735
		}
736
737
		// we have identical indexes, and no unequal values
738
		return true;
739
	}
740
741
	/**
742
	 * Constants
743
	 */
744
745
	/**
746
	 * @dataProvider store_provider
747
	 */
748
	function test_replica_set_constant( $store ) {
749
		$this->assertNull( $store->get_constant( 'FOO' ) );
750
751
		$store->set_constant( 'FOO', array( 'foo' => 'bar' ) );
752
753
		$this->assertEquals( array( 'foo' => 'bar' ), $store->get_constant( 'FOO' ) );
754
	}
755
756
	/**
757
	 * Updates
758
	 */
759
760
	/**
761
	 * @dataProvider store_provider
762
	 */
763
	function test_replica_set_updates( $store ) {
764
		$this->assertNull( $store->get_updates( 'core' ) );
765
766
		$store->set_updates( 'core', 1 );
767
768
		$this->assertEquals( 1, $store->get_updates( 'core' ) );
769
	}
770
771
	/**
772
	 * Callables
773
	 */
774
775
	/**
776
	 * @dataProvider store_provider
777
	 */
778
	function test_replica_set_callables( $store ) {
779
		if ( $store instanceof Replicastore ) {
780
			$this->markTestIncomplete( "The WP replicastore doesn't support setting callables directly" );
781
		}
782
783
		$this->assertNull( $store->get_callable( 'is_main_network' ) );
784
785
		$store->set_callable( 'is_main_network', '1' );
786
787
		$this->assertEquals( '1', $store->get_callable( 'is_main_network' ) );
788
	}
789
790
	/**
791
	 * Site (aka Network) options
792
	 */
793
794
	/**
795
	 * @dataProvider store_provider
796
	 */
797
	function test_replica_set_site_options( $store ) {
798
		$this->assertFalse( $store->get_site_option( 'foo' ), 'Site option Not empty.' );
799
800
		$store->update_site_option( 'foo', 'bar' );
801
802
		$this->assertEquals( 'bar', $store->get_site_option( 'foo' ), 'Site option Not bar.' );
803
	}
804
805
	/**
806
	 * @dataProvider store_provider
807
	 */
808
	function test_replica_delete_site_option( $store ) {
809
		$store->update_site_option( 'to_delete', 'me' );
810
811
		$this->assertEquals( 'me', $store->get_site_option( 'to_delete' ), 'Site option is NOT set to me.' );
812
813
		$store->delete_site_option( 'to_delete' );
814
815
		$this->assertEquals( false, $store->get_site_option( 'to_delete' ), 'Site option was NOT deleted.' );
816
	}
817
818
	/**
819
	 * Users
820
	 */
821
822
	/**
823
	 * @dataProvider store_provider
824
	 */
825
	function test_replica_update_users( $store ) {
826
		if ( $store instanceof Replicastore ) {
827
			$this->markTestIncomplete( "The WP replicastore doesn't support setting users" );
828
		}
829
830
		$this->assertNull( $store->get_user( 12 ) );
831
832
		$user = self::$factory->user( 12, 'example_user' );
833
834
		$store->upsert_user( $user );
835
836
		$this->assertNotNull( $store->get_user( 12 ) );
837
838
		// delete stuff that shouldn't be included because we don't sync that data
839
		unset( $user->data->user_activation_key );
840
841
		$stored_user = $store->get_user( 12 );
842
843
		if ( $store instanceof Jetpack_Sync_WPCOM_Shadow_Replicastore ) {
0 ignored issues
show
Bug introduced by
The class Jetpack_Sync_WPCOM_Shadow_Replicastore does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
844
			$this->assertEquals( $user->ID, $stored_user->external_user_id );
845
			$this->assertFalse( isset( $user->data->user_activation_key ) );
846
		} else {
847
			$this->assertEquals( $user->ID, $stored_user->ID );
848
		}
849
850
		$this->assertEquals( $user->data->user_login, $stored_user->data->user_login );
851
		$this->assertEquals( $user->data->user_nicename, $stored_user->data->user_nicename );
852
		$this->assertEquals( $user->data->user_email, $stored_user->data->user_email );
853
		$this->assertEquals( $user->data->user_url, $stored_user->data->user_url );
854
		$this->assertEquals( $user->data->user_registered, $stored_user->data->user_registered );
855
		$this->assertEquals( $user->data->user_status, $stored_user->data->user_status );
856
		$this->assertEquals( $user->data->display_name, $stored_user->data->display_name );
857
858
		$store->delete_user( 12 );
859
860
		$this->assertNull( $store->get_user( 12 ) );
861
	}
862
863
	/**
864
	 * @dataProvider store_provider
865
	 */
866
	function test_replica_get_allowed_mime_types( $store ) {
867
		if ( $store instanceof Replicastore ) {
868
			$this->markTestIncomplete( "The WP replicastore doesn't support setting users" );
869
		}
870
871
		$this->assertNull( $store->get_user( 12 ) );
872
873
		$user                    = self::$factory->user( 12, 'example_user' );
874
		$user_allowed_mime_types = $user->data->allowed_mime_types;
875
		$store->upsert_user( $user );
876
		$this->assertEquals( $user_allowed_mime_types, $store->get_allowed_mime_types( 12 ) );
877
	}
878
879
	/**
880
	 * Terms
881
	 */
882
883
	/**
884
	 * @dataProvider store_provider
885
	 */
886
	public function test_replica_update_terms( $store ) {
887
		$taxonomy = 'test_shadow_taxonomy_term';
888
889
		$this->ensure_synced_taxonomy( $store, $taxonomy );
890
891
		$term_object = self::$factory->term( 22,
892
			array(
893
				'name'             => 'Female',
894
				'slug'             => 'female',
895
				'term_taxonomy_id' => 22,
896
				'taxonomy'         => $taxonomy,
897
			)
898
		);
899
900
		$this->assertEmpty( $store->get_term( $term_object->taxonomy, $term_object->term_id ) );
901
902
		$store->update_term( $term_object );
903
904
		$term = $store->get_term( $term_object->taxonomy, $term_object->term_id );
905
906
		$this->assertEquals( (array) $term_object, (array) $term );
907
	}
908
909
	/**
910
	 * @dataProvider store_provider
911
	 */
912
	function test_replica_delete_terms( $store ) {
913
		$taxonomy = 'test_shadow_taxonomy_term';
914
915
		$this->ensure_synced_taxonomy( $store, $taxonomy );
916
917
		$term_object = self::$factory->term( 22,
918
			array(
919
				'name'             => 'Female',
920
				'slug'             => 'female',
921
				'term_taxonomy_id' => 22,
922
				'taxonomy'         => $taxonomy,
923
			)
924
		);
925
926
		$store->update_term( $term_object );
927
928
		$store->delete_term( $term_object->term_id, $taxonomy );
929
930
		$this->assertEmpty( $store->get_term( $term_object->taxonomy, $term_object->term_id ) );
931
	}
932
933
	/**
934
	 * @dataProvider store_provider
935
	 */
936
	function test_replica_update_post_terms( $store ) {
937
		$taxonomy = 'test_shadow_taxonomy_term';
938
		$this->ensure_synced_taxonomy( $store, $taxonomy );
939
940
		$term_object = self::$factory->term( 22,
941
			array(
942
				'name'             => 'Female',
943
				'slug'             => 'female',
944
				'term_taxonomy_id' => 22,
945
				'taxonomy'         => $taxonomy,
946
			)
947
		);
948
949
		$store->update_term( $term_object );
950
951
		$post = self::$factory->post( 5 );
952
		$store->upsert_post( $post );
953
		$replica_post = $store->get_post( 5 );
954
955
		$store->update_object_terms( $replica_post->ID, $taxonomy, array( 22 ), true );
956
957
		$terms = $store->get_the_terms( $replica_post->ID, $taxonomy );
958
959
		$this->assertEquals( 1, $terms[0]->count );
960
		$this->assertEquals( 22, $terms[0]->term_id );
961
		$this->assertEquals( 22, $terms[0]->term_taxonomy_id );
962
		$this->assertEquals( 'female', $terms[0]->slug );
963
		$this->assertEquals( 'Female', $terms[0]->name );
964
	}
965
966
	/**
967
	 * @dataProvider store_provider
968
	 */
969
	function test_replica_delete_post_terms( $store ) {
970
		$this->markTestIncomplete( 'contains SQL' );
971
		global $wpdb;
972
		$taxonomy = 'test_shadow_taxonomy_term';
973
974
		$this->ensure_synced_taxonomy( $store, $taxonomy );
975
976
		$term_object = (object) array(
977
			'term_id'          => 22,
978
			'name'             => 'Female',
979
			'slug'             => 'female',
980
			'term_group'       => 0,
981
			'term_taxonomy_id' => 22,
982
			'taxonomy'         => $taxonomy,
983
			'description'      => '',
984
			'parent'           => 0,
985
			'count'            => 0,
986
			'filter'           => 'raw',
987
		);
988
989
		$store->update_term( $term_object );
990
991
		$post = self::$factory->post( 5 );
992
		$store->upsert_post( $post );
993
		$replica_post = $store->get_post( 5 );
994
995
		$store->update_object_terms( $replica_post->ID, $taxonomy, array( 22 ), true );
996
997
		$terms = get_the_terms( $replica_post->ID, $taxonomy );
998
		$this->assertEquals( 1, $terms[0]->count );
999
1000
		$store->delete_object_terms( $replica_post->ID, array( 22 ) );
1001
1002
		$this->assertEquals( null, $wpdb->get_row( "SELECT * FROM $wpdb->term_relationships WHERE object_id = 5 " ) );
1003
1004
		$terms = get_the_terms( $replica_post->ID, $taxonomy );
1005
		$this->assertEquals( 0, $terms[0]->count );
1006
	}
1007
1008
	public function store_provider( $name ) {
1009 View Code Duplication
		if ( ! self::$all_replicastores ) {
1010
			// detect classes that implement iJetpack_Sync_Replicastore
1011
			self::$all_replicastores = array();
1012
1013
			foreach ( get_declared_classes() as $className ) {
1014
				if ( in_array( 'Automattic\\Jetpack\\Sync\\Replicastore_Interface', class_implements( $className ) ) ) {
1015
					self::$all_replicastores[] = $className;
1016
				}
1017
			}
1018
		}
1019
1020
		$return = array();
1021
1022
		foreach ( self::$all_replicastores as $replicastore_class ) {
1023
			if ( method_exists( $replicastore_class, 'getInstance' ) ) {
1024
				$instance = call_user_func( array( $replicastore_class, 'getInstance' ) );
1025
			} else {
1026
				$instance = new $replicastore_class();
1027
			}
1028
1029
			$return[] = array( $instance );
1030
		}
1031
1032
		return $return;
1033
	}
1034
1035
	private function ensure_synced_taxonomy( $store, $slug, $type = 'post' ) {
1036
		register_taxonomy(
1037
			$slug,
1038
			$type,
1039
			array(
1040
				'label'        => __( $slug ),
1041
				'rewrite'      => array( 'slug' => $slug ),
1042
				'hierarchical' => true,
1043
			)
1044
		);
1045
1046
		// fetch the taxonomy, sync it then delete it
1047
		global $wp_taxonomies;
1048
1049
		$store->set_callable( 'taxonomies', array( $slug => $wp_taxonomies[ $slug ] ) );
1050
1051
		// unregister_taxonomy( $slug );
1052
	}
1053
}
1054