284 lines
7.8 KiB
Go
284 lines
7.8 KiB
Go
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")
|
||
})
|
||
}
|
||
}
|