PluginProbe ʕ •ᴥ•ʔ
Reviews Feed – Add Testimonials and Customer Reviews From Google Reviews, Yelp, TripAdvisor, and More / 2.10.0
Reviews Feed – Add Testimonials and Customer Reviews From Google Reviews, Yelp, TripAdvisor, and More v2.10.0
2.11.0 2.10.0 2.9.0 2.8.0 2.7.0 2.6.7 2.6.8 2.6.5 2.6.4 2.6.3 2.6.2 2.6.0 2.5.5 2.5.4 2.5.3 2.5.2 trunk 1.0 1.0.1 1.0.2 1.0.3 1.1 1.1.1 1.1.2 1.2.0 2.0 2.1.0 2.1.1 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.5.0 2.5.1
reviews-feed / tests / Unit / BulkRearmOnGrowthTest.php
reviews-feed / tests / Unit Last commit date
Doubles 3 weeks ago Providers 3 weeks ago BulkRearmOnGrowthTest.php 3 weeks ago BulkReviewsUpdateStuckStateTest.php 3 weeks ago ClearCacheRelayResetTest.php 3 weeks ago DeleteSourceRelayFailureTest.php 3 weeks ago ErrorHandlerFalsyOptionTest.php 3 weeks ago FeedCacheUpdateServiceTest.php 3 weeks ago FeedMalformedPayloadTest.php 3 weeks ago ForceKeylessRefetchTest.php 3 weeks ago LicenseDeactivateStaleStateTest.php 3 weeks ago MediaFinderMemoTest.php 3 weeks ago MultiSourceAggregationTest.php 3 weeks ago ReconcileMigratedLicenseRoutineTest.php 3 weeks ago ReconcileRemovalTest.php 3 weeks ago RegisterWebsiteRoutineTest.php 3 weeks ago RemoteRequestMemoTest.php 3 weeks ago ReviewAlertHeaderTotalsTest.php 3 weeks ago ReviewAlertPageTargetingTest.php 3 weeks ago ReviewAlertStarFillTest.php 3 weeks ago ShortcodeNeutralizationTest.php 3 weeks ago SiteMigrationRecoveryTest.php 3 weeks ago Smash1583HeaderParityTest.php 3 weeks ago Smash1631MultiLanguageBulkTest.php 3 weeks ago Smash1631UpdateSingleLangScopeTest.php 3 weeks ago Smash1706TripAdvisorPlaceIdTest.php 3 weeks ago Smash1756SchemaServiceTest.php 3 weeks ago Smash1785AvatarLocalUrlGuardTest.php 3 weeks ago Smash1785AvatarReHealTest.php 3 weeks ago Smash1795ReviewTextXssTest.php 3 weeks ago Smash782BookingHeaderRatingTest.php 3 weeks ago Smash782CountryFlagEmojiTest.php 3 weeks ago Smash782ExternalRefreshCronTest.php 3 weeks ago Smash782ExtrasTemplateTest.php 3 weeks ago Smash782ReviewAlertProviderDataTest.php 3 weeks ago SourceIdLookupTest.php 3 weeks ago WpmlGetCurrentLanguageTest.php 3 weeks ago WpmlLanguageMappingTest.php 3 weeks ago
BulkRearmOnGrowthTest.php
141 lines
1 <?php
2
3 namespace SmashBalloon\Reviews\Tests\Unit;
4
5 use PHPUnit\Framework\TestCase;
6 use SmashBalloon\Reviews\Pro\Services\BulkUpdate\Bulk_Reviews_Update;
7
8 /**
9 * SMASH-1634 — change-driven re-arm of the one-shot paginated backfill.
10 *
11 * The bug: after a source's bulk history completes (`is_done`), it never re-runs,
12 * so review batches larger than the hourly incremental cap (Google/Yelp keyed
13 * API returns only the 5 newest bodies) never load without a manual "reset bulk
14 * history". `maybe_rearm_source()` re-opens ONE source's backfill when its
15 * upstream review count grows.
16 *
17 * These pin the exact contract, including the cost guards (seed-on-first-sight,
18 * key/provider gating) so the fix can't silently start a mass re-backfill.
19 *
20 * @group bulk-history
21 * @group smash-1634
22 */
23 class BulkRearmOnGrowthTest extends TestCase
24 {
25 protected function setUp(): void
26 {
27 parent::setUp();
28 global $wp_options_mock;
29 $wp_options_mock = [];
30 }
31
32 /** Keyed google/yelp needs an API key for the bulk (RapidAPI) path. */
33 private function withApiKey(string $provider = 'google'): void
34 {
35 global $wp_options_mock;
36 $wp_options_mock['sbr_apikeys'] = [$provider => 'TEST_KEY'];
37 }
38
39 private function seedBulk(array $state): void
40 {
41 global $wp_options_mock;
42 $wp_options_mock['sbr_bulk_sources'] = $state;
43 }
44
45 private function bulkState(string $account_id): array
46 {
47 global $wp_options_mock;
48 return $wp_options_mock['sbr_bulk_sources'][$account_id] ?? [];
49 }
50
51 /**
52 * First time we observe a completed source, we only SEED the baseline —
53 * we must NOT re-arm. This is the cost guard that stops deploying the fix
54 * from re-backfilling every existing source at once.
55 */
56 public function test_first_observation_seeds_baseline_without_rearm(): void
57 {
58 $this->withApiKey('google');
59 $id = 'ChIJ_SEED';
60 $this->seedBulk([$id => ['account_id' => $id, 'provider' => 'google', 'is_done' => true, 'page' => 3]]);
61
62 $rearmed = Bulk_Reviews_Update::maybe_rearm_source('google', $id, 233);
63
64 $this->assertFalse($rearmed, 'First sight of a done source must not re-arm.');
65 $state = $this->bulkState($id);
66 $this->assertTrue($state['is_done'], 'is_done must stay true on the seed pass.');
67 $this->assertSame(233, $state['last_total'], 'Baseline last_total must be seeded.');
68 }
69
70 /** No growth since the last backfill → no re-arm. */
71 public function test_no_growth_does_not_rearm(): void
72 {
73 $this->withApiKey('google');
74 $id = 'ChIJ_FLAT';
75 $this->seedBulk([$id => ['account_id' => $id, 'provider' => 'google', 'is_done' => true, 'page' => 3, 'last_total' => 233]]);
76
77 $this->assertFalse(Bulk_Reviews_Update::maybe_rearm_source('google', $id, 233));
78 $this->assertTrue($this->bulkState($id)['is_done'], 'Equal count must leave is_done untouched.');
79 }
80
81 /** THE FIX: upstream count grew → re-open the backfill for that source. */
82 public function test_growth_rearms_source(): void
83 {
84 $this->withApiKey('google');
85 $id = 'ChIJ_GROW';
86 $this->seedBulk([$id => ['account_id' => $id, 'provider' => 'google', 'is_done' => true, 'page' => 3, 'last_total' => 233]]);
87
88 $rearmed = Bulk_Reviews_Update::maybe_rearm_source('google', $id, 246);
89
90 $this->assertTrue($rearmed, 'Count growth must re-arm the source.');
91 $state = $this->bulkState($id);
92 $this->assertFalse($state['is_done'], 'Re-arm must clear is_done so the backfill re-runs.');
93 $this->assertSame(1, $state['page'], 'Re-arm must reset pagination to page 1 (matches the proven 1-indexed fresh init).');
94 $this->assertSame(246, $state['last_total'], 'Re-arm must record the new baseline (prevents re-loop).');
95 }
96
97 /** BC: a source still mid-backfill (is_done false) is left to the normal flow. */
98 public function test_not_done_source_is_untouched(): void
99 {
100 $this->withApiKey('google');
101 $id = 'ChIJ_RUNNING';
102 $this->seedBulk([$id => ['account_id' => $id, 'provider' => 'google', 'is_done' => false, 'page' => 1]]);
103
104 $this->assertFalse(Bulk_Reviews_Update::maybe_rearm_source('google', $id, 999));
105 $state = $this->bulkState($id);
106 $this->assertFalse($state['is_done']);
107 $this->assertArrayNotHasKey('last_total', $state, 'Running source must not be mutated.');
108 }
109
110 /** Cost guard: keyless (no API key) is not handled by this bulk service → never re-arm. */
111 public function test_no_api_key_never_rearms(): void
112 {
113 // no withApiKey()
114 $id = 'ChIJ_KEYLESS';
115 $this->seedBulk([$id => ['account_id' => $id, 'provider' => 'google', 'is_done' => true, 'page' => 3, 'last_total' => 100]]);
116
117 $this->assertFalse(Bulk_Reviews_Update::maybe_rearm_source('google', $id, 500));
118 $this->assertTrue($this->bulkState($id)['is_done'], 'Keyless source must be untouched.');
119 }
120
121 /** Guard: providers this bulk service doesn't own are ignored. */
122 public function test_non_google_yelp_provider_ignored(): void
123 {
124 $this->withApiKey('google');
125 $id = 'qa_booking';
126 $this->seedBulk([$id => ['account_id' => $id, 'provider' => 'booking', 'is_done' => true, 'page' => 3, 'last_total' => 10]]);
127
128 $this->assertFalse(Bulk_Reviews_Update::maybe_rearm_source('booking', $id, 50));
129 }
130
131 /** Guard: a zero/unknown current count is a no-op (don't act on missing data). */
132 public function test_zero_current_total_is_noop(): void
133 {
134 $this->withApiKey('google');
135 $id = 'ChIJ_ZERO';
136 $this->seedBulk([$id => ['account_id' => $id, 'provider' => 'google', 'is_done' => true, 'page' => 3, 'last_total' => 5]]);
137
138 $this->assertFalse(Bulk_Reviews_Update::maybe_rearm_source('google', $id, 0));
139 }
140 }
141