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:
Jan-Niclas Loosen
2026-10-18 22:57:35 +02:00
co-authored by Claude Opus 5.5
parent 7f9a087b8b
commit 63389f35a8
12 changed files with 129 additions and 68 deletions
@@ -4,12 +4,15 @@ declare(strict_types=1);
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Release;
use Brain\Monkey\Functions;
use LIT\MCP\Abilities\WriteFailed;
use LIT\MCP\Integrations\Divi\Release\DiviFeature;
use LIT\MCP\Integrations\Divi\Release\DiviLocked;
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\ReleaseStatus;
use LIT\MCP\Tests\Support\DiviFeatureFixtures;
use LIT\MCP\Tests\Support\ReleaseMatrices;
use LIT\MCP\Tests\Unit\TestCase;
use RuntimeException;
@@ -27,12 +30,17 @@ final class ReleaseGateTest extends TestCase
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);
self::assertTrue(ReleaseGate::feature(DiviFeature::PageRead)->usable());
DiviFeatureFixtures::lock(DiviFeature::Catalog);
$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
@@ -149,6 +157,33 @@ final class ReleaseGateTest extends TestCase
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
{
ReleaseGate::useResolver(static function (): never {