Repository: ClearcodeHQ/pytest-mongo (language: python)

Issue:
removed deprecated noprealloc flag
implemented noproc factory

Fixes #256 .

Changes proposed.


Discussion / hints:

Fix patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index a79b794..ef24284 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,6 +1,12 @@
 CHANGELOG
 =========
 
+unreleased
+-------
+
+- [feature] Add noproces fixture that can be used along the client to connect to
+  already existing MongoDB instance.
+
 2.0.0
 -------
 
diff --git a/README.rst b/README.rst
index 217af8c..0aca920 100644
--- a/README.rst
+++ b/README.rst
@@ -46,6 +46,9 @@ Plugin contains two fixtures
 
 * **mongodb** - it's a client fixture that has functional scope, and which cleans MongoDB at the end of each test.
 * **mongo_proc** - session scoped fixture, that starts MongoDB instance at the first use and stops at the end of the tests.
+* **mongo_noproc** - a no process fixture, that's connecting to already
+  running mongodb instance.
+  For example on dockerized test environments, or CI providing mongodb services
 
 Simply include one of these fixtures into your tests fixture list.
 
@@ -64,6 +67,21 @@ You can also create additional MongoDB client and process fixtures if you'd need
 
     Each MongoDB process fixture can be configured in a different way than the others through the fixture factory arguments.
 
+
+Connecting to already existing mongodb database
+-----------------------------------------------
+
+Some projects are using already running MongoDB servers (ie on docker instances).
+In order to connect to them, one would be using the ``mongo_noproc`` fixture.
+
+.. code-block:: python
+
+    mongo_external = factories.mongodb('mongo_noproc')
+
+By default the  ``mongo_noproc`` fixture would connect to MongoDB instance using **27017** port. Standard configuration options apply to it.
+
+These are the configuration options that are working on all levels with the ``mongo_noproc`` fixture:
+
 Configuration
 =============
 
@@ -81,36 +99,43 @@ You can pick which you prefer, but remember that these settings are handled in t
      - Fixture factory argument
      - Command line option
      - pytest.ini option
+     - Noop process fixture
      - Default
    * - Path to mongodb exec
      - executable
      - --mongo-exec
      - mongo_exec
+     - no
      - /usr/bin/mongod
    * - MongoDB host
      - host
      - --mongo-host
      - mongo_host
      - 127.0.0.1
+     - 127.0.0.1
    * - MongoDB port
      - port
      - --mongo-port
      - port
+     - 27017
      - random
    * - Path to store logs
      - logsdir
      - --mongo-logsdir
      - mongo_logsdir
+     - no
      - $TMPDIR
    * - Additional parameters
      - params
      - --mongo-params
      - mongo_params
+     - no
      -
    * - MongoDB client's time zone awarness
      - tz_aware
      - --mongo-tz-aware
      - mongo_tz_aware
+     - no
      - False
 
 


Test patch:
diff --git a/src/pytest_mongo/executor_noop.py b/src/pytest_mongo/executor_noop.py
new file mode 100644
index 0000000..2b46aab
--- /dev/null
+++ b/src/pytest_mongo/executor_noop.py
@@ -0,0 +1,32 @@
+"""MongoDB Noop executor providing connection details for mongodb client."""
+import pymongo
+
+
+class NoopExecutor:  # pylint: disable=too-few-public-methods
+    """
+    Nooperator executor.
+
+    This executor actually does nothing more than provide connection details
+    for existing MongoDB server. I.E. one already started either on machine
+    or with the use of containerisation like kubernetes or docker compose.
+    """
+
+    def __init__(self, host, port):
+        """
+        Initialize nooperator executor mock.
+
+        :param str host: MongoDB hostname
+        :param str|int port: MongoDB port
+        """
+        self.host = host
+        self.port = int(port)
+        self._version = None
+
+    @property
+    def version(self):
+        """Get MongoDB's version."""
+        if not self._version:
+            client = pymongo.MongoClient(host=self.host, port=self.port)
+            server_info = client.server_info()
+            self._version = server_info["version"]
+        return self._version
diff --git a/src/pytest_mongo/factories.py b/src/pytest_mongo/factories.py
index a0a33e7..57b51b3 100644
--- a/src/pytest_mongo/factories.py
+++ b/src/pytest_mongo/factories.py
@@ -19,10 +19,13 @@
 import os
 from shutil import rmtree
 from tempfile import gettempdir
