tailly_back_v2/internal/http/graph/messages_resolvers_test.go
2025-08-18 14:17:14 +03:00

284 lines
7.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package graph
import (
"context"
"fmt"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"tailly_back_v2/proto"
)
const (
grpcAddress = "localhost:50052"
userIDKey = "userID"
)
func setupIntegrationTest(t *testing.T) *Resolver {
// Создаем соединение с gRPC сервером
conn, err := grpc.Dial(grpcAddress, grpc.WithTransportCredentials(insecure.NewCredentials()))
require.NoError(t, err, "failed to connect to gRPC server")
return &Resolver{
MessageClient: proto.NewMessageServiceClient(conn),
}
}
func TestIntegration_CreateAndSendMessages(t *testing.T) {
r := setupIntegrationTest(t)
ctx := context.Background()
// Тест создания чата
t.Run("CreateChat", func(t *testing.T) {
resolver := &mutationResolver{r}
chat, err := resolver.CreateChat(ctx, 1, 2)
require.NoError(t, err)
assert.NotZero(t, chat.ID)
assert.Equal(t, 1, chat.User1ID)
assert.Equal(t, 2, chat.User2ID)
})
// Тест отправки сообщений
t.Run("SendMessages", func(t *testing.T) {
resolver := &mutationResolver{r}
// Сначала создаем чат
chat, err := resolver.CreateChat(ctx, 1, 2)
require.NoError(t, err)
// Отправляем 5 сообщений
for i := 0; i < 5; i++ {
msg, err := resolver.SendMessage(
context.WithValue(ctx, userIDKey, 1), // Добавляем senderID в контекст
int(chat.ID),
"test message "+string(rune('A'+i)),
)
require.NoError(t, err)
assert.NotZero(t, msg.ID)
assert.Equal(t, "test message "+string(rune('A'+i)), msg.Content)
}
})
}
func TestIntegration_MessageStream(t *testing.T) {
r := setupIntegrationTest(t)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
// Используем существующих пользователей
const user1ID = 5
const user2ID = 12
// Создаем чат
mutation := &mutationResolver{r}
chat, err := mutation.CreateChat(ctx, user1ID, user2ID)
require.NoError(t, err, "Failed to create chat")
// Канал для синхронизации завершения теста
testDone := make(chan struct{})
defer close(testDone)
// Канал для получения ошибок из горутин
errChan := make(chan error, 1)
// Запускаем подписку на сообщения
subscription := &subscriptionResolver{r}
msgChan, err := subscription.MessageStream(ctx, user2ID)
require.NoError(t, err, "Failed to create message stream")
// Отправляем 5 сообщений
go func() {
defer func() {
if r := recover(); r != nil {
t.Logf("Recovered in sender goroutine: %v", r)
}
}()
for i := 0; i < 5; i++ {
select {
case <-testDone:
return
default:
_, err := mutation.SendMessage(
context.WithValue(ctx, userIDKey, user1ID),
int(chat.ID),
fmt.Sprintf("stream message %d", i+1),
)
if err != nil {
select {
case errChan <- fmt.Errorf("failed to send message: %w", err):
default:
}
return
}
time.Sleep(500 * time.Millisecond) // Увеличиваем задержку
}
}
}()
// Получаем сообщения из стрима
received := 0
var lastErr error
for {
select {
case err := <-errChan:
lastErr = err
break
case msg, ok := <-msgChan:
if !ok {
break
}
if msg == nil {
continue // Пропускаем nil-сообщения (heartbeats)
}
t.Logf("Received message %d: %s", received+1, msg.Content)
received++
if received >= 5 {
return // Успешно получили все сообщения
}
case <-ctx.Done():
lastErr = ctx.Err()
break
}
// Выходим из цикла если была ошибка или завершение
if lastErr != nil {
break
}
}
if received < 5 {
if lastErr != nil {
require.NoError(t, lastErr, "Didn't receive all messages")
} else {
t.Errorf("Expected 5 messages, received %d", received)
}
}
}
func TestIntegration_GetChatMessages(t *testing.T) {
r := setupIntegrationTest(t)
ctx := context.Background()
// Используем существующих пользователей
const user1ID = 5
const user2ID = 12
// Создаем чат
mutation := &mutationResolver{r}
chat, err := mutation.CreateChat(ctx, user1ID, user2ID)
require.NoError(t, err, "Failed to create chat")
// Отправляем ровно 5 сообщений
expectedContents := make([]string, 5)
for i := 0; i < 5; i++ {
content := fmt.Sprintf("test message %d", i+1)
_, err := mutation.SendMessage(
context.WithValue(ctx, userIDKey, user1ID),
int(chat.ID),
content,
)
require.NoError(t, err, "Failed to send message")
expectedContents[i] = content
}
// Даем время на обработку
time.Sleep(1 * time.Second)
// Проверяем получение сообщений
query := &queryResolver{r}
messages, err := query.GetChatMessages(ctx, int(chat.ID), 10, 0)
require.NoError(t, err, "Failed to get chat messages")
// Проверяем что получили хотя бы 5 сообщений
assert.GreaterOrEqual(t, len(messages), 5, "Expected at least 5 messages")
// Проверяем последние 5 сообщений
for i := 0; i < 5; i++ {
assert.Equal(t, expectedContents[4-i], messages[i].Content, "Message content mismatch")
}
}
func TestIntegration_GetUserChats(t *testing.T) {
r := setupIntegrationTest(t)
ctx := context.Background()
// Создаем несколько чатов
mutation := &mutationResolver{r}
_, err := mutation.CreateChat(ctx, 1, 2)
require.NoError(t, err)
_, err = mutation.CreateChat(ctx, 1, 3)
require.NoError(t, err)
// Проверяем получение чатов пользователя
query := &queryResolver{r}
chats, err := query.GetUserChats(ctx, 1)
require.NoError(t, err)
assert.GreaterOrEqual(t, len(chats), 2)
}
func TestIntegration_UpdateMessageStatus(t *testing.T) {
r := setupIntegrationTest(t)
ctx := context.Background()
// Используем существующих пользователей
const user1ID = 5
const user2ID = 12
// Создаем чат
mutation := &mutationResolver{r}
chat, err := mutation.CreateChat(ctx, user1ID, user2ID)
require.NoError(t, err, "Failed to create chat")
// Отправляем тестовое сообщение
msg, err := mutation.SendMessage(
context.WithValue(ctx, userIDKey, user1ID),
int(chat.ID),
"status test",
)
require.NoError(t, err, "Failed to send message")
// Даем время на обработку
time.Sleep(500 * time.Millisecond)
// Определяем поддерживаемые статусы из вашего сервера
// (должны соответствовать тому, что действительно принимает сервер)
validStatuses := []struct {
name string
status string
}{
{"SENT", "SENT"},
{"DELIVERED", "DELIVERED"},
{"READ", "READ"},
}
for _, ts := range validStatuses {
t.Run(fmt.Sprintf("Update to %s", ts.name), func(t *testing.T) {
// Преобразуем строковый статус в MessageStatus
var msgStatus MessageStatus
switch ts.status {
case "SENT":
msgStatus = MessageStatusSent
case "DELIVERED":
msgStatus = MessageStatusDelivered
case "READ":
msgStatus = MessageStatusRead
default:
t.Fatalf("Unsupported status: %s", ts.status)
}
updatedMsg, err := mutation.UpdateMessageStatus(ctx, msg.ID, msgStatus)
if err != nil {
t.Logf("If this fails, check your server's message status constraints")
}
require.NoError(t, err, "Failed to update message status")
assert.Equal(t, ts.status, updatedMsg.Status, "Status mismatch")
})
}
}