MongoError:池正在耗尽,在集成测试中使用MongoMemoryServer时禁止新操作



我正在使用MongoMemoryServer编写集成测试。我有两个集成测试文件。当我运行IT测试时,我会看到以下内容。我不明白为什么。我使用的是jestjs测试框架。

当我有两个IT测试文件时,我看到了以下错误

MongoError: pool is draining, new operations prohibited
37 |   for (const key in collections) {
38 |     const collection = collections[key];
> 39 |     await collection.deleteMany();
|                      ^
40 |   }
41 | };

这是我的设置

//db-handler.js
const mongoose = require("mongoose");
const { MongoMemoryServer } = require("mongodb-memory-server");
const mongod = new MongoMemoryServer();
module.exports.connect = async () => {
const uri = await mongod.getConnectionString();
const mongooseOpts = {
useNewUrlParser: true,
autoReconnect: true,
reconnectTries: Number.MAX_VALUE,
reconnectInterval: 1000,
};
await mongoose.connect(uri, mongooseOpts);
};
module.exports.closeDatabase = async () => {
await mongoose.connection.dropDatabase();
await mongoose.connection.close();
await mongod.stop();
};
module.exports.clearDatabase = async () => {
const collections = mongoose.connection.collections;
for (const key in collections) {
const collection = collections[key];
await collection.deleteMany();
}
};

我所有的IT测试设置看起来都像这个

//example.it.test.js
const supertest = require("supertest");
const dbHandler = require("./db-handler");
const app = require("../../src/app");
const request = supertest(app);
const SomeModel = require("../Some");
beforeAll(async () => await dbHandler.connect());
afterEach(async () => await dbHandler.clearDatabase());
afterAll(async () => await dbHandler.closeDatabase());
describe("Some Test Block", () => {
it("Test One", async (done) => {
await SomeModel.create({a: "a", b "b"});
const response = await request.get("/endPointToTest");
expect(response.status).toBe(200);
done();
});

当我只有一个IT测试文件时,一切都很好。当我引入一个类似于example.it.test.js的新IT测试文件时,新的测试就会失败。上面的错误消息示例。

我错过了什么?当我有多个IT测试文件时,我的设置是否需要更改?

更新一个:我的package.json文件看起来像

{
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"test": "jest --runInBand ./tests"
},
"devDependencies": {
"jest": "^25.2.7",
"mongodb-memory-server": "^6.5.2",
"nodemon": "^2.0.2",
"supertest": "^4.0.2"
},
"jest": {
"testEnvironment": "node",
"coveragePathIgnorePatterns": [
"/node_modules/"
]
}
}

我认为在某些情况下,错误消息可能会产生误导。

这个问题似乎与";池大小太小";或";jest并行运行测试";,所以这个池最终用完了可用的池。

然而,如果你看看当mongo破坏游泳池时会发生什么,你就会明白了。

/**
* Destroy pool
* @method
*/
Pool.prototype.destroy = function(force, callback) {
...
// Set state to draining
stateTransition(this, DRAINING);
...

如果尝试关闭连接,则池会将其内部状态更改为"正在排出",从而导致问题。

因此,错误消息告诉我们的是,在pool.destroy之后仍有未完成的写入操作。

在我的例子中,这是一个每x秒运行一次的活动事件侦听器回调,它确实会写入mongo。

我更改了测试代码,直接调用事件回调函数,而不是每x秒调用一次。

这解决了我的问题。

默认情况下,Jest与"运行测试的子进程的工作池"(Jest CLI文档(并行运行测试。根据Jest文档。

每个测试文件都在与导致错误的mogodb服务器建立新的连接。

您可以运行Jest测试sequentially来避免此问题。

Jest CLI的--runInBand或-i选项允许您按顺序运行测试(在非并行模式下(。

如果您使用node-js或mongoose的官方mongodb库,则可能会出现此错误(池正在耗尽,禁止新操作(。建立mongodb连接时,请指定池大小。

module.exports.connect = async () => {
const uri = await mongod.getConnectionString();
const mongooseOpts = {
useNewUrlParser: true,
autoReconnect: true,
reconnectTries: Number.MAX_VALUE,
reconnectInterval: 1000,
poolSize: 10,
};
await mongoose.connect(uri, mongooseOpts);
};

我也做了同样的事情,也遇到了同样的错误。这是通过在测试中按模式名称删除来解决的,就像我下面在some.test.js 中所做的那样

**其余所有设置保持不变**

//example.it.test.js
const dbHandler = require("./db-handler");
const SomeModel = require("../Some");
const SomeOtherModel = require("../SomeOther");
beforeAll(async () => await dbHandler.connect());
afterEach(async () => {
await SomeModel.remove({});
await SomeOtherModel.remove({});
});
afterAll(async () => await dbHandler.closeDatabase());
describe("Some Test Block", () => {
it("Test One", async (done) => {
await SomeModel.create({a: "a", SomeOther: 'SomeOther Data' });
const data = await SomeModel.getAll();
expect(data.length).toBe(1);
done();
});
});

对于每个It测试用例,它都会连接到mongoose,如果发生任何错误,mongoose不会断开连接。

解决方案

  1. 您可以将it测试用例放在try-catch块中,但如果可能,请使用2点
  2. 尝试处理控制器和服务中的错误,等等文件(如果可能的话(
  3. 无论何时编写测试用例,都不应该有来自开发代码的错误
  4. 不要在一个描述中写嵌套的描述,最多嵌套2个描述我们应该使用
  5. 一个临时的解决方案,我跳过了所有描述,除了猫鼬连接的最外面
  6. 还有一个临时解决方案,断开mongod,然后查看状态,然后重新连接

最新更新