+from typing import Callable, Union
 
 import pytest
 import pymongo
 from mirakuru import TCPExecutor
+from _pytest.fixtures import FixtureRequest
+from pytest_mongo.executor_noop import NoopExecutor
 
 from pytest_mongo.port import get_port
 
@@ -114,6 +117,42 @@ def mongo_proc_fixture(request):
     return mongo_proc_fixture
 
 
+def mongo_noproc(
+        host: str = None, port: Union[str, int] = None
+) -> Callable[[FixtureRequest], NoopExecutor]:
+    """
+    MongoDB noprocess factory.
+
+    :param host: hostname
+    :param port: exact port (e.g. '8000', 8000)
+    :param user: MongoDB username
+    :param password: MongoDB password
+    :param options: MongoDB connection options
+    :returns: function which makes a postgresql process
+    """
+
+    @pytest.fixture(scope='session')
+    def mongo_noproc_fixture(request: FixtureRequest) -> NoopExecutor:
+        """
+        Noop Process fixture for MongoDB.
+
+        :param FixtureRequest request: fixture request object
+        :returns: tcp executor-like object
+        """
+        config = get_config(request)
+        mongo_host = host or config['host']
+        mongo_port = port or config['port'] or 27017
+
+        noop_exec = NoopExecutor(
+            host=mongo_host,
+            port=mongo_port
+        )
+
+        yield noop_exec
+
+    return mongo_noproc_fixture
+
+
 def mongodb(process_fixture_name, tz_aware=None):
     """
     Mongo database factory.
@@ -140,8 +179,6 @@ def mongodb_factory(request):
         elif config['tz_aware'] is not None \
                 and isinstance(config['tz_aware'], bool):
             mongo_tz_aware = config['tz_aware']
-        if not mongodb_process.running():
-            mongodb_process.start()
 
         mongo_host = mongodb_process.host
         mongo_port = mongodb_process.port
@@ -162,8 +199,9 @@ def mongodb_factory(request):
                 # Do not delete any of Mongo "system" collections
                 if not collection.name.startswith('system.'):
                     collection.drop()
+        mongo_conn.close()
 
     return mongodb_factory
 
 
-__all__ = ('mongodb', 'mongo_proc')
+__all__ = ('mongodb', 'mongo_proc', 'mongo_noproc')
diff --git a/src/pytest_mongo/plugin.py b/src/pytest_mongo/plugin.py
index f734442..4a316bd 100644
--- a/src/pytest_mongo/plugin.py
+++ b/src/pytest_mongo/plugin.py
@@ -115,4 +115,5 @@ def pytest_addoption(parser):
 
 
 mongo_proc = factories.mongo_proc()
+mongo_noproc = factories.mongo_noproc()
 mongodb = factories.mongodb('mongo_proc')
diff --git a/tests/conftest.py b/tests/conftest.py
index 430588d..e907c2e 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -2,7 +2,7 @@
 from pytest_mongo import factories
 
 # pylint:disable=invalid-name
-mongo_params = '--nojournal --noauth --noprealloc'
+mongo_params = '--nojournal --noauth'
 
 mongo_proc2 = factories.mongo_proc(port=27070, params=mongo_params)
 mongodb2 = factories.mongodb('mongo_proc2')
diff --git a/tests/test_noopexecutor.py b/tests/test_noopexecutor.py
new file mode 100644
index 0000000..5a80659
--- /dev/null
+++ b/tests/test_noopexecutor.py
@@ -0,0 +1,28 @@
+"""Test for NoopExecutor."""
+
+import pymongo
+from pytest_mongo.executor_noop import NoopExecutor
+
+
+def test_nooproc_version(mongo_proc):
+    """Test the way mongo version is being read."""
+    mongo_nooproc = NoopExecutor(
+        mongo_proc.host,
+        mongo_proc.port
+    )
+    proc_client = pymongo.MongoClient(
+        host=mongo_proc.host, port=mongo_proc.port
+    )
+    assert proc_client.server_info()['version'] == mongo_nooproc.version
+
+
+def test_nooproc_cached_version(mongo_proc):
+    """Test that the version is being cached."""
+    mongo_nooproc = NoopExecutor(
+        mongo_proc.host,
+        mongo_proc.port
+    )
+    ver = mongo_nooproc.version
+
+    with mongo_proc.stopped():
+        assert ver == mongo_nooproc.version