package http import ( "context" "encoding/json" "hyapp/services/gateway-service/internal/transport/http/httpkit" "net/http" "net/http/httptest" "testing" userv1 "hyapp.local/api/proto/user/v1" "hyapp/services/gateway-service/internal/auth" ) type fakeUserSocialClient struct { lastVisit *userv1.RecordProfileVisitRequest lastVisitors *userv1.ListProfileVisitorsRequest lastFollow *userv1.FollowUserRequest lastUnfollow *userv1.UnfollowUserRequest lastFollowing *userv1.ListFollowingRequest lastApply *userv1.ApplyFriendRequest lastAccept *userv1.AcceptFriendApplicationRequest lastDelete *userv1.DeleteFriendRequest lastFriends *userv1.ListFriendsRequest lastFriendApps *userv1.ListFriendApplicationsRequest } func (f *fakeUserSocialClient) RecordProfileVisit(_ context.Context, req *userv1.RecordProfileVisitRequest) (*userv1.RecordProfileVisitResponse, error) { f.lastVisit = req return &userv1.RecordProfileVisitResponse{Recorded: true, TargetStats: &userv1.UserProfileStats{UserId: req.GetTargetUserId(), VisitorsCount: 1}}, nil } func (f *fakeUserSocialClient) ListProfileVisitors(_ context.Context, req *userv1.ListProfileVisitorsRequest) (*userv1.ListProfileVisitorsResponse, error) { f.lastVisitors = req return &userv1.ListProfileVisitorsResponse{Records: []*userv1.ProfileVisitRecord{{VisitorUserId: 10002, TargetUserId: req.GetUserId(), VisitCount: 2, LastVisitedAtMs: 7000}}, Total: 1}, nil } func (f *fakeUserSocialClient) FollowUser(_ context.Context, req *userv1.FollowUserRequest) (*userv1.FollowUserResponse, error) { f.lastFollow = req return &userv1.FollowUserResponse{Following: true, FollowerStats: &userv1.UserProfileStats{UserId: req.GetFollowerUserId(), FollowingCount: 1}}, nil } func (f *fakeUserSocialClient) UnfollowUser(_ context.Context, req *userv1.UnfollowUserRequest) (*userv1.UnfollowUserResponse, error) { f.lastUnfollow = req return &userv1.UnfollowUserResponse{Following: false, FollowerStats: &userv1.UserProfileStats{UserId: req.GetFollowerUserId()}}, nil } func (f *fakeUserSocialClient) ListFollowing(_ context.Context, req *userv1.ListFollowingRequest) (*userv1.ListFollowingResponse, error) { f.lastFollowing = req return &userv1.ListFollowingResponse{Records: []*userv1.FollowRecord{{FollowerUserId: req.GetUserId(), FolloweeUserId: 10002, FollowedAtMs: 8000}}, Total: 1}, nil } func (f *fakeUserSocialClient) ApplyFriend(_ context.Context, req *userv1.ApplyFriendRequest) (*userv1.ApplyFriendResponse, error) { f.lastApply = req return &userv1.ApplyFriendResponse{Application: &userv1.FriendApplication{RequesterUserId: req.GetRequesterUserId(), TargetUserId: req.GetTargetUserId(), Status: "pending", CreatedAtMs: 9000, UpdatedAtMs: 9000}}, nil } func (f *fakeUserSocialClient) AcceptFriendApplication(_ context.Context, req *userv1.AcceptFriendApplicationRequest) (*userv1.AcceptFriendApplicationResponse, error) { f.lastAccept = req return &userv1.AcceptFriendApplicationResponse{Friend: &userv1.FriendRecord{UserId: req.GetAccepterUserId(), FriendUserId: req.GetRequesterUserId(), FriendedAtMs: 10000}}, nil } func (f *fakeUserSocialClient) DeleteFriend(_ context.Context, req *userv1.DeleteFriendRequest) (*userv1.DeleteFriendResponse, error) { f.lastDelete = req return &userv1.DeleteFriendResponse{Deleted: true}, nil } func (f *fakeUserSocialClient) ListFriends(_ context.Context, req *userv1.ListFriendsRequest) (*userv1.ListFriendsResponse, error) { f.lastFriends = req return &userv1.ListFriendsResponse{Records: []*userv1.FriendRecord{{UserId: req.GetUserId(), FriendUserId: 10002, FriendedAtMs: 10000}}, Total: 1}, nil } func (f *fakeUserSocialClient) ListFriendApplications(_ context.Context, req *userv1.ListFriendApplicationsRequest) (*userv1.ListFriendApplicationsResponse, error) { f.lastFriendApps = req return &userv1.ListFriendApplicationsResponse{Applications: []*userv1.FriendApplication{{RequesterUserId: 10002, TargetUserId: req.GetUserId(), Status: "pending", CreatedAtMs: 9000, UpdatedAtMs: 9000}}, Total: 1}, nil } func TestFriendApplicationFlowRoutesUseBackendThenIMOwnedReminder(t *testing.T) { socialClient := &fakeUserSocialClient{} handler := NewHandler(&fakeRoomClient{}) handler.SetUserSocialClient(socialClient) router := handler.Routes(auth.NewVerifier("secret")) applyReq := httptest.NewRequest(http.MethodPost, "/api/v1/users/10002/friend-requests", nil) applyReq.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 10001)) applyResp := httptest.NewRecorder() router.ServeHTTP(applyResp, applyReq) if applyResp.Code != http.StatusOK { t.Fatalf("apply friend status = %d body=%s", applyResp.Code, applyResp.Body.String()) } if socialClient.lastApply == nil || socialClient.lastApply.GetRequesterUserId() != 10001 || socialClient.lastApply.GetTargetUserId() != 10002 { t.Fatalf("apply friend request mismatch: %+v", socialClient.lastApply) } acceptReq := httptest.NewRequest(http.MethodPost, "/api/v1/users/10001/friend-requests/accept", nil) acceptReq.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 10002)) acceptResp := httptest.NewRecorder() router.ServeHTTP(acceptResp, acceptReq) if acceptResp.Code != http.StatusOK { t.Fatalf("accept friend status = %d body=%s", acceptResp.Code, acceptResp.Body.String()) } if socialClient.lastAccept == nil || socialClient.lastAccept.GetAccepterUserId() != 10002 || socialClient.lastAccept.GetRequesterUserId() != 10001 { t.Fatalf("accept friend request mismatch: %+v", socialClient.lastAccept) } } func TestSocialListRoutesPassPagingAndDirection(t *testing.T) { socialClient := &fakeUserSocialClient{} handler := NewHandler(&fakeRoomClient{}) handler.SetUserSocialClient(socialClient) router := handler.Routes(auth.NewVerifier("secret")) request := httptest.NewRequest(http.MethodGet, "/api/v1/users/me/friend-requests?direction=outgoing&page=2&page_size=30", nil) request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 10001)) response := httptest.NewRecorder() router.ServeHTTP(response, request) if response.Code != http.StatusOK { t.Fatalf("list friend applications status = %d body=%s", response.Code, response.Body.String()) } if socialClient.lastFriendApps == nil || socialClient.lastFriendApps.GetUserId() != 10001 || socialClient.lastFriendApps.GetDirection() != "outgoing" || socialClient.lastFriendApps.GetPage() != 2 || socialClient.lastFriendApps.GetPageSize() != 30 { t.Fatalf("friend application list request mismatch: %+v", socialClient.lastFriendApps) } var envelope httpkit.ResponseEnvelope if err := json.Unmarshal(response.Body.Bytes(), &envelope); err != nil || envelope.Code != httpkit.CodeOK { t.Fatalf("invalid envelope: %+v err=%v", envelope, err) } }