typegoose / typegoose/mongodb-memory-server
MongoMemoryServer.stop() is not a fully optimized teardown solution
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 2.8k
- Forks
- 191
- Avg merge
- 4h 25m
- Merged PRs (30d)
- 10
Description
Versions
- NodeJS: v24.19.0
- mongodb-memory-server-*: 11.2.0
- mongodb(the binary version): 0.0.0
- mongodb(the js package): n/a, not used directly by the repro
- system: Linux (GitHub Actions ubuntu-24.04 runner)
package: mongodb-memory-server-core
What is the Problem?
The documented lifecycle pattern for MongoMemoryServer — one instance, reused across tests, cleaned up with a single .stop() call at the end — is what docs/guides/integration-examples/test-runners.md recommends, and it's the same shape this project's own MongoMemoryServer.test.ts already uses (describe('getUri()', ...), plain afterAll(() => mongoServer.stop())).
Here I've created a new baseline test, a reasonably simple situation: the MongoMemoryServer mongod process is killed after the server has been created. In this situation, the documented .stop() call is not enough: it throws instead of succeeding.
That raises a bigger question than just this one code path: what's actually the process for managing a MongoMemoryServer instance's lifecycle in a real application? If the current testing suite is the best documentation available, it's clear that there is at least one (and likely many more) scenarios where a simple .stop() call is not sufficient.
Code Example
// mirrors describe('getUri()', ...)'s beforeAll/afterAll shape already in this file
describe('afterAll cleanup after mongod is killed unexpectedly', () => {
let mongoServer: MongoMemoryServer;
let dbPath: string;
beforeAll(async () => {
mongoServer = await MongoMemoryServer.create();
dbPath = mongoServer.instanceInfo!.dbPath;
});
// unchanged from getUri() above -- the plain, documented pattern
afterAll(async () => {
if (mongoServer) {
await mongoServer.stop();
}
});
// consequence 1: was the temp directory actually cleaned up?
afterAll(async () => {
expect(await utils.statPath(dbPath)).toBeUndefined();
});
// consequence 2: can the object be recovered by restarting it?
afterAll(async () => {
await mongoServer.start();
});
it('mongod is killed unexpectedly between tests', async () => {
const instance = mongoServer.instanceInfo!.instance;
const pid = instance.mongodProcess!.pid;
// wait for this library's own internal crash-recovery to fully settle first
const closedPromise = new Promise<void>((resolve) => {
instance.once(MongoInstanceEvents.instanceClosed, () => resolve());
});
process.kill(pid!, 'SIGKILL'); // simulate a crash
await closedPromise;
expect(instance.stopPromise).toBeDefined();
await instance.stopPromise!;
});
});
Debug Output
Debug Output
FAIL src/__tests__/MongoMemoryServer.test.ts
● Test suite failed to run
Cannot cleanup because "instance.mongodProcess" is still defined
at MongoMemoryServer.cleanup (src/MongoMemoryServer.ts:641:7)
at MongoMemoryServer.cleanup [as stop] (src/MongoMemoryServer.ts:600:18)
at Object.<anonymous> (src/__tests__/MongoMemoryServer.test.ts:865:9)
● Test suite failed to run
expect(received).toBeUndefined()
Received: {"atimeMs": 1788978155240.21, "birthtimeMs": 1788978155240.21, "blksize": 4096,
"blocks": 8, "ctimeMs": 1788978155348.21, "dev": 2049, "gid": 1001, "ino": 8957260,
"mode": 16832, "mtimeMs": 1788978155348.21, "nlink": 4, "rdev": 0, "size": 4096, "uid": 1001}
at Object.<anonymous> (src/__tests__/MongoMemoryServer.test.ts:871:44)
● Test suite failed to run
Cannot start because "instance.mongodProcess" is already defined!
at MongoMemoryServer.start (src/MongoMemoryServer.ts:345:7)
at Object.<anonymous> (src/__tests__/MongoMemoryServer.test.ts:876:25)
Tests: 64 passed, 64 total
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the failure in src/tests/MongoMemoryServer.test.ts using the killed mongod scenario and inspect MongoMemoryServer.stop(), cleanup(), and start() in src/MongoMemoryServer.ts. Compare the behavior with docs/guides/integration-examples/test-runners.md. Done should establish whether stop removes the temporary directory and whether the instance can be restarted after an unexpected mongod exit, with regression coverage for the agreed lifecycle behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- mongodb, nodejs, typescript
- Domain
- backend, testing-qa
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100