chore: Fix mcp-registry test seeding flake (#30941)

This commit is contained in:
Matsu 2026-05-25 14:23:44 +03:00 committed by GitHub
parent 7348f928c8
commit 40ecd5ea33
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 34 additions and 5 deletions

View File

@ -3,13 +3,34 @@ import { mock } from 'jest-mock-extended';
import { ForbiddenError } from '@/errors/response-errors/forbidden.error';
import { McpRegistryTestController } from '../mcp-registry-test.controller';
import { McpRegistryServerEntity } from '../registry/mcp-registry-server.entity';
import type { McpRegistryServerRepository } from '../registry/mcp-registry-server.repository';
import type { McpRegistryService } from '../registry/mcp-registry.service';
import { toEntity } from '../registry/mcp-registry.types';
import { notionMockServer, linearMockServer } from '../registry/mock-servers';
describe('McpRegistryTestController', () => {
const deleteQueryBuilder = {
delete: jest.fn().mockReturnThis(),
from: jest.fn().mockReturnThis(),
execute: jest.fn().mockResolvedValue({}),
};
const transactionManager = {
createQueryBuilder: jest.fn().mockReturnValue(deleteQueryBuilder),
insert: jest.fn().mockResolvedValue({}),
};
const manager = {
transaction: jest.fn(
async (runInTransaction: (m: typeof transactionManager) => Promise<unknown>) =>
await runInTransaction(transactionManager),
),
};
const repository = mock<McpRegistryServerRepository>();
Object.assign(repository, { manager });
const service = mock<McpRegistryService>();
const controller = new McpRegistryTestController(repository, service);
@ -25,15 +46,17 @@ describe('McpRegistryTestController', () => {
});
describe('seed', () => {
it('should upsert mock servers and trigger registry reload', async () => {
repository.upsert.mockResolvedValue({} as never);
it('should replace mock servers and trigger registry reload', async () => {
service.handleReloadMcpRegistry.mockResolvedValue();
const result = await controller.seed();
expect(repository.upsert).toHaveBeenCalledWith(
expect(manager.transaction).toHaveBeenCalled();
expect(deleteQueryBuilder.from).toHaveBeenCalledWith(McpRegistryServerEntity);
expect(deleteQueryBuilder.execute).toHaveBeenCalled();
expect(transactionManager.insert).toHaveBeenCalledWith(
McpRegistryServerEntity,
[notionMockServer, linearMockServer].map(toEntity),
['id'],
);
expect(service.handleReloadMcpRegistry).toHaveBeenCalled();
expect(result).toEqual({ ok: true, count: 2 });

View File

@ -2,6 +2,7 @@ import { Post, RestController } from '@n8n/decorators';
import { ForbiddenError } from '@/errors/response-errors/forbidden.error';
import { McpRegistryServerEntity } from './registry/mcp-registry-server.entity';
import { McpRegistryServerRepository } from './registry/mcp-registry-server.repository';
import { McpRegistryService } from './registry/mcp-registry.service';
import { toEntity } from './registry/mcp-registry.types';
@ -23,7 +24,12 @@ export class McpRegistryTestController {
this.assertE2ETestsEnabled();
const entities = [notionMockServer, linearMockServer].map(toEntity);
await this.repository.upsert(entities, ['id']);
// Replace rather than upsert: a startup refresh can leave rows whose slug collides with our mocks at a different id, which `ON CONFLICT (id) DO UPDATE` does not cover.
await this.repository.manager.transaction(async (manager) => {
await manager.createQueryBuilder().delete().from(McpRegistryServerEntity).execute();
await manager.insert(McpRegistryServerEntity, entities);
});
await this.service.handleReloadMcpRegistry();
return { ok: true, count: entities.length };