fix(audit L5): unter der Sperre Divis Laufzeit-Caches verwerfen (Options-Cache-Gruppe, GlobalData-/GlobalPreset-Static, et_theme_options) vor raw() und design_rev
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
6e84138979
commit
99c7aab238
@@ -43,6 +43,7 @@ final class ColorAreaTest extends TestCase
|
||||
public static function adapter(array &$stored, array &$saves): GlobalColorsAdapter
|
||||
{
|
||||
$colors = Mockery::mock(GlobalColorsAdapter::class);
|
||||
$colors->allows('refresh');
|
||||
$colors->allows('read')->andReturnUsing(static function () use (&$stored): array {
|
||||
return $stored;
|
||||
});
|
||||
|
||||
@@ -47,6 +47,7 @@ final class ColorRestorePlannerTest extends TestCase
|
||||
private static function planner(bool $visualBuilder = true, ?GlobalUsages $usages = null): ColorRestorePlanner
|
||||
{
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('canUseVisualBuilder')->andReturn($visualBuilder);
|
||||
|
||||
return new ColorRestorePlanner(
|
||||
|
||||
@@ -56,6 +56,9 @@ final class DesignChangeTest extends TestCase
|
||||
|
||||
public array $restores = [];
|
||||
|
||||
/** @var list<string> refresh()/raw() in the order they happened */
|
||||
public array $calls = [];
|
||||
|
||||
public function __construct(
|
||||
private array &$stored,
|
||||
private int $failWrites,
|
||||
@@ -79,8 +82,15 @@ final class DesignChangeTest extends TestCase
|
||||
return DiviFeature::PresetWrite;
|
||||
}
|
||||
|
||||
public function refresh(): void
|
||||
{
|
||||
$this->calls[] = 'refresh';
|
||||
}
|
||||
|
||||
public function raw(): array
|
||||
{
|
||||
$this->calls[] = 'raw';
|
||||
|
||||
return $this->stored;
|
||||
}
|
||||
|
||||
@@ -205,6 +215,25 @@ final class DesignChangeTest extends TestCase
|
||||
self::assertSame([], $area->writes);
|
||||
}
|
||||
|
||||
/** Audit L5 (re-review): under the lock Divi's request caches are dropped before the inventory is read. */
|
||||
public function testTheAreaDropsItsCachesUnderTheLockBeforeReading(): void
|
||||
{
|
||||
$stored = ['v' => 1];
|
||||
$area = self::area($stored);
|
||||
$snapshots = Mockery::mock(SnapshotStore::class);
|
||||
$snapshots->allows('save')->andReturn('presets-1');
|
||||
$snapshots->allows('attachLog');
|
||||
|
||||
(new DesignChange($snapshots, new FakeChangeLog(1), new DesignLock()))->run(
|
||||
'lit/divi-presets-set',
|
||||
$area,
|
||||
['confirm' => true, 'design_rev' => $area->rev($stored)],
|
||||
self::plan(['v' => 2])
|
||||
);
|
||||
|
||||
self::assertSame(['refresh', 'raw'], array_slice($area->calls, 0, 2));
|
||||
}
|
||||
|
||||
/** Final review I-5: a confirm while another change of the area runs writes nothing. */
|
||||
public function testAHeldLockRefusesTheConfirm(): void
|
||||
{
|
||||
|
||||
@@ -102,26 +102,33 @@ final class DesignLockTest extends TestCase
|
||||
public function testTheLockHolderReadsEtDiviFreshNotFromTheRequestStartCache(): void
|
||||
{
|
||||
$db = $this->table();
|
||||
$stored = ['et_divi' => ['color' => 'alt']];
|
||||
$stored = ['et_divi' => ['color' => 'alt'], 'et_divi_global_variables' => ['v' => 'alt']];
|
||||
$cache = [];
|
||||
// Like WordPress: every option is cached under its own key (not autoloaded ones) or in "alloptions".
|
||||
Functions\when('get_option')->alias(static function (string $name) use (&$stored, &$cache) {
|
||||
if (! isset($cache['options:' . $name]) && ! isset($cache['options:alloptions'][$name])) {
|
||||
$cache['options:alloptions'][$name] = $stored[$name] ?? false;
|
||||
}
|
||||
$key = 'options:' . $name;
|
||||
$cache[$key] ??= $stored[$name] ?? false;
|
||||
|
||||
return $cache['options:' . $name] ?? $cache['options:alloptions'][$name];
|
||||
return $cache[$key];
|
||||
});
|
||||
Functions\when('wp_cache_delete')->alias(static function (string $key, string $group = '') use (&$cache): bool {
|
||||
unset($cache[$group . ':' . $key]);
|
||||
Functions\when('wp_cache_flush_group')->alias(static function (string $group) use (&$cache): bool {
|
||||
foreach (array_keys($cache) as $key) {
|
||||
if (str_starts_with($key, $group . ':')) {
|
||||
unset($cache[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
self::assertSame(['color' => 'alt'], get_option('et_divi'), 'request B cached the old array');
|
||||
self::assertSame(['v' => 'alt'], get_option('et_divi_global_variables'));
|
||||
$stored['et_divi'] = ['color' => 'neu']; // request A wrote and released meanwhile
|
||||
$stored['et_divi_global_variables'] = ['v' => 'neu'];
|
||||
|
||||
self::assertTrue((new DesignLock())->acquire('colors'));
|
||||
self::assertSame(['color' => 'neu'], get_option('et_divi'));
|
||||
self::assertSame(['v' => 'neu'], get_option('et_divi_global_variables'), 'also options that are not autoloaded');
|
||||
self::assertNotSame([], $db->rows);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ final class DesignRightsTest extends TestCase
|
||||
public function testPresetsNeedEditThemeOptionsAndTheVisualBuilder(): void
|
||||
{
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true, false);
|
||||
Functions\when('current_user_can')->alias(static fn (string $cap): bool => $cap === 'edit_theme_options');
|
||||
|
||||
@@ -33,6 +34,7 @@ final class DesignRightsTest extends TestCase
|
||||
public function testColorsNeedEditThemeOptionsAndTheVisualBuilder(): void
|
||||
{
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true, false);
|
||||
Functions\when('current_user_can')->alias(static fn (string $cap): bool => $cap === 'edit_theme_options');
|
||||
|
||||
@@ -49,8 +51,10 @@ final class DesignRightsTest extends TestCase
|
||||
public function testVariablesAlsoNeedTheVariablesManager(): void
|
||||
{
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true);
|
||||
$variables = Mockery::mock(GlobalVariablesAdapter::class);
|
||||
$variables->allows('refresh');
|
||||
$variables->allows('canManage')->andReturn(true, false);
|
||||
Functions\when('current_user_can')->alias(static fn (string $cap): bool => $cap === 'edit_theme_options');
|
||||
|
||||
@@ -63,8 +67,10 @@ final class DesignRightsTest extends TestCase
|
||||
public function testVariablesAskTheThemeRightAndTheVisualBuilderFirst(): void
|
||||
{
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(false);
|
||||
$variables = Mockery::mock(GlobalVariablesAdapter::class);
|
||||
$variables->allows('refresh');
|
||||
$variables->allows('canManage')->andReturn(true);
|
||||
Functions\when('current_user_can')->justReturn(true);
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ final class DiviColorsSetAbilityTest extends TestCase
|
||||
bool $visualBuilder = true
|
||||
): DiviColorsSetAbility {
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('canUseVisualBuilder')->andReturn($visualBuilder);
|
||||
$writer->allows('presets')->andReturn($presets === [] ? PresetBookTest::stored() : $presets);
|
||||
$counter = 0;
|
||||
@@ -297,6 +298,7 @@ final class DiviColorsSetAbilityTest extends TestCase
|
||||
{
|
||||
$calls = [];
|
||||
$colors = Mockery::mock(GlobalColorsAdapter::class);
|
||||
$colors->allows('refresh');
|
||||
$colors->allows('read')->andReturn(ColorAreaTest::stored());
|
||||
$colors->allows('save')->andReturnUsing(static function (array $entries, bool $replace) use (&$calls): void {
|
||||
$calls[] = $replace;
|
||||
|
||||
@@ -80,6 +80,7 @@ final class DiviDesignDetachAbilityTest extends TestCase
|
||||
private static function readOnlyWriter(?array $stored = null): DesignSystemWriter&MockInterface
|
||||
{
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('presets')->andReturn($stored ?? PresetBookTest::stored());
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true);
|
||||
$writer->expects('savePresets')->never();
|
||||
@@ -91,6 +92,7 @@ final class DiviDesignDetachAbilityTest extends TestCase
|
||||
private static function variableAdapter(bool $manage = true, string $radius = '8px'): GlobalVariablesAdapter&MockInterface
|
||||
{
|
||||
$variables = Mockery::mock(GlobalVariablesAdapter::class);
|
||||
$variables->allows('refresh');
|
||||
$variables->allows('read')->andReturn(self::variables($radius));
|
||||
$variables->allows('canManage')->andReturn($manage);
|
||||
$variables->expects('save')->never();
|
||||
@@ -246,6 +248,7 @@ final class DiviDesignDetachAbilityTest extends TestCase
|
||||
$calls = [];
|
||||
$stored = self::storedWithVariable();
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('presets')->andReturn($stored);
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true);
|
||||
$writer->expects('savePresets')
|
||||
@@ -451,6 +454,7 @@ final class DiviDesignDetachAbilityTest extends TestCase
|
||||
{
|
||||
$calls = [];
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('presets')->andReturn(PresetBookTest::stored());
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true);
|
||||
$writer->expects('savePresets')
|
||||
@@ -502,6 +506,7 @@ final class DiviDesignDetachAbilityTest extends TestCase
|
||||
public function testAPageErrorAfterThePresetStepSaysThePresetsAreChanged(): void
|
||||
{
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('presets')->andReturn(PresetBookTest::stored());
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true);
|
||||
$writer->expects('savePresets')
|
||||
@@ -633,6 +638,7 @@ final class DiviDesignDetachAbilityTest extends TestCase
|
||||
private function abilityAfterThePresetStep(PageRewriter $pages): DiviDesignDetachAbility
|
||||
{
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('presets')->andReturn(PresetBookTest::stored());
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true);
|
||||
$writer->expects('savePresets')
|
||||
|
||||
@@ -42,6 +42,7 @@ final class DiviDesignRestoreAbilityTest extends TestCase
|
||||
$older = PresetBookTest::stored();
|
||||
unset($older['module']['divi/button']['items']['bbbbbbbbbb']);
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('presets')->andReturn(PresetBookTest::stored());
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true);
|
||||
$writer->expects('savePresets')->with(Mockery::type('array'), true)->andReturn($older);
|
||||
@@ -73,6 +74,7 @@ final class DiviDesignRestoreAbilityTest extends TestCase
|
||||
{
|
||||
Functions\when('current_user_can')->justReturn(true);
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('presets')->andReturn($current);
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true);
|
||||
$snapshots = Mockery::mock(SnapshotStore::class);
|
||||
@@ -108,6 +110,7 @@ final class DiviDesignRestoreAbilityTest extends TestCase
|
||||
{
|
||||
Functions\when('current_user_can')->justReturn(false);
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true);
|
||||
$writer->shouldNotReceive('savePresets');
|
||||
$snapshots = Mockery::mock(SnapshotStore::class);
|
||||
@@ -144,6 +147,7 @@ final class DiviDesignRestoreAbilityTest extends TestCase
|
||||
{
|
||||
Functions\when('current_user_can')->justReturn(true);
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true);
|
||||
$snapshots = Mockery::mock(SnapshotStore::class);
|
||||
$snapshots->shouldNotReceive('get');
|
||||
@@ -171,6 +175,7 @@ final class DiviDesignRestoreAbilityTest extends TestCase
|
||||
): DiviDesignRestoreAbility {
|
||||
Functions\when('current_user_can')->justReturn(true);
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true);
|
||||
$writer->allows('presets')->andReturn(PresetBookTest::stored());
|
||||
$writer->shouldNotReceive('savePresets');
|
||||
@@ -206,6 +211,7 @@ final class DiviDesignRestoreAbilityTest extends TestCase
|
||||
private static function colorStore(array $stored): GlobalColorsAdapter&MockInterface
|
||||
{
|
||||
$colors = Mockery::mock(GlobalColorsAdapter::class);
|
||||
$colors->allows('refresh');
|
||||
$colors->allows('read')->andReturnUsing(static function () use (&$stored): array {
|
||||
return $stored;
|
||||
});
|
||||
@@ -225,6 +231,7 @@ final class DiviDesignRestoreAbilityTest extends TestCase
|
||||
private static function variableStore(array $stored, bool $manage = true): GlobalVariablesAdapter&MockInterface
|
||||
{
|
||||
$variables = Mockery::mock(GlobalVariablesAdapter::class);
|
||||
$variables->allows('refresh');
|
||||
$variables->allows('canManage')->andReturn($manage);
|
||||
$variables->allows('read')->andReturnUsing(static function () use (&$stored): array {
|
||||
return $stored;
|
||||
|
||||
@@ -19,6 +19,7 @@ final class DiviPresetGetAbilityTest extends TestCase
|
||||
private function ability(?GlobalUsages $usages = null): DiviPresetGetAbility
|
||||
{
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('presets')->andReturn(PresetBookTest::stored());
|
||||
$usages ??= Mockery::mock(GlobalUsages::class);
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ final class DiviPresetsAssignAbilityTest extends TestCase
|
||||
private function ability(PageRewriter $pages): DiviPresetsAssignAbility
|
||||
{
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('presets')->andReturn(PresetBookTest::stored());
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true);
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ final class DiviPresetsDeleteAbilityTest extends TestCase
|
||||
Functions\when('current_user_can')->justReturn(true);
|
||||
if ($writer === null) {
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('presets')->andReturn($stored === [] ? PresetBookTest::stored() : $stored);
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true);
|
||||
}
|
||||
@@ -59,6 +60,7 @@ final class DiviPresetsDeleteAbilityTest extends TestCase
|
||||
public function testUnusedPresetIsDeletedAfterConfirm(): void
|
||||
{
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('presets')->andReturn(PresetBookTest::stored());
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true);
|
||||
$writer->expects('savePresets')
|
||||
@@ -153,6 +155,7 @@ final class DiviPresetsDeleteAbilityTest extends TestCase
|
||||
0, 1, [], 0, false);
|
||||
Functions\when('current_user_can')->justReturn(true);
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('presets')->andReturn(PresetBookTest::stored());
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true);
|
||||
$usages = Mockery::mock(GlobalUsages::class);
|
||||
|
||||
@@ -52,6 +52,7 @@ final class DiviPresetsSetAbilityTest extends TestCase
|
||||
private function savingWriter(): DesignSystemWriter
|
||||
{
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('presets')->andReturnUsing(fn (): array => $this->stored);
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true);
|
||||
$writer->allows('savePresets')->andReturnUsing(function (array $rest, bool $mayRemove): array {
|
||||
@@ -291,6 +292,7 @@ final class DiviPresetsSetAbilityTest extends TestCase
|
||||
public function testNothingIsWrittenWhenOneItemHasErrors(): void
|
||||
{
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('presets')->andReturnUsing(fn (): array => $this->stored);
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true);
|
||||
$writer->shouldNotReceive('savePresets');
|
||||
|
||||
@@ -53,6 +53,7 @@ final class DiviVariablesSetAbilityTest extends TestCase
|
||||
?FontCatalog $fonts = null
|
||||
): DiviVariablesSetAbility {
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true);
|
||||
$writer->allows('presets')->andReturn($presets === [] ? PresetBookTest::stored() : $presets);
|
||||
$counter = 0;
|
||||
@@ -313,6 +314,7 @@ final class DiviVariablesSetAbilityTest extends TestCase
|
||||
{
|
||||
$calls = [];
|
||||
$variables = Mockery::mock(GlobalVariablesAdapter::class);
|
||||
$variables->allows('refresh');
|
||||
$variables->allows('canManage')->andReturn(true);
|
||||
$variables->allows('read')->andReturn(VariableAreaTest::stored());
|
||||
$variables->allows('save')->andReturnUsing(static function (array $data, array $expected) use (&$calls): void {
|
||||
|
||||
@@ -16,6 +16,7 @@ final class PresetAreaTest extends TestCase
|
||||
public function testWritesTheRestFormatAndReadsBack(): void
|
||||
{
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$stored = PresetBookTest::stored();
|
||||
$writer->allows('presets')->andReturn($stored);
|
||||
$writer->expects('savePresets')
|
||||
@@ -50,6 +51,7 @@ final class PresetAreaTest extends TestCase
|
||||
public function testRestoreReplacesTheWholeInventory(): void
|
||||
{
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$stored = PresetBookTest::stored();
|
||||
$writer->expects('savePresets')->with(PresetBook::fromDivi($stored)->toRest(), true)->andReturn($stored);
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ final class VariableAreaTest extends TestCase
|
||||
public static function adapter(array &$stored, array &$saves, bool $manage = true): GlobalVariablesAdapter
|
||||
{
|
||||
$variables = Mockery::mock(GlobalVariablesAdapter::class);
|
||||
$variables->allows('refresh');
|
||||
$variables->allows('canManage')->andReturn($manage);
|
||||
$variables->allows('read')->andReturnUsing(static function () use (&$stored): array {
|
||||
return $stored;
|
||||
|
||||
@@ -47,8 +47,10 @@ final class VariableRestorePlannerTest extends TestCase
|
||||
private static function planner(bool $manage = true, ?GlobalUsages $usages = null): VariableRestorePlanner
|
||||
{
|
||||
$writer = Mockery::mock(DesignSystemWriter::class);
|
||||
$writer->allows('refresh');
|
||||
$writer->allows('canUseVisualBuilder')->andReturn(true);
|
||||
$variables = Mockery::mock(GlobalVariablesAdapter::class);
|
||||
$variables->allows('refresh');
|
||||
$variables->allows('canManage')->andReturn($manage);
|
||||
|
||||
return new VariableRestorePlanner($writer, $variables, $usages ?? UsageFixture::none());
|
||||
|
||||
Reference in New Issue
Block a user