Encapsulate session handling from protocol to new SessionManager (#247)

This commit is contained in:
Christopher Hertel 2026-03-10 18:09:15 +01:00 • committed by GitHub
commit ae320646bf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 444 additions and 200 deletions

View file

@ -24,9 +24,8 @@ use Mcp\Schema\Request\CallToolRequest;
use Mcp\Server\Handler\Notification\NotificationHandlerInterface;
use Mcp\Server\Handler\Request\RequestHandlerInterface;
use Mcp\Server\Protocol;
use Mcp\Server\Session\SessionFactoryInterface;
use Mcp\Server\Session\SessionInterface;
use Mcp\Server\Session\SessionStoreInterface;
use Mcp\Server\Session\SessionManagerInterface;
use Mcp\Server\Transport\TransportInterface;
use PHPUnit\Framework\Attributes\TestDox;
use PHPUnit\Framework\MockObject\MockObject;
@ -36,15 +35,13 @@ use Symfony\Component\Uid\Uuid;
final class ProtocolTest extends TestCase
{
private MockObject&SessionFactoryInterface $sessionFactory;
private MockObject&SessionStoreInterface $sessionStore;
private MockObject&SessionManagerInterface $sessionManager;
/** @var MockObject&TransportInterface<mixed> */
private MockObject&TransportInterface $transport;
protected function setUp(): void
{
$this->sessionFactory = $this->createMock(SessionFactoryInterface::class);
$this->sessionStore = $this->createMock(SessionStoreInterface::class);
$this->sessionManager = $this->createMock(SessionManagerInterface::class);
$this->transport = $this->createMock(TransportInterface::class);
}
@ -65,15 +62,14 @@ final class ProtocolTest extends TestCase
$session = $this->createMock(SessionInterface::class);
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
$protocol = new Protocol(
requestHandlers: [],
notificationHandlers: [$handlerA, $handlerB, $handlerC],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
);
$sessionId = Uuid::v4();
@ -101,8 +97,8 @@ final class ProtocolTest extends TestCase
$session = $this->createMock(SessionInterface::class);
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
$session->method('getId')->willReturn(Uuid::v4());
// Configure session mock for queue operations
@ -130,8 +126,7 @@ final class ProtocolTest extends TestCase
requestHandlers: [$handlerA, $handlerB, $handlerC],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
);
$sessionId = Uuid::v4();
@ -168,8 +163,7 @@ final class ProtocolTest extends TestCase
requestHandlers: [],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
);
$sessionId = Uuid::v4();
@ -199,8 +193,7 @@ final class ProtocolTest extends TestCase
requestHandlers: [],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
);
$protocol->processInput(
@ -231,8 +224,7 @@ final class ProtocolTest extends TestCase
requestHandlers: [],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
);
$protocol->processInput(
@ -245,7 +237,7 @@ final class ProtocolTest extends TestCase
#[TestDox('Non-existent session ID returns error')]
public function testNonExistentSessionIdReturnsError(): void
{
$this->sessionStore->method('exists')->willReturn(false);
$this->sessionManager->method('exists')->willReturn(false);
$this->transport->expects($this->once())
->method('send')
@ -265,8 +257,7 @@ final class ProtocolTest extends TestCase
requestHandlers: [],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
);
$sessionId = Uuid::v4();
@ -296,8 +287,7 @@ final class ProtocolTest extends TestCase
requestHandlers: [],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
);
$protocol->processInput(
@ -312,8 +302,8 @@ final class ProtocolTest extends TestCase
{
$session = $this->createMock(SessionInterface::class);
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
// Configure session mock for queue operations
$queue = [];
@ -340,8 +330,7 @@ final class ProtocolTest extends TestCase
requestHandlers: [],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
);
$sessionId = Uuid::v4();
@ -365,8 +354,8 @@ final class ProtocolTest extends TestCase
{
$session = $this->createMock(SessionInterface::class);
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
// Configure session mock for queue operations
$queue = [];
@ -393,8 +382,7 @@ final class ProtocolTest extends TestCase
requestHandlers: [],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
);
$sessionId = Uuid::v4();
@ -423,8 +411,8 @@ final class ProtocolTest extends TestCase
$session = $this->createMock(SessionInterface::class);
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
// Configure session mock for queue operations
$queue = [];
@ -451,8 +439,7 @@ final class ProtocolTest extends TestCase
requestHandlers: [$handler],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
);
$sessionId = Uuid::v4();
@ -481,8 +468,8 @@ final class ProtocolTest extends TestCase
$session = $this->createMock(SessionInterface::class);
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
// Configure session mock for queue operations
$queue = [];
@ -509,8 +496,7 @@ final class ProtocolTest extends TestCase
requestHandlers: [$handler],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
);
$sessionId = Uuid::v4();
@ -539,15 +525,14 @@ final class ProtocolTest extends TestCase
$session = $this->createMock(SessionInterface::class);
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
$protocol = new Protocol(
requestHandlers: [],
notificationHandlers: [$handler],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
);
$sessionId = Uuid::v4();
@ -571,8 +556,8 @@ final class ProtocolTest extends TestCase
$session = $this->createMock(SessionInterface::class);
$session->method('getId')->willReturn($sessionId);
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
// Configure session mock for queue operations
$queue = [];
@ -599,8 +584,7 @@ final class ProtocolTest extends TestCase
requestHandlers: [$handler],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
);
$protocol->processInput(
@ -650,8 +634,8 @@ final class ProtocolTest extends TestCase
}
});
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
// The protocol now queues responses instead of sending them directly
$session->expects($this->exactly(2))
@ -661,8 +645,7 @@ final class ProtocolTest extends TestCase
requestHandlers: [$handlerA],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
);
$sessionId = Uuid::v4();
@ -687,8 +670,8 @@ final class ProtocolTest extends TestCase
{
$session = $this->createMock(SessionInterface::class);
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
$session->expects($this->once())->method('save');
@ -696,8 +679,7 @@ final class ProtocolTest extends TestCase
requestHandlers: [],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
);
$sessionId = Uuid::v4();
@ -713,7 +695,7 @@ final class ProtocolTest extends TestCase
{
$sessionId = Uuid::v4();
$this->sessionStore->expects($this->once())
$this->sessionManager->expects($this->once())
->method('destroy')
->with($sessionId);
@ -721,8 +703,7 @@ final class ProtocolTest extends TestCase
requestHandlers: [],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
);
$protocol->destroySession($sessionId);
@ -750,15 +731,14 @@ final class ProtocolTest extends TestCase
$session->method('getId')->willReturn(Uuid::v4());
$session->method('get')->willReturn([]);
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
$protocol = new Protocol(
requestHandlers: [$handler],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
eventDispatcher: $eventDispatcher,
);
@ -820,15 +800,14 @@ final class ProtocolTest extends TestCase
$session->method('getId')->willReturn(Uuid::v4());
$session->method('get')->willReturn([]);
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
$protocol = new Protocol(
requestHandlers: [$handler],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
eventDispatcher: $eventDispatcher,
);
@ -857,15 +836,14 @@ final class ProtocolTest extends TestCase
$session->method('getId')->willReturn(Uuid::v4());
$session->method('get')->willReturn([]);
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
$protocol = new Protocol(
requestHandlers: [$handler],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
eventDispatcher: null,
);
@ -902,15 +880,14 @@ final class ProtocolTest extends TestCase
$session->method('getId')->willReturn(Uuid::v4());
$session->method('get')->willReturn([]);
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
$protocol = new Protocol(
requestHandlers: [$handler],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
eventDispatcher: $eventDispatcher,
);
@ -969,15 +946,14 @@ final class ProtocolTest extends TestCase
}
});
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
$protocol = new Protocol(
requestHandlers: [$handler],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
eventDispatcher: $eventDispatcher,
);
@ -1021,15 +997,14 @@ final class ProtocolTest extends TestCase
$session->method('getId')->willReturn(Uuid::v4());
$session->method('get')->willReturn([]);
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
$protocol = new Protocol(
requestHandlers: [$handler],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
eventDispatcher: $eventDispatcher,
);
@ -1074,15 +1049,14 @@ final class ProtocolTest extends TestCase
$session->method('getId')->willReturn(Uuid::v4());
$session->method('get')->willReturn([]);
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
$protocol = new Protocol(
requestHandlers: [$handler],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
eventDispatcher: $eventDispatcher,
);
@ -1126,15 +1100,14 @@ final class ProtocolTest extends TestCase
$session->method('getId')->willReturn(Uuid::v4());
$session->method('get')->willReturn([]);
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
$protocol = new Protocol(
requestHandlers: [$handler],
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
eventDispatcher: $eventDispatcher,
);
@ -1176,15 +1149,14 @@ final class ProtocolTest extends TestCase
$session->expects($this->once())->method('save');
$session->expects($this->atLeastOnce())->method('set');
$this->sessionFactory->method('create')->willReturn($session); // create() for initialize
$this->sessionStore->method('exists')->willReturn(false); // No existing session
$this->sessionManager->method('create')->willReturn($session); // create() for initialize
$this->sessionManager->method('exists')->willReturn(false); // No existing session
$protocol = new Protocol(
requestHandlers: [], // No handlers
notificationHandlers: [],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
eventDispatcher: $eventDispatcher,
);
@ -1227,15 +1199,14 @@ final class ProtocolTest extends TestCase
$session = $this->createMock(SessionInterface::class);
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
$protocol = new Protocol(
requestHandlers: [],
notificationHandlers: [$handler],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
eventDispatcher: $eventDispatcher,
);
@ -1289,15 +1260,14 @@ final class ProtocolTest extends TestCase
$session = $this->createMock(SessionInterface::class);
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
$protocol = new Protocol(
requestHandlers: [],
notificationHandlers: [$handler],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
eventDispatcher: $eventDispatcher,
);
@ -1324,15 +1294,14 @@ final class ProtocolTest extends TestCase
$session = $this->createMock(SessionInterface::class);
$this->sessionFactory->method('createWithId')->willReturn($session);
$this->sessionStore->method('exists')->willReturn(true);
$this->sessionManager->method('createWithId')->willReturn($session);
$this->sessionManager->method('exists')->willReturn(true);
$protocol = new Protocol(
requestHandlers: [],
notificationHandlers: [$handler],
messageFactory: MessageFactory::make(),
sessionFactory: $this->sessionFactory,
sessionStore: $this->sessionStore,
sessionManager: $this->sessionManager,
eventDispatcher: null,
);

