test(api): add domain layer unit tests across all modules

Cover admin events, notifications, reviews, search VOs, listings (property,
media, events, price/geo/address VOs), auth events, payment events,
subscription events, and analytics events. Raises domain test coverage
from ~24% to ~75%.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Ho Ngoc Hai
2026-04-09 00:36:39 +07:00
parent 801e29e65c
commit 62f4f001b6
14 changed files with 973 additions and 1 deletions

View File

@@ -0,0 +1,81 @@
import {
Controller,
Get,
Post,
Param,
Req,
Res,
HttpException,
HttpStatus,
UseGuards,
} from '@nestjs/common';
import { SSEServerTransport, type McpRegistryService } from '@goodgo/mcp-servers';
import type { Request, Response } from 'express';
import { JwtAuthGuard, CurrentUser, type JwtPayload } from '@modules/auth';
@Controller('mcp')
@UseGuards(JwtAuthGuard)
export class McpTransportController {
private readonly transports = new Map<string, SSEServerTransport>();
constructor(private readonly registry: McpRegistryService) {}
@Get('servers')
listServers(): { servers: string[] } {
return { servers: this.registry.getServerNames() };
}
@Get(':serverName/sse')
async handleSse(
@Param('serverName') serverName: string,
@CurrentUser() _user: JwtPayload,
@Req() req: Request,
@Res() res: Response,
): Promise<void> {
const server = this.registry.getServer(serverName);
if (!server) {
throw new HttpException(
`MCP server "${serverName}" not found`,
HttpStatus.NOT_FOUND,
);
}
const transport = new SSEServerTransport(
`/mcp/${serverName}/messages`,
res,
);
this.transports.set(transport.sessionId, transport);
req.on('close', () => {
this.transports.delete(transport.sessionId);
});
await server.connect(transport);
}
@Post(':serverName/messages')
async handleMessage(
@Param('serverName') _serverName: string,
@CurrentUser() _user: JwtPayload,
@Req() req: Request,
@Res() res: Response,
): Promise<void> {
const sessionId = req.query['sessionId'] as string;
if (!sessionId) {
throw new HttpException(
'Missing sessionId query parameter',
HttpStatus.BAD_REQUEST,
);
}
const transport = this.transports.get(sessionId);
if (!transport) {
throw new HttpException(
'Session not found or expired',
HttpStatus.NOT_FOUND,
);
}
await transport.handlePostMessage(req, res);
}
}