package main import ( "context" "github.com/jackc/pgx/v4/pgxpool" "github.com/stretchr/testify/assert" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "tailly_subscribers/proto" "testing" ) func setupTestDB(t *testing.T) *pgxpool.Pool { dbURL := "postgres://tailly_v2:i0Oq%2675LA%26M612ceuy@79.174.89.104:15452/tailly_v2" pool, err := pgxpool.Connect(context.Background(), dbURL) if err != nil { t.Fatalf("Failed to connect to database: %v", err) } // ОЧИСТКА ТЕСТОВЫХ ДАННЫХ ПЕРЕД ТЕСТАМИ _, err = pool.Exec(context.Background(), "DELETE FROM subscription_notifications") if err != nil { t.Fatalf("Failed to clean notifications: %v", err) } _, err = pool.Exec(context.Background(), "DELETE FROM subscriptions") if err != nil { t.Fatalf("Failed to clean subscriptions: %v", err) } return pool } func TestFollowUser(t *testing.T) { db := setupTestDB(t) server := NewServer(db) tests := []struct { name string req *proto.FollowRequest expectError bool errorCode codes.Code }{ { name: "Success - user 1 follows user 2", req: &proto.FollowRequest{FollowerId: 1, FollowingId: 2}, expectError: false, }, { name: "Success - user 2 follows user 3", req: &proto.FollowRequest{FollowerId: 2, FollowingId: 3}, expectError: false, }, { name: "Error - self follow", req: &proto.FollowRequest{FollowerId: 1, FollowingId: 1}, expectError: true, errorCode: codes.InvalidArgument, }, { name: "Error - non-existent user", // ИЗМЕНИЛОСЬ: теперь Internal error из-за foreign key req: &proto.FollowRequest{FollowerId: 1, FollowingId: 999}, expectError: true, errorCode: codes.Internal, // Foreign key violation }, { name: "Error - zero IDs", req: &proto.FollowRequest{FollowerId: 0, FollowingId: 0}, expectError: true, errorCode: codes.InvalidArgument, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() resp, err := server.FollowUser(ctx, tt.req) if tt.expectError { assert.Error(t, err) if st, ok := status.FromError(err); ok { assert.Equal(t, tt.errorCode, st.Code()) } } else { assert.NoError(t, err) assert.True(t, resp.Success) assert.Contains(t, resp.Message, "Successfully") } }) } } func TestUnfollowUser(t *testing.T) { db := setupTestDB(t) server := NewServer(db) // Сначала создаем подписки для тестов server.FollowUser(context.Background(), &proto.FollowRequest{FollowerId: 1, FollowingId: 2}) server.FollowUser(context.Background(), &proto.FollowRequest{FollowerId: 1, FollowingId: 3}) tests := []struct { name string req *proto.UnfollowRequest expectError bool errorCode codes.Code success bool }{ { name: "Success - user 1 unfollows user 2", req: &proto.UnfollowRequest{FollowerId: 1, FollowingId: 2}, expectError: false, success: true, }, { name: "Success - user 1 unfollows user 3", req: &proto.UnfollowRequest{FollowerId: 1, FollowingId: 3}, expectError: false, success: true, }, { name: "Success - non-existent subscription", // ИЗМЕНИЛОСЬ: не ошибка req: &proto.UnfollowRequest{FollowerId: 1, FollowingId: 999}, expectError: false, success: false, }, { name: "Error - non-existent user", // ИЗМЕНИЛОСЬ: не ошибка, просто false req: &proto.UnfollowRequest{FollowerId: 999, FollowingId: 1}, expectError: false, success: false, }, { name: "Error - zero IDs", req: &proto.UnfollowRequest{FollowerId: 0, FollowingId: 0}, expectError: true, errorCode: codes.InvalidArgument, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() resp, err := server.UnfollowUser(ctx, tt.req) if tt.expectError { assert.Error(t, err) if st, ok := status.FromError(err); ok { assert.Equal(t, tt.errorCode, st.Code()) } } else { assert.NoError(t, err) assert.Equal(t, tt.success, resp.Success) if tt.success { assert.Contains(t, resp.Message, "Successfully") } else { assert.Contains(t, resp.Message, "not found") } } }) } } func TestGetFollowersCount(t *testing.T) { db := setupTestDB(t) server := NewServer(db) tests := []struct { name string req *proto.GetCountRequest expected int32 expectError bool errorCode codes.Code }{ { name: "Success - user 2 has 0 followers initially", req: &proto.GetCountRequest{UserId: 2}, expected: 0, expectError: false, }, { name: "Success - user 1 has 0 followers", req: &proto.GetCountRequest{UserId: 1}, expected: 0, expectError: false, }, { name: "Success - user 3 has 0 followers", req: &proto.GetCountRequest{UserId: 3}, expected: 0, expectError: false, }, { name: "Success - non-existent user returns 0", req: &proto.GetCountRequest{UserId: 999}, expected: 0, expectError: false, }, { name: "Error - zero user ID", req: &proto.GetCountRequest{UserId: 0}, expectError: true, errorCode: codes.InvalidArgument, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() resp, err := server.GetFollowersCount(ctx, tt.req) if tt.expectError { assert.Error(t, err) if st, ok := status.FromError(err); ok { assert.Equal(t, tt.errorCode, st.Code()) } } else { assert.NoError(t, err) assert.Equal(t, tt.expected, resp.Count) } }) } } func TestGetFollowingCount(t *testing.T) { db := setupTestDB(t) server := NewServer(db) tests := []struct { name string req *proto.GetCountRequest expected int32 expectError bool errorCode codes.Code }{ { name: "Success - user 2 follows 0 users initially", req: &proto.GetCountRequest{UserId: 2}, expected: 0, expectError: false, }, { name: "Success - user 1 follows 0 users", req: &proto.GetCountRequest{UserId: 1}, expected: 0, expectError: false, }, { name: "Success - user 3 follows 0 users", req: &proto.GetCountRequest{UserId: 3}, expected: 0, expectError: false, }, { name: "Success - non-existent user returns 0", req: &proto.GetCountRequest{UserId: 999}, expected: 0, expectError: false, }, { name: "Error - zero user ID", req: &proto.GetCountRequest{UserId: 0}, expectError: true, errorCode: codes.InvalidArgument, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() resp, err := server.GetFollowingCount(ctx, tt.req) if tt.expectError { assert.Error(t, err) if st, ok := status.FromError(err); ok { assert.Equal(t, tt.errorCode, st.Code()) } } else { assert.NoError(t, err) assert.Equal(t, tt.expected, resp.Count) } }) } } func TestGetFollowers(t *testing.T) { db := setupTestDB(t) server := NewServer(db) tests := []struct { name string req *proto.GetFollowersRequest expectedCount int expectError bool errorCode codes.Code }{ { name: "Success - user 2 has 0 followers initially", req: &proto.GetFollowersRequest{UserId: 2, Limit: 10, Offset: 0}, expectedCount: 0, expectError: false, }, { name: "Success - user 1 has 0 followers", req: &proto.GetFollowersRequest{UserId: 1, Limit: 10, Offset: 0}, expectedCount: 0, expectError: false, }, { name: "Success - get with limit 0", req: &proto.GetFollowersRequest{UserId: 2, Limit: 0, Offset: 0}, expectedCount: 0, expectError: false, }, { name: "Success - non-existent user returns empty list", req: &proto.GetFollowersRequest{UserId: 999, Limit: 10, Offset: 0}, expectError: false, }, { name: "Error - zero user ID", req: &proto.GetFollowersRequest{UserId: 0, Limit: 10, Offset: 0}, expectError: true, errorCode: codes.InvalidArgument, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() resp, err := server.GetFollowers(ctx, tt.req) if tt.expectError { assert.Error(t, err) if st, ok := status.FromError(err); ok { assert.Equal(t, tt.errorCode, st.Code()) } } else { assert.NoError(t, err) if tt.expectedCount >= 0 { assert.Len(t, resp.Followers, tt.expectedCount) } assert.NotNil(t, resp.TotalCount) } }) } } func TestGetFollowing(t *testing.T) { db := setupTestDB(t) server := NewServer(db) tests := []struct { name string req *proto.GetFollowingRequest expectedCount int expectError bool errorCode codes.Code }{ { name: "Success - user 2 follows 0 users initially", req: &proto.GetFollowingRequest{UserId: 2, Limit: 10, Offset: 0}, expectedCount: 0, expectError: false, }, { name: "Success - user 1 follows 0 users", req: &proto.GetFollowingRequest{UserId: 1, Limit: 10, Offset: 0}, expectedCount: 0, expectError: false, }, { name: "Success - get with limit 0", req: &proto.GetFollowingRequest{UserId: 2, Limit: 0, Offset: 0}, expectedCount: 0, expectError: false, }, { name: "Success - non-existent user returns empty list", req: &proto.GetFollowingRequest{UserId: 999, Limit: 10, Offset: 0}, expectError: false, }, { name: "Error - zero user ID", req: &proto.GetFollowingRequest{UserId: 0, Limit: 10, Offset: 0}, expectError: true, errorCode: codes.InvalidArgument, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() resp, err := server.GetFollowing(ctx, tt.req) if tt.expectError { assert.Error(t, err) if st, ok := status.FromError(err); ok { assert.Equal(t, tt.errorCode, st.Code()) } } else { assert.NoError(t, err) if tt.expectedCount >= 0 { assert.Len(t, resp.Following, tt.expectedCount) } assert.NotNil(t, resp.TotalCount) } }) } }