View file

@ -14,9 +14,264 @@ namespace Mcp\Tests\Unit\Server\Session;
use Mcp\Server\Session\InMemorySessionStore;
use Mcp\Server\Session\Session;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Uid\UuidV4;
class SessionTest extends TestCase
{
private InMemorySessionStore $store;
private Session $session;
protected function setUp(): void
{
$this->store = new InMemorySessionStore();
$this->session = new Session($this->store);
}
public function testGetIdReturnsSessionId(): void
{
$id = new UuidV4();
$session = new Session($this->store, $id);
$this->assertSame($id, $session->getId());
}
public function testSetAndGetSimpleKey(): void
{
$this->session->set('foo', 'bar');
$this->assertSame('bar', $this->session->get('foo'));
}
public function testGetReturnsDefaultWhenKeyDoesNotExist(): void
{
$this->assertNull($this->session->get('nonexistent'));
$this->assertSame('default', $this->session->get('nonexistent', 'default'));
}
public function testSetAndGetNestedKey(): void
{
$this->session->set('user.name', 'John');
$this->session->set('user.email', 'john@example.com');
$this->session->set('user.address.city', 'New York');
$this->assertSame('John', $this->session->get('user.name'));
$this->assertSame('john@example.com', $this->session->get('user.email'));
$this->assertSame('New York', $this->session->get('user.address.city'));
$this->assertSame(['city' => 'New York'], $this->session->get('user.address'));
}
public function testSetDoesNotOverwriteWhenOverwriteIsFalse(): void
{
$this->session->set('key', 'original');
$this->session->set('key', 'new', overwrite: false);
$this->assertSame('original', $this->session->get('key'));
}
public function testSetOverwritesWhenOverwriteIsTrue(): void
{
$this->session->set('key', 'original');
$this->session->set('key', 'new');
$this->assertSame('new', $this->session->get('key'));
}
public function testHasReturnsTrueForExistingKey(): void
{
$this->session->set('foo', 'bar');
$this->assertTrue($this->session->has('foo'));
}
public function testHasReturnsFalseForNonExistingKey(): void
{
$this->assertFalse($this->session->has('nonexistent'));
}
public function testHasWorksWithNestedKeys(): void
{
$this->session->set('user.name', 'John');
$this->assertTrue($this->session->has('user'));
$this->assertTrue($this->session->has('user.name'));
$this->assertFalse($this->session->has('user.email'));
$this->assertFalse($this->session->has('user.name.first'));
}
public function testForgetRemovesSimpleKey(): void
{
$this->session->set('foo', 'bar');
$this->session->forget('foo');
$this->assertFalse($this->session->has('foo'));
$this->assertNull($this->session->get('foo'));
}
public function testForgetRemovesNestedKey(): void
{
$this->session->set('user.name', 'John');
$this->session->set('user.email', 'john@example.com');
$this->session->forget('user.name');
$this->assertFalse($this->session->has('user.name'));
$this->assertTrue($this->session->has('user.email'));
}
public function testClearRemovesAllData(): void
{
$this->session->set('foo', 'bar');
$this->session->set('baz', 'qux');
$this->session->clear();
$this->assertSame([], $this->session->all());
$this->assertFalse($this->session->has('foo'));
$this->assertFalse($this->session->has('baz'));
}
public function testPullReturnsValueAndRemovesKey(): void
{
$this->session->set('foo', 'bar');
$value = $this->session->pull('foo');
$this->assertSame('bar', $value);
$this->assertFalse($this->session->has('foo'));
}
public function testPullReturnsDefaultWhenKeyDoesNotExist(): void
{
$this->assertNull($this->session->pull('nonexistent'));
$this->assertSame('default', $this->session->pull('also_nonexistent', 'default'));
}
public function testAllReturnsAllData(): void
{
$this->session->set('foo', 'bar');
$this->session->set('user.name', 'John');
$all = $this->session->all();
$this->assertSame([
'foo' => 'bar',
'user' => ['name' => 'John'],
], $all);
}
public function testHydrateReplacesAllData(): void
{
$this->session->set('original', 'value');
$this->session->hydrate(['new' => 'data', 'nested' => ['key' => 'value']]);
$this->assertSame([
'new' => 'data',
'nested' => ['key' => 'value'],
], $this->session->all());
$this->assertFalse($this->session->has('original'));
}
public function testJsonSerializeReturnsAllData(): void
{
$this->session->set('foo', 'bar');
$this->session->set('user.name', 'John');
$serialized = $this->session->jsonSerialize();
$this->assertSame([
'foo' => 'bar',
'user' => ['name' => 'John'],
], $serialized);
}
public function testSavePersistsDataToStore(): void
{
$this->session->set('foo', 'bar');
$result = $this->session->save();
$this->assertTrue($result);
// Verify data was persisted by creating a new session with the same ID
$newSession = new Session($this->store, $this->session->getId());
$this->assertSame('bar', $newSession->get('foo'));
}
public function testSessionLoadsDataFromStoreOnConstruction(): void
{
// Set and save data in one session
$this->session->set('persisted', 'value');
$this->session->save();
$sessionId = $this->session->getId();
// Create a new session instance with the same ID
$newSession = new Session($this->store, $sessionId);
$this->assertSame('value', $newSession->get('persisted'));
}
public function testSetCreatesNestedStructure(): void
{
$this->session->set('a.b.c.d', 'value');
$this->assertSame('value', $this->session->get('a.b.c.d'));
$this->assertSame(['d' => 'value'], $this->session->get('a.b.c'));
$this->assertSame(['c' => ['d' => 'value']], $this->session->get('a.b'));
$this->assertSame(['b' => ['c' => ['d' => 'value']]], $this->session->get('a'));
}
public function testSetOverwritesNonArrayWithNestedStructure(): void
{
$this->session->set('key', 'string_value');
$this->session->set('key.nested', 'nested_value');
$this->assertSame('nested_value', $this->session->get('key.nested'));
$this->assertSame(['nested' => 'nested_value'], $this->session->get('key'));
}
public function testGetReturnsArrayForIntermediateKey(): void
{
$this->session->set('user.profile.name', 'John');
$this->session->set('user.profile.age', 30);
$profile = $this->session->get('user.profile');
$this->assertSame(['name' => 'John', 'age' => 30], $profile);
}
public function testForgetDoesNotThrowWhenKeyDoesNotExist(): void
{
$this->session->forget('nonexistent');
$this->session->forget('nested.nonexistent');
$this->assertFalse($this->session->has('nonexistent'));
}
public function testSessionCanStoreVariousDataTypes(): void
{
$this->session->set('string', 'value');
$this->session->set('int', 42);
$this->session->set('float', 3.14);
$this->session->set('bool', true);
$this->session->set('null', null);
$this->session->set('array', ['a', 'b', 'c']);
$this->session->set('assoc', ['key' => 'value']);
$this->assertSame('value', $this->session->get('string'));
$this->assertSame(42, $this->session->get('int'));
$this->assertSame(3.14, $this->session->get('float'));
$this->assertTrue($this->session->get('bool'));
$this->assertNull($this->session->get('null'));
$this->assertSame(['a', 'b', 'c'], $this->session->get('array'));
$this->assertSame(['key' => 'value'], $this->session->get('assoc'));
}
public function testSessionGeneratesUniqueIdIfNotProvided(): void
{
$session1 = new Session($this->store);
$session2 = new Session($this->store);
$this->assertNotEquals($session1->getId()->toRfc4122(), $session2->getId()->toRfc4122());
}
public function testAll()
{
$store = $this->getMockBuilder(InMemorySessionStore::class)