optimizations

This commit is contained in:
2026-03-28 19:15:39 +01:00
parent 0b25d9570a
commit cab4fbd83e
509 changed files with 1016804 additions and 1605 deletions

View File

@@ -13,6 +13,7 @@ use App\Events\ConversationUpdated;
use App\Events\MessageCreated;
use App\Events\MessageRead;
use App\Services\Messaging\MessagingPresenceService;
use Illuminate\Database\QueryException;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
@@ -177,6 +178,80 @@ test('sending a message dispatches realtime events and preserves client temp id'
Event::assertDispatched(ConversationUpdated::class);
});
test('retrying a send with the same client temp id reuses the existing message', function () {
Event::fake([MessageCreated::class]);
$userA = makeMessagingUser();
$userB = makeMessagingUser();
$conv = makeDirectConversation($userA, $userB);
$first = $this->actingAs($userA)->postJson("/api/messages/{$conv->id}", [
'body' => 'Retry safe hello',
'client_temp_id' => 'tmp_retry_safe_001',
]);
$second = $this->actingAs($userA)->postJson("/api/messages/{$conv->id}", [
'body' => 'Retry safe hello',
'client_temp_id' => 'tmp_retry_safe_001',
]);
$first->assertStatus(201);
$second->assertStatus(201);
expect(Message::query()->count())->toBe(1)
->and($second->json('id'))->toBe($first->json('id'))
->and($second->json('uuid'))->toBe($first->json('uuid'))
->and($second->json('client_temp_id'))->toBe('tmp_retry_safe_001');
Event::assertDispatchedTimes(MessageCreated::class, 1);
});
test('client temp id dedupe is scoped to sender', function () {
Event::fake([MessageCreated::class]);
$userA = makeMessagingUser();
$userB = makeMessagingUser();
$conv = makeDirectConversation($userA, $userB);
$first = $this->actingAs($userA)->postJson("/api/messages/{$conv->id}", [
'body' => 'Sender A',
'client_temp_id' => 'tmp_sender_scope_001',
]);
$second = $this->actingAs($userB)->postJson("/api/messages/{$conv->id}", [
'body' => 'Sender B',
'client_temp_id' => 'tmp_sender_scope_001',
]);
$first->assertStatus(201);
$second->assertStatus(201);
expect(Message::query()->count())->toBe(2)
->and($second->json('id'))->not->toBe($first->json('id'));
Event::assertDispatchedTimes(MessageCreated::class, 2);
});
test('database enforces sender scoped client temp id uniqueness', function () {
$userA = makeMessagingUser();
$userB = makeMessagingUser();
$conv = makeDirectConversation($userA, $userB);
Message::create([
'conversation_id' => $conv->id,
'sender_id' => $userA->id,
'body' => 'Stored once',
'client_temp_id' => 'tmp_db_guard_001',
]);
expect(fn () => Message::create([
'conversation_id' => $conv->id,
'sender_id' => $userA->id,
'body' => 'Stored twice',
'client_temp_id' => 'tmp_db_guard_001',
]))->toThrow(QueryException::class);
});
test('non participant cannot send a message', function () {
$userA = makeMessagingUser();
$userB = makeMessagingUser();
@@ -338,6 +413,9 @@ test('delta endpoint returns only messages after requested id in ascending order
$response = $this->actingAs($userA)->getJson("/api/messages/{$conv->id}/delta?after_message_id={$first->id}");
$response->assertStatus(200)
->assertJsonPath('conversation.id', $conv->id)
->assertJsonPath('conversation.latest_message.id', $third->id)
->assertJsonPath('summary.unread_total', 2)
->assertJsonPath('data.0.id', $second->id)
->assertJsonPath('data.1.id', $third->id);
});