refactor: ReleaseGate::invalidate() als einzige Stelle zum Zurücksetzen des Freigabe-Zustands; CompatibilityMatrix::locked() und ReleaseGate::lockOf() ersetzen die drei Kopien der Sperrprüfung
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
7f9a087b8b
commit
63389f35a8
@@ -160,7 +160,7 @@ final class DiviTab implements AdminTab
|
|||||||
}
|
}
|
||||||
|
|
||||||
($this->releases ?? new ReleaseStore())->add($version, Plugin::VERSION, get_current_user_id(), $report->id);
|
($this->releases ?? new ReleaseStore())->add($version, Plugin::VERSION, get_current_user_id(), $report->id);
|
||||||
ReleaseGate::forget();
|
ReleaseGate::invalidate();
|
||||||
$this->log?->record(
|
$this->log?->record(
|
||||||
'lit/divi-release',
|
'lit/divi-release',
|
||||||
'divi',
|
'divi',
|
||||||
@@ -183,7 +183,7 @@ final class DiviTab implements AdminTab
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReleaseGate::forget();
|
ReleaseGate::invalidate();
|
||||||
$this->log?->record(
|
$this->log?->record(
|
||||||
'lit/divi-release',
|
'lit/divi-release',
|
||||||
'divi',
|
'divi',
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ use LIT\MCP\Integrations\Divi\Release\DiviEnvironment;
|
|||||||
use LIT\MCP\Integrations\Divi\Release\DiviReference;
|
use LIT\MCP\Integrations\Divi\Release\DiviReference;
|
||||||
use LIT\MCP\Integrations\Divi\Release\LineDiff;
|
use LIT\MCP\Integrations\Divi\Release\LineDiff;
|
||||||
use LIT\MCP\Integrations\Divi\Release\ReleaseGate;
|
use LIT\MCP\Integrations\Divi\Release\ReleaseGate;
|
||||||
use LIT\MCP\Integrations\Divi\Release\ReleaseResolver;
|
|
||||||
use LIT\MCP\Integrations\Divi\Release\SourceFingerprint;
|
use LIT\MCP\Integrations\Divi\Release\SourceFingerprint;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
|
|
||||||
@@ -173,8 +172,7 @@ final class DiviCheckCommand
|
|||||||
return ($this->matrix)();
|
return ($this->matrix)();
|
||||||
}
|
}
|
||||||
|
|
||||||
delete_transient(ReleaseResolver::CACHE);
|
ReleaseGate::invalidate(mirrors: true);
|
||||||
ReleaseGate::forget();
|
|
||||||
|
|
||||||
return ReleaseGate::status()->matrix;
|
return ReleaseGate::status()->matrix;
|
||||||
}
|
}
|
||||||
@@ -279,8 +277,7 @@ final class DiviCheckCommand
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
delete_transient(ReleaseResolver::CACHE);
|
ReleaseGate::invalidate(mirrors: true);
|
||||||
ReleaseGate::forget();
|
|
||||||
($this->out)(sprintf(
|
($this->out)(sprintf(
|
||||||
'Referenz aktualisiert (%d Fingerabdrücke, %d Signaturen). Smoke-Skripte laufen lassen, dann committen.',
|
'Referenz aktualisiert (%d Fingerabdrücke, %d Signaturen). Smoke-Skripte laufen lassen, dann committen.',
|
||||||
count($prints),
|
count($prints),
|
||||||
|
|||||||
@@ -55,8 +55,8 @@ use LIT\MCP\Integrations\Divi\Pages\DiviWriter;
|
|||||||
use LIT\MCP\Integrations\Divi\Pages\DynamicContentMap;
|
use LIT\MCP\Integrations\Divi\Pages\DynamicContentMap;
|
||||||
use LIT\MCP\Integrations\Divi\Release\CompatibilityCheck;
|
use LIT\MCP\Integrations\Divi\Release\CompatibilityCheck;
|
||||||
use LIT\MCP\Integrations\Divi\Release\DiviCheckRoute;
|
use LIT\MCP\Integrations\Divi\Release\DiviCheckRoute;
|
||||||
use LIT\MCP\Integrations\Divi\Release\ReleaseResolver;
|
|
||||||
use LIT\MCP\Integrations\Divi\Release\FeatureOverview;
|
use LIT\MCP\Integrations\Divi\Release\FeatureOverview;
|
||||||
|
use LIT\MCP\Integrations\Divi\Release\ReleaseGate;
|
||||||
use LIT\MCP\Integrations\Divi\Schema\DiviCatalogAbility;
|
use LIT\MCP\Integrations\Divi\Schema\DiviCatalogAbility;
|
||||||
use LIT\MCP\Integrations\Divi\Schema\DiviModules;
|
use LIT\MCP\Integrations\Divi\Schema\DiviModules;
|
||||||
use LIT\MCP\Integrations\Divi\ThemeBuilder\DiviThemeBuilder;
|
use LIT\MCP\Integrations\Divi\ThemeBuilder\DiviThemeBuilder;
|
||||||
@@ -212,7 +212,7 @@ final class DiviIntegration implements Integration, Bootable
|
|||||||
{
|
{
|
||||||
// Spec §5.4: a theme update checks the Divi fingerprints again at once (the state key would, too).
|
// Spec §5.4: a theme update checks the Divi fingerprints again at once (the state key would, too).
|
||||||
add_action('upgrader_process_complete', static function (): void {
|
add_action('upgrader_process_complete', static function (): void {
|
||||||
delete_transient(ReleaseResolver::CACHE);
|
ReleaseGate::invalidate(mirrors: true);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Spec §6: the admin check runs as a REST request (same context as MCP calls). Its short form has no
|
// Spec §6: the admin check runs as a REST request (same context as MCP calls). Its short form has no
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use LIT\MCP\Integrations\Divi\BlockTree\Outline;
|
|||||||
use LIT\MCP\Integrations\Divi\BlockTree\Serializer;
|
use LIT\MCP\Integrations\Divi\BlockTree\Serializer;
|
||||||
use LIT\MCP\Integrations\Divi\Design\DesignSystemReader;
|
use LIT\MCP\Integrations\Divi\Design\DesignSystemReader;
|
||||||
use LIT\MCP\Integrations\Divi\Release\DiviFeature;
|
use LIT\MCP\Integrations\Divi\Release\DiviFeature;
|
||||||
use LIT\MCP\Integrations\Divi\Release\DiviFeatureGate;
|
use LIT\MCP\Integrations\Divi\Release\ReleaseGate;
|
||||||
use LIT\MCP\Integrations\Divi\Schema\DiviModules;
|
use LIT\MCP\Integrations\Divi\Schema\DiviModules;
|
||||||
use LIT\MCP\Integrations\WordPress\Content\ContentComposer;
|
use LIT\MCP\Integrations\WordPress\Content\ContentComposer;
|
||||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||||
@@ -81,7 +81,7 @@ final class DiviContentComposer implements ContentComposer
|
|||||||
|
|
||||||
public function refusal(): ?WP_Error
|
public function refusal(): ?WP_Error
|
||||||
{
|
{
|
||||||
return DiviFeatureGate::lockFor(self::FEATURES)?->toError();
|
return ReleaseGate::lockOf(self::FEATURES)?->toError();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function check(string $postType, array $sections): ?WP_Error
|
public function check(string $postType, array $sections): ?WP_Error
|
||||||
|
|||||||
@@ -76,6 +76,27 @@ final class CompatibilityMatrix
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The statuses of those of $features that are not usable – each once, in the order of $features. The one answer
|
||||||
|
* to "what locks this call" for the gate (DiviFeatureGate), the adapters (ReleaseGate::assertFeatures()) and the
|
||||||
|
* refusal (ReleaseStatus::refusalFor()).
|
||||||
|
*
|
||||||
|
* @param list<DiviFeature> $features
|
||||||
|
* @return list<FeatureStatus>
|
||||||
|
*/
|
||||||
|
public function locked(array $features): array
|
||||||
|
{
|
||||||
|
$locked = [];
|
||||||
|
foreach ($features as $feature) {
|
||||||
|
$status = $this->of($feature);
|
||||||
|
if (! $status->usable()) {
|
||||||
|
$locked[$feature->value] = $status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_values($locked);
|
||||||
|
}
|
||||||
|
|
||||||
/** @return list<FeatureStatus> */
|
/** @return list<FeatureStatus> */
|
||||||
public function unusable(): array
|
public function unusable(): array
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ final class DiviCheckRoute
|
|||||||
try {
|
try {
|
||||||
$report = ($this->check)()->run(get_current_user_id());
|
$report = ($this->check)()->run(get_current_user_id());
|
||||||
($this->reports ?? new CheckReportStore())->save($report);
|
($this->reports ?? new CheckReportStore())->save($report);
|
||||||
ReleaseGate::forget();
|
ReleaseGate::invalidate();
|
||||||
$notice = 'divi_checked';
|
$notice = 'divi_checked';
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
Log::failure('divi check', $e);
|
Log::failure('divi check', $e);
|
||||||
|
|||||||
@@ -25,27 +25,9 @@ final class DiviFeatureGate implements AbilityGuard
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The lock for the usable-ness of $features, or null when every one is usable. Public: the Divi short form of
|
|
||||||
* lit/content-create asks the same question for its own capabilities (DiviContentComposer::refusal()).
|
|
||||||
*
|
|
||||||
* @param list<DiviFeature> $features
|
|
||||||
*/
|
|
||||||
public static function lockFor(array $features): ?DiviLocked
|
|
||||||
{
|
|
||||||
$unusable = [];
|
|
||||||
foreach ($features as $feature) {
|
|
||||||
if (! ReleaseGate::feature($feature)->usable()) {
|
|
||||||
$unusable[$feature->value] = $feature;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $unusable === [] ? null : new DiviLocked(ReleaseGate::status(), array_values($unusable));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function refusal(Ability $ability, array $input): ?WP_Error
|
public function refusal(Ability $ability, array $input): ?WP_Error
|
||||||
{
|
{
|
||||||
$lock = self::lockFor(FeatureSets::declaredBy($ability, $input));
|
$lock = ReleaseGate::lockOf(FeatureSets::declaredBy($ability, $input));
|
||||||
if ($lock === null) {
|
if ($lock === null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,15 +51,25 @@ final class ReleaseGate
|
|||||||
self::$probe = null;
|
self::$probe = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The next status() computes again (after a check, a release or a withdrawal). */
|
/** The next status() of this request computes again; the cached mirror results stay (see invalidate()). */
|
||||||
public static function forget(): void
|
public static function forget(): void
|
||||||
{
|
{
|
||||||
self::$status = null;
|
self::$status = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function feature(DiviFeature $feature): FeatureStatus
|
/**
|
||||||
|
* The single way to make the release state current again: forgets the status of this request and, with
|
||||||
|
* $mirrors, also deletes the cached mirror results (transient ReleaseResolver::CACHE) so the next status()
|
||||||
|
* fingerprints Divi's code again. Without $mirrors: after a release or a withdrawal and after the admin check
|
||||||
|
* (only the source of the state changed). With $mirrors: after a theme update, a CLI check or a new reference
|
||||||
|
* (the code or the reference may have changed).
|
||||||
|
*/
|
||||||
|
public static function invalidate(bool $mirrors = false): void
|
||||||
{
|
{
|
||||||
return self::status()->matrix->of($feature);
|
if ($mirrors) {
|
||||||
|
delete_transient(ReleaseResolver::CACHE);
|
||||||
|
}
|
||||||
|
self::forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @throws DiviLocked When $feature is not usable – before anything is written. */
|
/** @throws DiviLocked When $feature is not usable – before anything is written. */
|
||||||
@@ -80,16 +90,28 @@ final class ReleaseGate
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$lock = self::lockOf($features);
|
||||||
|
if ($lock !== null) {
|
||||||
|
throw $lock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The lock of this request's status for the locked ones of $features, or null when every one is usable. Asked by
|
||||||
|
* DiviFeatureGate before a tool runs and by the Divi short form of lit/content-create (DiviContentComposer::
|
||||||
|
* refusal()); no probe exception – tool calls never write the probe page.
|
||||||
|
*
|
||||||
|
* @param list<DiviFeature> $features
|
||||||
|
*/
|
||||||
|
public static function lockOf(array $features): ?DiviLocked
|
||||||
|
{
|
||||||
$status = self::status();
|
$status = self::status();
|
||||||
$locked = [];
|
$locked = $status->matrix->locked($features);
|
||||||
foreach ($features as $feature) {
|
|
||||||
if (! $status->matrix->of($feature)->usable()) {
|
return $locked === [] ? null : new DiviLocked(
|
||||||
$locked[$feature->value] = $feature;
|
$status,
|
||||||
}
|
array_map(static fn (FeatureStatus $feature): DiviFeature => $feature->feature, $locked)
|
||||||
}
|
);
|
||||||
if ($locked !== []) {
|
|
||||||
throw new DiviLocked($status, array_values($locked));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function whileProbing(int $postId, callable $write): mixed
|
public static function whileProbing(int $postId, callable $write): mixed
|
||||||
|
|||||||
@@ -77,18 +77,11 @@ final class ReleaseStatus
|
|||||||
*/
|
*/
|
||||||
public function refusalFor(array $features): WP_Error
|
public function refusalFor(array $features): WP_Error
|
||||||
{
|
{
|
||||||
$locked = [];
|
$locked = $this->matrix->locked($features);
|
||||||
foreach ($features as $feature) {
|
|
||||||
$status = $this->matrix->of($feature);
|
|
||||||
if (! $status->usable()) {
|
|
||||||
$locked[$feature->value] = $status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($locked === []) {
|
if ($locked === []) {
|
||||||
throw new LogicException('usable features refuse nothing');
|
throw new LogicException('usable features refuse nothing');
|
||||||
}
|
}
|
||||||
|
|
||||||
$locked = array_values($locked);
|
|
||||||
$incompatible = array_values(array_filter(
|
$incompatible = array_values(array_filter(
|
||||||
$locked,
|
$locked,
|
||||||
static fn (FeatureStatus $status): bool => $status->state === ReleaseState::Incompatible
|
static fn (FeatureStatus $status): bool => $status->state === ReleaseState::Incompatible
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use LIT\MCP\Integrations\Divi\Release\CompatibilityMatrix;
|
|||||||
use LIT\MCP\Integrations\Divi\Release\DiviFeature;
|
use LIT\MCP\Integrations\Divi\Release\DiviFeature;
|
||||||
use LIT\MCP\Integrations\Divi\Release\FeatureStatus;
|
use LIT\MCP\Integrations\Divi\Release\FeatureStatus;
|
||||||
use LIT\MCP\Integrations\Divi\Release\ReleaseState;
|
use LIT\MCP\Integrations\Divi\Release\ReleaseState;
|
||||||
|
use LIT\MCP\Tests\Support\ReleaseMatrices;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
final class CompatibilityMatrixTest extends TestCase
|
final class CompatibilityMatrixTest extends TestCase
|
||||||
@@ -84,6 +85,29 @@ final class CompatibilityMatrixTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testLockedNamesEveryUnusableFeatureOnceInTheGivenOrder(): void
|
||||||
|
{
|
||||||
|
$matrix = ReleaseMatrices::matrix(
|
||||||
|
[DiviFeature::LibraryWrite, DiviFeature::ThemeBuilderWrite, DiviFeature::Catalog],
|
||||||
|
ReleaseState::Incompatible
|
||||||
|
);
|
||||||
|
|
||||||
|
$locked = $matrix->locked([
|
||||||
|
DiviFeature::PageWrite,
|
||||||
|
DiviFeature::ThemeBuilderWrite,
|
||||||
|
DiviFeature::LibraryWrite,
|
||||||
|
DiviFeature::ThemeBuilderWrite,
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertSame(
|
||||||
|
[DiviFeature::ThemeBuilderWrite, DiviFeature::LibraryWrite],
|
||||||
|
array_map(static fn (FeatureStatus $status): DiviFeature => $status->feature, $locked)
|
||||||
|
);
|
||||||
|
self::assertSame(ReleaseState::Incompatible, $locked[0]->state);
|
||||||
|
self::assertSame([], $matrix->locked([DiviFeature::PageWrite, DiviFeature::PageRead]));
|
||||||
|
self::assertSame([], $matrix->locked([]));
|
||||||
|
}
|
||||||
|
|
||||||
public function testToArrayListsEveryFeatureInCaseOrder(): void
|
public function testToArrayListsEveryFeatureInCaseOrder(): void
|
||||||
{
|
{
|
||||||
$rows = self::matrix(['tb-write' => [ReleaseState::Incompatible, ['b']]])->toArray();
|
$rows = self::matrix(['tb-write' => [ReleaseState::Incompatible, ['b']]])->toArray();
|
||||||
|
|||||||
@@ -317,19 +317,6 @@ final class DiviFeatureGateTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testLockForIsNullForUsableFeaturesAndNamesTheUnusableOnesOtherwise(): void
|
|
||||||
{
|
|
||||||
self::assertNull(DiviFeatureGate::lockFor([]));
|
|
||||||
self::assertNull(DiviFeatureGate::lockFor([DiviFeature::PageWrite]));
|
|
||||||
|
|
||||||
DiviFeatureFixtures::lock(DiviFeature::Catalog);
|
|
||||||
$lock = DiviFeatureGate::lockFor([DiviFeature::PageWrite, DiviFeature::Catalog, DiviFeature::Catalog]);
|
|
||||||
|
|
||||||
self::assertNotNull($lock);
|
|
||||||
self::assertSame([DiviFeature::Catalog], $lock->features);
|
|
||||||
self::assertSame('5.3.0', $lock->status->version);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The real tools of the three Divi groups: locking one capability refuses exactly the tools that declare it
|
* The real tools of the three Divi groups: locking one capability refuses exactly the tools that declare it
|
||||||
* (reading and writing alike) and no other.
|
* (reading and writing alike) and no other.
|
||||||
|
|||||||
@@ -4,12 +4,15 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Release;
|
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Release;
|
||||||
|
|
||||||
|
use Brain\Monkey\Functions;
|
||||||
use LIT\MCP\Abilities\WriteFailed;
|
use LIT\MCP\Abilities\WriteFailed;
|
||||||
use LIT\MCP\Integrations\Divi\Release\DiviFeature;
|
use LIT\MCP\Integrations\Divi\Release\DiviFeature;
|
||||||
use LIT\MCP\Integrations\Divi\Release\DiviLocked;
|
use LIT\MCP\Integrations\Divi\Release\DiviLocked;
|
||||||
use LIT\MCP\Integrations\Divi\Release\ReleaseGate;
|
use LIT\MCP\Integrations\Divi\Release\ReleaseGate;
|
||||||
|
use LIT\MCP\Integrations\Divi\Release\ReleaseResolver;
|
||||||
use LIT\MCP\Integrations\Divi\Release\ReleaseState;
|
use LIT\MCP\Integrations\Divi\Release\ReleaseState;
|
||||||
use LIT\MCP\Integrations\Divi\Release\ReleaseStatus;
|
use LIT\MCP\Integrations\Divi\Release\ReleaseStatus;
|
||||||
|
use LIT\MCP\Tests\Support\DiviFeatureFixtures;
|
||||||
use LIT\MCP\Tests\Support\ReleaseMatrices;
|
use LIT\MCP\Tests\Support\ReleaseMatrices;
|
||||||
use LIT\MCP\Tests\Unit\TestCase;
|
use LIT\MCP\Tests\Unit\TestCase;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
@@ -27,12 +30,17 @@ final class ReleaseGateTest extends TestCase
|
|||||||
ReleaseGate::assertFeatures(DiviFeature::cases(), 7);
|
ReleaseGate::assertFeatures(DiviFeature::cases(), 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testFeatureReadsTheMatrixOfThisRequest(): void
|
public function testLockOfIsNullForUsableFeaturesAndNamesTheUnusableOnesOtherwise(): void
|
||||||
{
|
{
|
||||||
ReleaseGate::useResolver(static fn (): ReleaseStatus => ReleaseMatrices::status([DiviFeature::Catalog]));
|
self::assertNull(ReleaseGate::lockOf([]));
|
||||||
|
self::assertNull(ReleaseGate::lockOf([DiviFeature::PageWrite]));
|
||||||
|
|
||||||
self::assertSame(ReleaseState::Untested, ReleaseGate::feature(DiviFeature::Catalog)->state);
|
DiviFeatureFixtures::lock(DiviFeature::Catalog);
|
||||||
self::assertTrue(ReleaseGate::feature(DiviFeature::PageRead)->usable());
|
$lock = ReleaseGate::lockOf([DiviFeature::PageWrite, DiviFeature::Catalog, DiviFeature::Catalog]);
|
||||||
|
|
||||||
|
self::assertNotNull($lock);
|
||||||
|
self::assertSame([DiviFeature::Catalog], $lock->features);
|
||||||
|
self::assertSame('5.3.0', $lock->status->version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAssertFeatureRefusesOnlyALockedFeature(): void
|
public function testAssertFeatureRefusesOnlyALockedFeature(): void
|
||||||
@@ -149,6 +157,33 @@ final class ReleaseGateTest extends TestCase
|
|||||||
self::assertSame(2, $calls);
|
self::assertSame(2, $calls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testInvalidateForgetsTheStatusAndClearsTheMirrorCacheOnlyWhenAsked(): void
|
||||||
|
{
|
||||||
|
$calls = 0;
|
||||||
|
$deleted = [];
|
||||||
|
ReleaseGate::useResolver(static function () use (&$calls): ReleaseStatus {
|
||||||
|
++$calls;
|
||||||
|
|
||||||
|
return ReleaseMatrices::released('5.2.1');
|
||||||
|
});
|
||||||
|
Functions\when('delete_transient')->alias(static function (string $key) use (&$deleted): bool {
|
||||||
|
$deleted[] = $key;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
ReleaseGate::status();
|
||||||
|
ReleaseGate::invalidate();
|
||||||
|
ReleaseGate::status();
|
||||||
|
self::assertSame(2, $calls);
|
||||||
|
self::assertSame([], $deleted, 'a release or withdrawal leaves the mirror results alone');
|
||||||
|
|
||||||
|
ReleaseGate::invalidate(mirrors: true);
|
||||||
|
ReleaseGate::status();
|
||||||
|
self::assertSame(3, $calls);
|
||||||
|
self::assertSame([ReleaseResolver::CACHE], $deleted);
|
||||||
|
}
|
||||||
|
|
||||||
public function testAFailingResolverLocksWrites(): void
|
public function testAFailingResolverLocksWrites(): void
|
||||||
{
|
{
|
||||||
ReleaseGate::useResolver(static function (): never {
|
ReleaseGate::useResolver(static function (): never {
|
||||||
|
|||||||
Reference in New Issue
Block a user