fix(MongoDB Atlas Vector Store Node): Old credentials used even after credentials are updated/changed (#16471)

This commit is contained in:
RomanDavydchuk
2025-06-23 13:30:42 +03:00
committed by GitHub
parent b5ba655863
commit 9346463c6b
2 changed files with 94 additions and 7 deletions

View File

@@ -0,0 +1,78 @@
import { MongoClient } from 'mongodb';
import { getMongoClient, mongoConfig } from './VectorStoreMongoDBAtlas.node';
jest.mock('mongodb', () => ({
MongoClient: jest.fn(),
}));
describe('VectorStoreMongoDBAtlas -> getMongoClient', () => {
const mockContext = {
getCredentials: jest.fn(),
};
const mockClient1 = {
connect: jest.fn().mockResolvedValue(undefined),
close: jest.fn().mockResolvedValue(undefined),
};
const mockClient2 = {
connect: jest.fn().mockResolvedValue(undefined),
close: jest.fn().mockResolvedValue(undefined),
};
const MockMongoClient = MongoClient as jest.MockedClass<typeof MongoClient>;
beforeEach(() => {
jest.resetAllMocks();
mongoConfig.client = null;
mongoConfig.connectionString = '';
});
it('should reuse the same client when connection string is unchanged', async () => {
MockMongoClient.mockImplementation(() => mockClient1 as unknown as MongoClient);
mockContext.getCredentials.mockResolvedValue({
connectionString: 'mongodb://localhost:27017',
});
const client1 = await getMongoClient(mockContext);
const client2 = await getMongoClient(mockContext);
expect(MockMongoClient).toHaveBeenCalledTimes(1);
expect(MockMongoClient).toHaveBeenCalledWith('mongodb://localhost:27017', {
appName: 'devrel.integration.n8n_vector_integ',
});
expect(mockClient1.connect).toHaveBeenCalledTimes(1);
expect(mockClient1.close).not.toHaveBeenCalled();
expect(mockClient2.connect).not.toHaveBeenCalled();
expect(client1).toBe(mockClient1);
expect(client2).toBe(mockClient1);
});
it('should create new client when connection string changes', async () => {
MockMongoClient.mockImplementationOnce(
() => mockClient1 as unknown as MongoClient,
).mockImplementationOnce(() => mockClient2 as unknown as MongoClient);
mockContext.getCredentials
.mockResolvedValueOnce({
connectionString: 'mongodb://localhost:27017',
})
.mockResolvedValueOnce({
connectionString: 'mongodb://different-host:27017',
});
const client1 = await getMongoClient(mockContext);
const client2 = await getMongoClient(mockContext);
expect(MockMongoClient).toHaveBeenCalledTimes(2);
expect(MockMongoClient).toHaveBeenNthCalledWith(1, 'mongodb://localhost:27017', {
appName: 'devrel.integration.n8n_vector_integ',
});
expect(MockMongoClient).toHaveBeenNthCalledWith(2, 'mongodb://different-host:27017', {
appName: 'devrel.integration.n8n_vector_integ',
});
expect(mockClient1.connect).toHaveBeenCalledTimes(1);
expect(mockClient1.close).toHaveBeenCalledTimes(1);
expect(mockClient2.connect).toHaveBeenCalledTimes(1);
expect(mockClient2.close).not.toHaveBeenCalled();
expect(client1).toBe(mockClient1);
expect(client2).toBe(mockClient2);
});
});

View File

@@ -103,17 +103,26 @@ const insertFields: INodeProperties[] = [
},
];
let mongoClient: MongoClient | null = null;
export const mongoConfig = {
client: null as MongoClient | null,
connectionString: '',
};
async function getMongoClient(context: any) {
if (!mongoClient) {
const credentials = await context.getCredentials('mongoDb');
mongoClient = new MongoClient(credentials.connectionString as string, {
export async function getMongoClient(context: any) {
const credentials = await context.getCredentials('mongoDb');
const connectionString = credentials.connectionString as string;
if (!mongoConfig.client || mongoConfig.connectionString !== connectionString) {
if (mongoConfig.client) {
await mongoConfig.client.close();
}
mongoConfig.connectionString = connectionString;
mongoConfig.client = new MongoClient(connectionString, {
appName: 'devrel.integration.n8n_vector_integ',
});
await mongoClient.connect();
await mongoConfig.client.connect();
}
return mongoClient;
return mongoConfig.client;
}
async function mongoClientAndDatabase(context: any) {