|null $row */ public function __construct(private ?array $row) { } /** @return array|null */ public function fetch_assoc(): ?array { return $this->row; } } final class InvoicingPeriodCanaryDbStub { /** @var string[] */ public array $queries = []; public ?string $value = '[7,43]'; public ?string $legacyValue = null; public function escape_string(string $value): string { return addslashes($value); } public function query(string $sql): InvoicingPeriodCanaryResultStub|bool { $this->queries[] = $sql; if (str_contains($sql, 'GET_LOCK')) { return new InvoicingPeriodCanaryResultStub(['acquired' => 1]); } if (str_starts_with(ltrim($sql), 'SELECT value')) { $selectedValue = str_contains($sql, 'object_tree_v2_allowlisted_user_ids') ? $this->legacyValue : $this->value; return new InvoicingPeriodCanaryResultStub( $selectedValue === null ? null : ['value' => $selectedValue] ); } if (preg_match("/SET value = '([^']+)'/", $sql, $matches) === 1) { $this->value = stripslashes($matches[1]); } if (preg_match("/VALUES \('InvoicingPeriod', 'object_tree_v2_superuser_allowlist', '([^']+)'/", $sql, $matches) === 1) { $this->value = stripslashes($matches[1]); } return true; } } /** @return int[] */ function setInvoicePeriodCanaryUserForTest(int $userId, bool $enabled): array { $method = new ReflectionMethod(InvoicingPeriodRoute::class, 'setInvoicePeriodObjectTreeV2CanaryUser'); /** @var int[] $result */ $result = $method->invoke(null, $userId, $enabled); return $result; } it('serializes self-canary updates and preserves other allowlisted users', function (): void { $db = new InvoicingPeriodCanaryDbStub(); $previousDb = $GLOBALS['db'] ?? null; $hadDb = array_key_exists('db', $GLOBALS); $GLOBALS['db'] = $db; try { expect(setInvoicePeriodCanaryUserForTest(99, true))->toBe([7, 43, 99]); expect(setInvoicePeriodCanaryUserForTest(43, false))->toBe([7, 99]); } finally { if ($hadDb) { $GLOBALS['db'] = $previousDb; } else { unset($GLOBALS['db']); } } $queries = implode("\n", $db->queries); expect($queries)->toContain("GET_LOCK('invoice_period_object_tree_rollout', 5)") ->and($queries)->toContain("RELEASE_LOCK('invoice_period_object_tree_rollout')") ->and($db->value)->toBe('[7,99]'); }); it('migrates and preserves the legacy allowlist when the canonical row is absent', function (): void { $db = new InvoicingPeriodCanaryDbStub(); $db->value = null; $db->legacyValue = '[7,43]'; $previousDb = $GLOBALS['db'] ?? null; $hadDb = array_key_exists('db', $GLOBALS); $GLOBALS['db'] = $db; try { expect(setInvoicePeriodCanaryUserForTest(99, true))->toBe([7, 43, 99]); } finally { if ($hadDb) { $GLOBALS['db'] = $previousDb; } else { unset($GLOBALS['db']); } } expect($db->value)->toBe('[7,43,99]'); }); it('exposes only a self-canary endpoint guarded by the superuser permission', function (): void { $route = (string)file_get_contents(app_path('routes/InvoicingPeriodRoute.php')); expect($route)->toContain("'/superuser/invoicing/period/object-tree/canary'") ->and($route)->toContain("requirePermission('superuser')") ->and($route)->toContain("'configured_enabled' => \$enabled") ->and($route)->toContain("'effective_enabled' => \$effectiveEnabled") ->and($route)->toContain('OBJECT_TREE_V2_CANARY_ENABLE_FAILED') ->and($route)->toContain('OBJECT_TREE_V2_CANARY_ENABLED') ->and($route)->toContain('OBJECT_TREE_V2_CANARY_DISABLED'); });