From 2ab5fcd9b547e9752ce18572b246a17711e5432f Mon Sep 17 00:00:00 2001 From: Kevin Szuchet Date: Wed, 22 Jan 2025 16:04:35 -0300 Subject: [PATCH] feat: GetMutualFriends also retrieves profiles and improves the response --- src/adapters/rpc-server/rpc-server.ts | 2 +- .../rpc-server/services/get-mutual-friends.ts | 15 +++- test/mocks/friend.ts | 14 ++++ .../rpc-server/services/get-friends.spec.ts | 15 +--- .../services/get-mutual-friends.spec.ts | 68 ++++++++++--------- 5 files changed, 65 insertions(+), 49 deletions(-) create mode 100644 test/mocks/friend.ts diff --git a/src/adapters/rpc-server/rpc-server.ts b/src/adapters/rpc-server/rpc-server.ts index 1ec5f9b..af67fdc 100644 --- a/src/adapters/rpc-server/rpc-server.ts +++ b/src/adapters/rpc-server/rpc-server.ts @@ -38,7 +38,7 @@ export async function createRpcServerComponent({ const rpcServerPort = (await config.getNumber('RPC_SERVER_PORT')) || 8085 const getFriends = await getFriendsService({ components: { logs, db, catalystClient, config } }) - const getMutualFriends = getMutualFriendsService({ components: { logs, db } }) + const getMutualFriends = await getMutualFriendsService({ components: { logs, db, catalystClient, config } }) const getPendingFriendshipRequests = getPendingFriendshipRequestsService({ components: { logs, db } }) const getSentFriendshipRequests = getSentFriendshipRequestsService({ components: { logs, db } }) const upsertFriendship = upsertFriendshipService({ components: { logs, db, pubsub } }) diff --git a/src/adapters/rpc-server/services/get-mutual-friends.ts b/src/adapters/rpc-server/services/get-mutual-friends.ts index ebb12fa..6525761 100644 --- a/src/adapters/rpc-server/services/get-mutual-friends.ts +++ b/src/adapters/rpc-server/services/get-mutual-friends.ts @@ -6,22 +6,31 @@ import { } from '@dcl/protocol/out-js/decentraland/social_service/v2/social_service_v2.gen' import { normalizeAddress } from '../../../utils/address' import { getPage } from '../../../utils/pagination' +import { parseProfilesToFriends } from '../../../logic/friends' -export function getMutualFriendsService({ components: { logs, db } }: RPCServiceContext<'logs' | 'db'>) { +export async function getMutualFriendsService({ + components: { logs, db, catalystClient, config } +}: RPCServiceContext<'logs' | 'db' | 'catalystClient' | 'config'>) { const logger = logs.getLogger('get-mutual-friends-service') + const contentServerUrl = await config.requireString('CONTENT_SERVER_URL') return async function (request: GetMutualFriendsPayload, context: RpcServerContext): Promise { - logger.debug(`getting mutual friends ${context.address}<>${request.user!.address}`) + logger.debug(`Getting mutual friends ${context.address}<>${request.user!.address}`) + try { const { address: requester } = context const { pagination, user } = request const requested = normalizeAddress(user!.address) + const [mutualFriends, total] = await Promise.all([ db.getMutualFriends(requester, requested, pagination), db.getMutualFriendsCount(requester, requested) ]) + + const profiles = await catalystClient.getEntitiesByPointers(mutualFriends.map((friend) => friend.address)) + return { - users: mutualFriends, + users: parseProfilesToFriends(profiles, contentServerUrl), paginationData: { total, page: getPage(pagination?.limit || FRIENDSHIPS_PER_PAGE, pagination?.offset) diff --git a/test/mocks/friend.ts b/test/mocks/friend.ts new file mode 100644 index 0000000..fdb6383 --- /dev/null +++ b/test/mocks/friend.ts @@ -0,0 +1,14 @@ +import { Friend } from '../../src/types' + +export const createMockFriend = (address: string): Friend => ({ + address +}) + +export function parseExpectedFriends(contentServerUrl: string) { + return (address: string) => ({ + address, + name: `Profile name ${address}`, + hasClaimedName: true, + profilePictureUrl: `${contentServerUrl}/contents/bafybeiasdfqwer` + }) +} diff --git a/test/unit/adapters/rpc-server/services/get-friends.spec.ts b/test/unit/adapters/rpc-server/services/get-friends.spec.ts index dc59dfb..8883d63 100644 --- a/test/unit/adapters/rpc-server/services/get-friends.spec.ts +++ b/test/unit/adapters/rpc-server/services/get-friends.spec.ts @@ -1,7 +1,8 @@ import { mockCatalystClient, mockConfig, mockDb, mockLogs } from '../../../../mocks/components' import { getFriendsService } from '../../../../../src/adapters/rpc-server/services/get-friends' -import { RpcServerContext, Friend } from '../../../../../src/types' +import { RpcServerContext } from '../../../../../src/types' import { createMockProfile } from '../../../../mocks/profile' +import { createMockFriend, parseExpectedFriends } from '../../../../mocks/friend' describe('getFriendsService', () => { let getFriends: Awaited> @@ -34,12 +35,7 @@ describe('getFriendsService', () => { const response = await getFriends({ pagination: { limit: 10, offset: 0 } }, rpcContext) expect(response).toEqual({ - users: addresses.map((address) => ({ - address, - name: `Profile name ${address}`, - hasClaimedName: true, - profilePictureUrl: `${contentServerUrl}/contents/bafybeiasdfqwer` - })), + users: addresses.map(parseExpectedFriends(contentServerUrl)), paginationData: { total: totalFriends, page: 1 @@ -93,9 +89,4 @@ describe('getFriendsService', () => { } }) }) - - // Helper to create a mock friendship object - const createMockFriend = (address): Friend => ({ - address - }) }) diff --git a/test/unit/adapters/rpc-server/services/get-mutual-friends.spec.ts b/test/unit/adapters/rpc-server/services/get-mutual-friends.spec.ts index fdef13f..c423c30 100644 --- a/test/unit/adapters/rpc-server/services/get-mutual-friends.spec.ts +++ b/test/unit/adapters/rpc-server/services/get-mutual-friends.spec.ts @@ -1,12 +1,14 @@ -import { mockDb, mockLogs } from '../../../../mocks/components' +import { mockCatalystClient, mockConfig, mockDb, mockLogs } from '../../../../mocks/components' import { getMutualFriendsService } from '../../../../../src/adapters/rpc-server/services/get-mutual-friends' -import { FRIENDSHIPS_PER_PAGE } from '../../../../../src/adapters/rpc-server/constants' import { GetMutualFriendsPayload } from '@dcl/protocol/out-js/decentraland/social_service/v2/social_service_v2.gen' -import { RpcServerContext, AppComponents } from '../../../../../src/types' +import { RpcServerContext } from '../../../../../src/types' +import { createMockProfile } from '../../../../mocks/profile' +import { createMockFriend, parseExpectedFriends } from '../../../../mocks/friend' describe('getMutualFriendsService', () => { - let components: jest.Mocked> - let getMutualFriends: ReturnType + let getMutualFriends: Awaited> + + const contentServerUrl = 'https://peer.decentraland.org/content' const rpcContext: RpcServerContext = { address: '0x123', @@ -18,50 +20,34 @@ describe('getMutualFriendsService', () => { pagination: { limit: 10, offset: 0 } } - beforeEach(() => { - components = { db: mockDb, logs: mockLogs } - getMutualFriends = getMutualFriendsService({ components }) + beforeEach(async () => { + mockConfig.requireString.mockResolvedValueOnce(contentServerUrl) + getMutualFriends = await getMutualFriendsService({ + components: { db: mockDb, logs: mockLogs, catalystClient: mockCatalystClient, config: mockConfig } + }) }) it('should return the correct list of mutual friends with pagination data', async () => { - const mockMutualFriends = [{ address: '0x789' }, { address: '0xabc' }] + const addresses = ['0x789', '0xabc'] + const mockMutualFriends = addresses.map(createMockFriend) + const mockMutualFriendsProfiles = addresses.map(createMockProfile) const totalMutualFriends = 2 mockDb.getMutualFriends.mockResolvedValueOnce(mockMutualFriends) mockDb.getMutualFriendsCount.mockResolvedValueOnce(totalMutualFriends) + mockCatalystClient.getEntitiesByPointers.mockResolvedValueOnce(mockMutualFriendsProfiles) const response = await getMutualFriends(mutualFriendsRequest, rpcContext) expect(response).toEqual({ - users: mockMutualFriends, + users: addresses.map(parseExpectedFriends(contentServerUrl)), paginationData: { total: totalMutualFriends, - page: 1 // First page is 1 + page: 1 } }) }) - it('should respect the pagination limit', async () => { - const mockMutualFriends = Array.from({ length: FRIENDSHIPS_PER_PAGE }, (_, i) => ({ - address: `0x${i + 1}` - })) - const totalMutualFriends = FRIENDSHIPS_PER_PAGE + 5 - - mockDb.getMutualFriends.mockResolvedValueOnce(mockMutualFriends) - mockDb.getMutualFriendsCount.mockResolvedValueOnce(totalMutualFriends) - - const response = await getMutualFriends( - { ...mutualFriendsRequest, pagination: { limit: FRIENDSHIPS_PER_PAGE, offset: 0 } }, - rpcContext - ) - - expect(response.users).toHaveLength(FRIENDSHIPS_PER_PAGE) - expect(response.paginationData).toEqual({ - total: totalMutualFriends, - page: 1 // First page is 1 - }) - }) - it('should return an empty list if no mutual friends are found', async () => { mockDb.getMutualFriends.mockResolvedValueOnce([]) mockDb.getMutualFriendsCount.mockResolvedValueOnce(0) @@ -75,7 +61,7 @@ describe('getMutualFriendsService', () => { users: [], paginationData: { total: 0, - page: 1 // First page is 1, even when no results + page: 1 } }) }) @@ -95,4 +81,20 @@ describe('getMutualFriendsService', () => { } }) }) + + it('should handle errors from the catalyst gracefully', async () => { + mockCatalystClient.getEntitiesByPointers.mockImplementationOnce(() => { + throw new Error('Catalyst error') + }) + + const response = await getMutualFriends(mutualFriendsRequest, rpcContext) + + expect(response).toEqual({ + users: [], + paginationData: { + total: 0, + page: 1 + } + }) + }) })