testcontainers-python icon indicating copy to clipboard operation
testcontainers-python copied to clipboard

Feature: mongodb as replica set (single node)

Open iamsaywhat opened this issue 1 year ago • 6 comments

What are you trying to do?

Unit testing of Mongodb transactions.

Why should it be done this way?

mongomock can often be used in unit testing of mongodb-related functionality. It's faster and easier than using docker containers for such tests. But perhaps one of the most important scenarios in which mongomock is not applicable is testing the functionality using MongoDB transactions. At the moment, transaction mocking is not implemented in mongomock. But even if support for this was implemented there, such sensitive functionality (using transactions) would like to be checked "naturally". But as you know, transactions are possible only for replica sets, which the default MongoDB container is not. It is possible to configure mongodb as a replicaset (although with one node, but I think this is not critical for testing).

If you find this functionality useful here in the public, I can provide a PR (either as a separate Mongodb container, or extend the current MongoDbContainer with configuration options). What do you think about it?

iamsaywhat avatar Jul 05 '24 11:07 iamsaywhat

that would be great! also would be cool to have streaming, i think also only available with replica sets.

alexanderankin avatar Jul 06 '24 04:07 alexanderankin

mongodb replica set can be set with mongo_container.with_command("--replSet=rs"). but it makes it impossible to set since auth is forced internally and replica set with auth requires a key File. it would be great if the auth is optional.

naolaregaqena avatar Aug 17 '24 10:08 naolaregaqena

there is a work around to it

@fixture(autouse=True, scope="session")
def init_testcontainers():
    mongo_container = DockerContainer("mongo:6.0.7")
    mongo_bind_port = randint(a=30000, b=40000)
    
    mongo_container.with_name("python_testing_mongodb")
    mongo_container.with_bind_ports(container=mongo_bind_port, host=mongo_bind_port)
    mongo_container.with_command(f"--port={mongo_bind_port} --replSet=rs")
    mongo_container.start()

    settings().connection_string = f"mongodb://localhost:{mongo_bind_port}/?replicaSet=rs"
    exit_code, _ = mongo_container.exec("mongosh --quiet --eval=\"rs.initiate({_id:\'rs\',members:[{_id:0,host:\'localhost:%s\'}]})\" mongodb://localhost:%s" % (mongo_bind_port, mongo_bind_port))

    if exit_code != 0:
        raise RuntimeError("replica set didn't get setup properly")

    yield

    mongo_container.stop()

naolaregaqena avatar Aug 17 '24 13:08 naolaregaqena

@naolaregaqena can you comment with an example of using the streams for something? this way i can add a test to the pull request for this feature and add it to the library.

alexanderankin avatar Aug 17 '24 21:08 alexanderankin

@alexanderankin stream also works too, you could use motor like so

async def watch_users():
    async with db.users.watch() as users_stream:
        async for user in users_stream:
            print(user)

naolaregaqena avatar Aug 18 '24 14:08 naolaregaqena

Linking the .NET implementation of WithReplicaSet(): https://github.com/testcontainers/testcontainers-dotnet/pull/1196

gpkc avatar Dec 06 '24 22:12 gpkc