From 7c8cd04d21cc24f3e04168b8093ba8a3660b0848 Mon Sep 17 00:00:00 2001 From: JanHuang <384099566@qq.com> Date: Tue, 27 Oct 2026 18:14:50 +0800 Subject: [PATCH] =?UTF-8?q?test(session):=20=E8=A1=A5=E5=85=85=20Redis=20S?= =?UTF-8?q?ession=20Handler=20=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 覆盖非字符串/非数组 JSON、Unicode、最大长度边界、 JSON 编码失败、setex 失败、destroy/exists 缺失以及 gc 参数。 --- tests/session/RedisSessionHandlerTest.php | 121 ++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/tests/session/RedisSessionHandlerTest.php b/tests/session/RedisSessionHandlerTest.php index 52101ee..78640fd 100644 --- a/tests/session/RedisSessionHandlerTest.php +++ b/tests/session/RedisSessionHandlerTest.php @@ -6,6 +6,7 @@ use FastD\Http\Session\Handler\RedisSessionHandler; use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Redis; @@ -85,4 +86,124 @@ public function testGcIsNoopBecauseRedisExpiresKeys(): void { $this->assertSame(0, (new RedisSessionHandler($this->createMock(Redis::class)))->gc()); } + + public function testReadReturnsEmptyArrayForNonStringRedisValues(): void + { + $redis = $this->createMock(Redis::class); + $redis->expects($this->exactly(3)) + ->method('get') + ->willReturnOnConsecutiveCalls(false, null, 123); + + $handler = new RedisSessionHandler($redis); + + $this->assertSame([], $handler->read('a')); + $this->assertSame([], $handler->read('b')); + $this->assertSame([], $handler->read('c')); + } + + #[DataProvider('nonArrayJsonProvider')] + public function testReadReturnsEmptyArrayForScalarJson(string $payload): void + { + $redis = $this->createMock(Redis::class); + $redis->method('get')->willReturn($payload); + + $this->assertSame([], (new RedisSessionHandler($redis))->read('scalar')); + } + + public static function nonArrayJsonProvider(): array + { + return [ + 'null' => ['null'], + 'integer' => ['123'], + 'string' => ['"value"'], + 'boolean' => ['true'], + ]; + } + + public function testReadUsesCustomPrefix(): void + { + $redis = $this->createMock(Redis::class); + $redis->expects($this->once()) + ->method('get') + ->with('custom:abc') + ->willReturn(json_encode(['ok' => true])); + + $this->assertSame(['ok' => true], (new RedisSessionHandler($redis, 60, 'custom:'))->read('abc')); + } + + public function testWriteEncodesUnicodeWithoutEscaping(): void + { + $data = ['name' => '简']; + $json = json_encode($data, JSON_UNESCAPED_UNICODE); + + $redis = $this->createMock(Redis::class); + $redis->expects($this->once()) + ->method('setex') + ->with('fastd:session:abc', 60, $json) + ->willReturn(true); + + $this->assertTrue((new RedisSessionHandler($redis, 60))->write('abc', $data)); + } + + public function testWriteAllowsPayloadAtExactMaxDataSize(): void + { + $data = ['blob' => str_repeat('x', 32)]; + $json = json_encode($data, JSON_UNESCAPED_UNICODE); + + $redis = $this->createMock(Redis::class); + $redis->expects($this->once()) + ->method('setex') + ->with('fastd:session:abc', 60, $json) + ->willReturn(true); + + $handler = new RedisSessionHandler($redis, 60, 'fastd:session:', strlen($json)); + + $this->assertTrue($handler->write('abc', $data)); + } + + public function testWriteReturnsFalseWhenJsonEncodingFails(): void + { + $redis = $this->createMock(Redis::class); + $redis->expects($this->never())->method('setex'); + + $handler = new RedisSessionHandler($redis, 60); + + $this->assertFalse($handler->write('abc', ['invalid' => "\xB1\x31"])); + } + + public function testWriteReturnsFalseWhenSetexFails(): void + { + $redis = $this->createMock(Redis::class); + $redis->expects($this->once()) + ->method('setex') + ->willReturn(false); + + $this->assertFalse((new RedisSessionHandler($redis, 60))->write('abc', ['ok' => true])); + } + + public function testDestroyReturnsFalseWhenKeyDoesNotExist(): void + { + $redis = $this->createMock(Redis::class); + $redis->expects($this->once())->method('del')->with('fastd:session:missing')->willReturn(0); + + $this->assertFalse((new RedisSessionHandler($redis))->destroy('missing')); + } + + public function testExistsReturnsFalseWhenKeyDoesNotExist(): void + { + $redis = $this->createMock(Redis::class); + $redis->expects($this->once())->method('exists')->with('fastd:session:missing')->willReturn(0); + + $this->assertFalse((new RedisSessionHandler($redis))->exists('missing')); + } + + public function testGcAcceptsMaxLifetimeAndRemainsNoop(): void + { + $redis = $this->createMock(Redis::class); + $redis->expects($this->never())->method('get'); + $redis->expects($this->never())->method('setex'); + $redis->expects($this->never())->method('del'); + + $this->assertSame(0, (new RedisSessionHandler($redis))->gc(3600)); + } }