feat(Docker): Upgrade to PHP 8.5.0RC3 with native ext-uri support
BREAKING CHANGE: Requires PHP 8.5.0RC3 Changes: - Update Docker base image from php:8.4-fpm to php:8.5.0RC3-fpm - Enable ext-uri for native WHATWG URL parsing support - Update composer.json PHP requirement from ^8.4 to ^8.5 - Add ext-uri as required extension in composer.json - Move URL classes from Url.php85/ to Url/ directory (now compatible) - Remove temporary PHP 8.4 compatibility workarounds Benefits: - Native URL parsing with Uri\WhatWg\Url class - Better performance for URL operations - Future-proof with latest PHP features - Eliminates PHP version compatibility issues
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Framework\Cache\CacheItem;
|
||||
use App\Framework\Cache\CacheKey;
|
||||
use App\Framework\Cache\Driver\InMemoryCache;
|
||||
use App\Framework\Core\ValueObjects\Duration;
|
||||
@@ -12,65 +13,71 @@ beforeEach(function () {
|
||||
|
||||
test('get returns miss for non-existent key', function () {
|
||||
$key = CacheKey::fromString('non-existent');
|
||||
$item = $this->cache->get($key);
|
||||
$result = $this->cache->get($key);
|
||||
|
||||
expect($item->isHit)->toBeFalse()
|
||||
->and($item->key)->toBe($key)
|
||||
->and($item->value)->toBeNull();
|
||||
expect($result->isHit)->toBeFalse()
|
||||
->and($result->value)->toBeNull();
|
||||
});
|
||||
|
||||
test('set and get stores and retrieves value', function () {
|
||||
$key = CacheKey::fromString('test-key');
|
||||
$value = 'test-value';
|
||||
|
||||
$result = $this->cache->set($key, $value);
|
||||
$result = $this->cache->set(CacheItem::forSet($key, $value));
|
||||
|
||||
expect($result)->toBeTrue();
|
||||
|
||||
$item = $this->cache->get($key);
|
||||
$cacheResult = $this->cache->get($key);
|
||||
|
||||
expect($item->isHit)->toBeTrue()
|
||||
->and($item->key)->toBe($key)
|
||||
->and($item->value)->toBe($value);
|
||||
expect($cacheResult->isHit)->toBeTrue()
|
||||
->and($cacheResult->value)->toBe($value);
|
||||
});
|
||||
|
||||
test('has returns correct existence status', function () {
|
||||
$key = CacheKey::fromString('test-key');
|
||||
|
||||
expect($this->cache->has($key))->toBeFalse();
|
||||
$hasResult = $this->cache->has($key);
|
||||
expect($hasResult['test-key'])->toBeFalse();
|
||||
|
||||
$this->cache->set($key, 'value');
|
||||
$this->cache->set(CacheItem::forSet($key, 'value'));
|
||||
|
||||
expect($this->cache->has($key))->toBeTrue();
|
||||
$hasResult = $this->cache->has($key);
|
||||
expect($hasResult['test-key'])->toBeTrue();
|
||||
});
|
||||
|
||||
test('forget removes item from cache', function () {
|
||||
$key = CacheKey::fromString('test-key');
|
||||
$this->cache->set($key, 'value');
|
||||
$this->cache->set(CacheItem::forSet($key, 'value'));
|
||||
|
||||
expect($this->cache->has($key))->toBeTrue();
|
||||
$hasResult = $this->cache->has($key);
|
||||
expect($hasResult['test-key'])->toBeTrue();
|
||||
|
||||
$result = $this->cache->forget($key);
|
||||
|
||||
expect($result)->toBeTrue()
|
||||
->and($this->cache->has($key))->toBeFalse();
|
||||
expect($result)->toBeTrue();
|
||||
|
||||
$hasResult = $this->cache->has($key);
|
||||
expect($hasResult['test-key'])->toBeFalse();
|
||||
});
|
||||
|
||||
test('clear removes all items from cache', function () {
|
||||
$key1 = CacheKey::fromString('key1');
|
||||
$key2 = CacheKey::fromString('key2');
|
||||
|
||||
$this->cache->set($key1, 'value1');
|
||||
$this->cache->set($key2, 'value2');
|
||||
$this->cache->set(CacheItem::forSet($key1, 'value1'));
|
||||
$this->cache->set(CacheItem::forSet($key2, 'value2'));
|
||||
|
||||
expect($this->cache->has($key1))->toBeTrue()
|
||||
->and($this->cache->has($key2))->toBeTrue();
|
||||
$hasResult = $this->cache->has($key1, $key2);
|
||||
expect($hasResult['key1'])->toBeTrue();
|
||||
expect($hasResult['key2'])->toBeTrue();
|
||||
|
||||
$result = $this->cache->clear();
|
||||
|
||||
expect($result)->toBeTrue()
|
||||
->and($this->cache->has($key1))->toBeFalse()
|
||||
->and($this->cache->has($key2))->toBeFalse();
|
||||
expect($result)->toBeTrue();
|
||||
|
||||
$hasResult = $this->cache->has($key1, $key2);
|
||||
expect($hasResult['key1'])->toBeFalse();
|
||||
expect($hasResult['key2'])->toBeFalse();
|
||||
});
|
||||
|
||||
test('set with ttl parameter still stores value', function () {
|
||||
@@ -78,14 +85,14 @@ test('set with ttl parameter still stores value', function () {
|
||||
$value = 'test-value';
|
||||
$ttl = Duration::fromHours(1);
|
||||
|
||||
$result = $this->cache->set($key, $value, $ttl);
|
||||
$result = $this->cache->set(CacheItem::forSet($key, $value, $ttl));
|
||||
|
||||
expect($result)->toBeTrue();
|
||||
|
||||
$item = $this->cache->get($key);
|
||||
$cacheResult = $this->cache->get($key);
|
||||
|
||||
expect($item->isHit)->toBeTrue()
|
||||
->and($item->value)->toBe($value);
|
||||
expect($cacheResult->isHit)->toBeTrue()
|
||||
->and($cacheResult->value)->toBe($value);
|
||||
});
|
||||
|
||||
test('multiple keys can be stored independently', function () {
|
||||
@@ -93,9 +100,9 @@ test('multiple keys can be stored independently', function () {
|
||||
$key2 = CacheKey::fromString('key2');
|
||||
$key3 = CacheKey::fromString('key3');
|
||||
|
||||
$this->cache->set($key1, 'value1');
|
||||
$this->cache->set($key2, 'value2');
|
||||
$this->cache->set($key3, 'value3');
|
||||
$this->cache->set(CacheItem::forSet($key1, 'value1'));
|
||||
$this->cache->set(CacheItem::forSet($key2, 'value2'));
|
||||
$this->cache->set(CacheItem::forSet($key3, 'value3'));
|
||||
|
||||
expect($this->cache->get($key1)->value)->toBe('value1')
|
||||
->and($this->cache->get($key2)->value)->toBe('value2')
|
||||
@@ -105,9 +112,9 @@ test('multiple keys can be stored independently', function () {
|
||||
test('overwriting existing key updates value', function () {
|
||||
$key = CacheKey::fromString('test-key');
|
||||
|
||||
$this->cache->set($key, 'original-value');
|
||||
$this->cache->set(CacheItem::forSet($key, 'original-value'));
|
||||
expect($this->cache->get($key)->value)->toBe('original-value');
|
||||
|
||||
$this->cache->set($key, 'updated-value');
|
||||
$this->cache->set(CacheItem::forSet($key, 'updated-value'));
|
||||
expect($this->cache->get($key)->value)->toBe('updated-value');
|
||||
});
|
||||
|
||||
@@ -13,7 +13,6 @@ use App\Framework\DI\Container;
|
||||
use App\Framework\Discovery\Results\AttributeRegistry;
|
||||
use App\Framework\Discovery\Results\DiscoveryRegistry;
|
||||
use App\Framework\Discovery\Results\InterfaceRegistry;
|
||||
use App\Framework\Discovery\Results\RouteRegistry;
|
||||
use App\Framework\Discovery\Results\TemplateRegistry;
|
||||
use App\Framework\Discovery\ValueObjects\InterfaceMapping;
|
||||
use App\Framework\Filesystem\ValueObjects\FilePath;
|
||||
@@ -38,7 +37,6 @@ final class MigrationLoaderTest extends TestCase
|
||||
$discoveryRegistry = new DiscoveryRegistry(
|
||||
new AttributeRegistry(),
|
||||
$interfaceRegistry,
|
||||
new RouteRegistry(),
|
||||
new TemplateRegistry()
|
||||
);
|
||||
|
||||
@@ -85,7 +83,6 @@ final class MigrationLoaderTest extends TestCase
|
||||
$discoveryRegistry = new DiscoveryRegistry(
|
||||
new AttributeRegistry(),
|
||||
$interfaceRegistry,
|
||||
new RouteRegistry(),
|
||||
new TemplateRegistry()
|
||||
);
|
||||
|
||||
@@ -119,7 +116,6 @@ final class MigrationLoaderTest extends TestCase
|
||||
$discoveryRegistry = new DiscoveryRegistry(
|
||||
new AttributeRegistry(),
|
||||
$interfaceRegistry,
|
||||
new RouteRegistry(),
|
||||
new TemplateRegistry()
|
||||
);
|
||||
|
||||
@@ -149,7 +145,6 @@ final class MigrationLoaderTest extends TestCase
|
||||
$discoveryRegistry = new DiscoveryRegistry(
|
||||
new AttributeRegistry(),
|
||||
$interfaceRegistry,
|
||||
new RouteRegistry(),
|
||||
new TemplateRegistry()
|
||||
);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Framework\DateTime\FrozenClock;
|
||||
use App\Framework\Http\Cookies\Cookie;
|
||||
use App\Framework\Http\Cookies\Cookies;
|
||||
use App\Framework\Http\HttpRequest;
|
||||
use App\Framework\Http\Request;
|
||||
use App\Framework\Http\Response;
|
||||
use App\Framework\Http\ResponseManipulator;
|
||||
use App\Framework\Http\Session\InMemorySessionStorage;
|
||||
@@ -63,9 +64,9 @@ describe('SessionManager Basic Operations', function () {
|
||||
$this->storage->write($sessionId, $testData);
|
||||
|
||||
// Request mit Session-Cookie erstellen
|
||||
$cookies = new Cookies([
|
||||
new Cookie('ms_context', $sessionId->toString()),
|
||||
]);
|
||||
$cookies = new Cookies(
|
||||
new Cookie('ms_context', $sessionId->toString())
|
||||
);
|
||||
|
||||
$request = new Request(
|
||||
method: 'GET',
|
||||
@@ -86,9 +87,9 @@ describe('SessionManager Basic Operations', function () {
|
||||
// Session-ID existiert, aber keine Daten im Storage
|
||||
$sessionId = SessionId::fromString('nonexistentsessionid1234567890abc');
|
||||
|
||||
$cookies = new Cookies([
|
||||
new Cookie('ms_context', $sessionId->toString()),
|
||||
]);
|
||||
$cookies = new Cookies(
|
||||
new Cookie('ms_context', $sessionId->toString())
|
||||
);
|
||||
|
||||
$request = new Request(
|
||||
method: 'GET',
|
||||
@@ -138,9 +139,9 @@ describe('SessionManager Session Persistence', function () {
|
||||
$sessionId = $session1->id->toString();
|
||||
|
||||
// Zweite Request: Session mit Cookie laden
|
||||
$cookies = new Cookies([
|
||||
new Cookie('ms_context', $sessionId),
|
||||
]);
|
||||
$cookies = new Cookies(
|
||||
new Cookie('ms_context', $sessionId)
|
||||
);
|
||||
|
||||
$request2 = new Request(
|
||||
method: 'GET',
|
||||
@@ -185,9 +186,9 @@ describe('SessionManager Session Persistence', function () {
|
||||
$this->sessionManager->saveSession($session, $response);
|
||||
|
||||
// Session erneut laden
|
||||
$cookies = new Cookies([
|
||||
new Cookie('ms_context', $session->id->toString()),
|
||||
]);
|
||||
$cookies = new Cookies(
|
||||
new Cookie('ms_context', $session->id->toString())
|
||||
);
|
||||
|
||||
$request = new Request(
|
||||
method: 'GET',
|
||||
@@ -316,9 +317,9 @@ describe('SessionManager Configuration', function () {
|
||||
|
||||
describe('SessionManager Error Handling', function () {
|
||||
test('handles invalid session ID gracefully', function () {
|
||||
$cookies = new Cookies([
|
||||
new Cookie('ms_context', 'invalid-session-id-format'),
|
||||
]);
|
||||
$cookies = new Cookies(
|
||||
new Cookie('ms_context', 'invalid-session-id-format')
|
||||
);
|
||||
|
||||
$request = new Request(
|
||||
method: 'GET',
|
||||
@@ -368,9 +369,9 @@ describe('SessionManager Error Handling', function () {
|
||||
);
|
||||
|
||||
$sessionId = SessionId::fromString('existingsessionid1234567890abcdef');
|
||||
$cookies = new Cookies([
|
||||
new Cookie('ms_context', $sessionId->toString()),
|
||||
]);
|
||||
$cookies = new Cookies(
|
||||
new Cookie('ms_context', $sessionId->toString())
|
||||
);
|
||||
|
||||
$request = new Request(
|
||||
method: 'GET',
|
||||
|
||||
@@ -7,16 +7,44 @@ use App\Framework\Queue\InMemoryQueue;
|
||||
use App\Framework\Queue\ValueObjects\JobPayload;
|
||||
use App\Framework\Queue\ValueObjects\QueuePriority;
|
||||
|
||||
// Test job classes
|
||||
class SimpleTestJob
|
||||
{
|
||||
public function handle(): string
|
||||
{
|
||||
return 'test job executed';
|
||||
}
|
||||
}
|
||||
|
||||
class CounterTestJob
|
||||
{
|
||||
public function __construct(public int $id)
|
||||
{
|
||||
}
|
||||
|
||||
public function handle(): string
|
||||
{
|
||||
return "job {$this->id} executed";
|
||||
}
|
||||
}
|
||||
|
||||
class PriorityTestJob
|
||||
{
|
||||
public function __construct(public string $priority)
|
||||
{
|
||||
}
|
||||
|
||||
public function handle(): string
|
||||
{
|
||||
return "job with {$this->priority} priority executed";
|
||||
}
|
||||
}
|
||||
|
||||
describe('Queue Interface Basic Operations', function () {
|
||||
|
||||
beforeEach(function () {
|
||||
$this->queue = new InMemoryQueue();
|
||||
$this->testJob = new class () {
|
||||
public function handle(): string
|
||||
{
|
||||
return 'test job executed';
|
||||
}
|
||||
};
|
||||
$this->testJob = new SimpleTestJob();
|
||||
});
|
||||
|
||||
describe('push() operation', function () {
|
||||
@@ -82,12 +110,8 @@ describe('Queue Interface Basic Operations', function () {
|
||||
});
|
||||
|
||||
it('processes FIFO for same priority jobs', function () {
|
||||
$job1 = new class () {
|
||||
public $id = 1;
|
||||
};
|
||||
$job2 = new class () {
|
||||
public $id = 2;
|
||||
};
|
||||
$job1 = (object)['id' => 1];
|
||||
$job2 = (object)['id' => 2];
|
||||
|
||||
$payload1 = JobPayload::create($job1, QueuePriority::normal());
|
||||
$payload2 = JobPayload::create($job2, QueuePriority::normal());
|
||||
@@ -218,7 +242,7 @@ describe('Queue Interface Basic Operations', function () {
|
||||
$this->queue->pop();
|
||||
$updatedStats = $this->queue->getStats();
|
||||
expect($updatedStats['size'])->toBe(1);
|
||||
expect($updatedStats['priority_breakdown']['critical'])->toBe(0);
|
||||
expect($updatedStats['priority_breakdown']['critical'] ?? 0)->toBe(0);
|
||||
expect($updatedStats['priority_breakdown']['normal'])->toBe(1);
|
||||
});
|
||||
});
|
||||
@@ -234,21 +258,11 @@ describe('Queue Priority Processing', function () {
|
||||
$jobs = [];
|
||||
|
||||
// Create jobs with different priorities
|
||||
$jobs['low'] = JobPayload::create(new class () {
|
||||
public $type = 'low';
|
||||
}, QueuePriority::low());
|
||||
$jobs['deferred'] = JobPayload::create(new class () {
|
||||
public $type = 'deferred';
|
||||
}, QueuePriority::deferred());
|
||||
$jobs['normal'] = JobPayload::create(new class () {
|
||||
public $type = 'normal';
|
||||
}, QueuePriority::normal());
|
||||
$jobs['high'] = JobPayload::create(new class () {
|
||||
public $type = 'high';
|
||||
}, QueuePriority::high());
|
||||
$jobs['critical'] = JobPayload::create(new class () {
|
||||
public $type = 'critical';
|
||||
}, QueuePriority::critical());
|
||||
$jobs['low'] = JobPayload::create((object)['type' => 'low'], QueuePriority::low());
|
||||
$jobs['deferred'] = JobPayload::create((object)['type' => 'deferred'], QueuePriority::deferred());
|
||||
$jobs['normal'] = JobPayload::create((object)['type' => 'normal'], QueuePriority::normal());
|
||||
$jobs['high'] = JobPayload::create((object)['type' => 'high'], QueuePriority::high());
|
||||
$jobs['critical'] = JobPayload::create((object)['type' => 'critical'], QueuePriority::critical());
|
||||
|
||||
// Push in random order
|
||||
$this->queue->push($jobs['normal']);
|
||||
@@ -267,15 +281,9 @@ describe('Queue Priority Processing', function () {
|
||||
});
|
||||
|
||||
it('handles custom priority values correctly', function () {
|
||||
$customHigh = JobPayload::create(new class () {
|
||||
public $id = 'custom_high';
|
||||
}, new QueuePriority(500));
|
||||
$customLow = JobPayload::create(new class () {
|
||||
public $id = 'custom_low';
|
||||
}, new QueuePriority(-50));
|
||||
$standardHigh = JobPayload::create(new class () {
|
||||
public $id = 'standard_high';
|
||||
}, QueuePriority::high());
|
||||
$customHigh = JobPayload::create((object)['id' => 'custom_high'], new QueuePriority(500));
|
||||
$customLow = JobPayload::create((object)['id' => 'custom_low'], new QueuePriority(-50));
|
||||
$standardHigh = JobPayload::create((object)['id' => 'standard_high'], QueuePriority::high());
|
||||
|
||||
$this->queue->push($customLow);
|
||||
$this->queue->push($standardHigh);
|
||||
@@ -309,9 +317,7 @@ describe('Queue Edge Cases', function () {
|
||||
});
|
||||
|
||||
it('maintains integrity after mixed operations', function () {
|
||||
$job = new class () {
|
||||
public $data = 'test';
|
||||
};
|
||||
$job = (object)['data' => 'test'];
|
||||
|
||||
// Complex sequence of operations
|
||||
$this->queue->push(JobPayload::create($job));
|
||||
@@ -338,12 +344,8 @@ describe('Queue Edge Cases', function () {
|
||||
|
||||
// Add 1000 jobs
|
||||
for ($i = 0; $i < 1000; $i++) {
|
||||
$job = new class () {
|
||||
public function __construct(public int $id)
|
||||
{
|
||||
}
|
||||
};
|
||||
$payload = JobPayload::create(new $job($i), QueuePriority::normal());
|
||||
$job = new CounterTestJob($i);
|
||||
$payload = JobPayload::create($job, QueuePriority::normal());
|
||||
$this->queue->push($payload);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user