middleware(); // Assert middleware exists expect($middleware)->toBeArray() ->and($middleware)->toHaveCount(1); $overlappingMiddleware = $middleware[0]; // Assert it's a WithoutOverlapping instance expect($overlappingMiddleware)->toBeInstanceOf(WithoutOverlapping::class); // Use reflection to check private properties $reflection = new ReflectionClass($overlappingMiddleware); // Check expireAfter is set (should be 60 seconds - matches job frequency) $expiresAfterProperty = $reflection->getProperty('expiresAfter'); $expiresAfterProperty->setAccessible(true); $expiresAfter = $expiresAfterProperty->getValue($overlappingMiddleware); expect($expiresAfter)->toBe(90) ->and($expiresAfter)->toBeGreaterThan(0, 'expireAfter must be set to prevent stale locks'); // Check releaseAfter is NOT set (we use dontRelease) $releaseAfterProperty = $reflection->getProperty('releaseAfter'); $releaseAfterProperty->setAccessible(true); $releaseAfter = $releaseAfterProperty->getValue($overlappingMiddleware); expect($releaseAfter)->toBeNull('releaseAfter should be null when using dontRelease()'); // Check the lock key $keyProperty = $reflection->getProperty('key'); $keyProperty->setAccessible(true); $key = $keyProperty->getValue($overlappingMiddleware); expect($key)->toBe('scheduled-job-manager'); });