新增聊天室发送图片功能
This commit is contained in:
@@ -5,20 +5,32 @@ namespace Tests\Feature;
|
||||
use App\Models\Room;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* 聊天室控制器功能测试
|
||||
* 覆盖进房、发言、图片消息与退房等关键聊天流程。
|
||||
*/
|
||||
class ChatControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
/**
|
||||
* 每个测试前清空 Redis,避免跨用例污染在线状态与消息缓存。
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
Redis::flushall();
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试用户可以正常进入聊天室页面。
|
||||
*/
|
||||
public function test_can_view_room()
|
||||
{
|
||||
$room = Room::create(['room_name' => 'testroom']);
|
||||
@@ -33,6 +45,9 @@ class ChatControllerTest extends TestCase
|
||||
$this->assertEquals(1, Redis::hexists("room:{$room->id}:users", $user->username));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试用户可以发送普通文本消息。
|
||||
*/
|
||||
public function test_can_send_message()
|
||||
{
|
||||
$room = Room::create(['room_name' => 'test_send']);
|
||||
@@ -67,9 +82,12 @@ class ChatControllerTest extends TestCase
|
||||
$this->assertTrue($found, 'Message not found in Redis');
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试文本内容为字符串 0 时仍可正常发送。
|
||||
*/
|
||||
public function test_can_send_zero_message_content(): void
|
||||
{
|
||||
$room = Room::create(['room_name' => 'test_send_zero']);
|
||||
$room = Room::create(['room_name' => 'send0']);
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user)->get(route('chat.room', $room->id));
|
||||
@@ -100,6 +118,90 @@ class ChatControllerTest extends TestCase
|
||||
$this->assertTrue($found, 'Zero message not found in Redis');
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试用户可以发送带缩略图的图片消息。
|
||||
*/
|
||||
public function test_can_send_image_message(): void
|
||||
{
|
||||
Storage::fake('public');
|
||||
|
||||
$room = Room::create(['room_name' => 'imgsend']);
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user)->get(route('chat.room', $room->id));
|
||||
|
||||
$response = $this->actingAs($user)->post(route('chat.send', $room->id), [
|
||||
'to_user' => '大家',
|
||||
'content' => '图片说明',
|
||||
'font_color' => '#000000',
|
||||
'action' => '',
|
||||
'image' => UploadedFile::fake()->image('chat-picture.png', 1280, 960),
|
||||
], [
|
||||
'Accept' => 'application/json',
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJson(['status' => 'success']);
|
||||
|
||||
$messages = Redis::lrange("room:{$room->id}:messages", 0, -1);
|
||||
$payload = collect($messages)
|
||||
->map(fn (string $item) => json_decode($item, true))
|
||||
->first(fn (array $item) => ($item['from_user'] ?? null) === $user->username && ($item['message_type'] ?? null) === 'image');
|
||||
|
||||
$this->assertNotNull($payload);
|
||||
$this->assertSame('image', $payload['message_type'] ?? null);
|
||||
$this->assertNotEmpty($payload['image_path'] ?? null);
|
||||
$this->assertNotEmpty($payload['image_thumb_path'] ?? null);
|
||||
$this->assertNotEmpty($payload['image_url'] ?? null);
|
||||
$this->assertNotEmpty($payload['image_thumb_url'] ?? null);
|
||||
Storage::disk('public')->assertExists($payload['image_path']);
|
||||
Storage::disk('public')->assertExists($payload['image_thumb_path']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试超过保留期的聊天图片会被命令清理并改成过期占位消息。
|
||||
*/
|
||||
public function test_purge_command_cleans_expired_chat_images(): void
|
||||
{
|
||||
Storage::fake('public');
|
||||
|
||||
Storage::disk('public')->put('chat-images/2026-04-08/sample_original.png', 'original');
|
||||
Storage::disk('public')->put('chat-images/2026-04-08/sample_thumb.png', 'thumb');
|
||||
|
||||
$message = \App\Models\Message::create([
|
||||
'room_id' => 1,
|
||||
'from_user' => 'tester',
|
||||
'to_user' => '大家',
|
||||
'content' => '历史图片',
|
||||
'is_secret' => false,
|
||||
'font_color' => '#000000',
|
||||
'action' => '',
|
||||
'message_type' => 'image',
|
||||
'image_path' => 'chat-images/2026-04-08/sample_original.png',
|
||||
'image_thumb_path' => 'chat-images/2026-04-08/sample_thumb.png',
|
||||
'image_original_name' => 'sample.png',
|
||||
'sent_at' => now()->subDays(4),
|
||||
]);
|
||||
|
||||
$this->artisan('messages:purge', [
|
||||
'--days' => 30,
|
||||
'--image-days' => 3,
|
||||
])->assertExitCode(0);
|
||||
|
||||
$message->refresh();
|
||||
|
||||
$this->assertSame('expired_image', $message->message_type);
|
||||
$this->assertNull($message->image_path);
|
||||
$this->assertNull($message->image_thumb_path);
|
||||
$this->assertNull($message->image_original_name);
|
||||
$this->assertStringContainsString('图片已过期', $message->content);
|
||||
Storage::disk('public')->assertMissing('chat-images/2026-04-08/sample_original.png');
|
||||
Storage::disk('public')->assertMissing('chat-images/2026-04-08/sample_thumb.png');
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试心跳接口可以正常返回成功响应。
|
||||
*/
|
||||
public function test_can_trigger_heartbeat()
|
||||
{
|
||||
$room = Room::create(['room_name' => 'test_hb']);
|
||||
@@ -114,6 +216,9 @@ class ChatControllerTest extends TestCase
|
||||
$this->assertGreaterThanOrEqual(0, $user->exp_num); // Might be 1 depending on sysparam
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试显式退房会清理 Redis 在线状态。
|
||||
*/
|
||||
public function test_can_leave_room()
|
||||
{
|
||||
$room = Room::create(['room_name' => 'test_leave']);
|
||||
@@ -132,9 +237,12 @@ class ChatControllerTest extends TestCase
|
||||
$this->assertEquals(0, Redis::hexists("room:{$room->id}:users", $user->username));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试签名退房链接同样可以正常清理在线状态。
|
||||
*/
|
||||
public function test_can_leave_room_through_signed_expired_route(): void
|
||||
{
|
||||
$room = Room::create(['room_name' => 'expired_leave_room']);
|
||||
$room = Room::create(['room_name' => 'leave2']);
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user)->get(route('chat.room', $room->id));
|
||||
@@ -156,7 +264,7 @@ class ChatControllerTest extends TestCase
|
||||
*/
|
||||
public function test_vip_user_join_message_uses_presence_theme_payload(): void
|
||||
{
|
||||
$room = Room::create(['room_name' => 'vip_theme_room']);
|
||||
$room = Room::create(['room_name' => 'viproom']);
|
||||
$vipLevel = \App\Models\VipLevel::factory()->create([
|
||||
'join_effect' => 'lightning',
|
||||
'join_banner_style' => 'storm',
|
||||
@@ -182,6 +290,9 @@ class ChatControllerTest extends TestCase
|
||||
$this->assertStringContainsString($user->username, $presenceMessage['presence_text']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试可以获取所有房间的在线人数状态。
|
||||
*/
|
||||
public function test_can_get_rooms_online_status()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
@@ -205,6 +316,9 @@ class ChatControllerTest extends TestCase
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试管理员可以设置房间公告。
|
||||
*/
|
||||
public function test_can_set_announcement()
|
||||
{
|
||||
$user = User::factory()->create(['user_level' => 100]); // superadmin
|
||||
@@ -220,6 +334,9 @@ class ChatControllerTest extends TestCase
|
||||
$this->assertStringContainsString('This is a new test announcement', $room->announcement);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试无权限用户不能设置房间公告。
|
||||
*/
|
||||
public function test_cannot_set_announcement_without_permission()
|
||||
{
|
||||
$user = User::factory()->create(['user_level' => 0]);
|
||||
|
||||
Reference in New Issue
Block a user