From d5882075d63fc9209640ebd7e92d60fd3684d6aa Mon Sep 17 00:00:00 2001 From: Noah Stapp Date: Wed, 28 Jun 2023 10:57:23 -0700 Subject: [PATCH] PYTHON-3789 Use tox for Evergreen mockupdb tests (#1277) --- .evergreen/config.yml | 4 +- .evergreen/run-mockupdb-tests.sh | 18 ------ test/mockupdb/test_handshake.py | 97 ++++++++++++++++---------------- tox.ini | 9 +++ 4 files changed, 60 insertions(+), 68 deletions(-) delete mode 100755 .evergreen/run-mockupdb-tests.sh diff --git a/.evergreen/config.yml b/.evergreen/config.yml index f3c159a1d..8fa2df241 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -357,7 +357,9 @@ functions: script: | set -o xtrace ${PREPARE_SHELL} - PYTHON_BINARY=${PYTHON_BINARY} bash ${PROJECT_DIRECTORY}/.evergreen/run-mockupdb-tests.sh + + alias python=${PYTHON_BINARY} + python -m tox -e test-mockupdb "run doctests": - command: shell.exec diff --git a/.evergreen/run-mockupdb-tests.sh b/.evergreen/run-mockupdb-tests.sh deleted file mode 100755 index a76ed6316..000000000 --- a/.evergreen/run-mockupdb-tests.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# Must be run from pymongo repo root -set -o xtrace -set -o errexit - -. .evergreen/utils.sh - -${PYTHON_BINARY} setup.py clean - -createvirtualenv ${PYTHON_BINARY} mockuptests -trap "deactivate; rm -rf mockuptests" EXIT HUP - -# Install PyMongo from git clone so mockup-tests don't -# download it from pypi. -python -m pip install . -python -m pip install --upgrade 'https://github.com/ajdavis/mongo-mockup-db/archive/master.zip' -cd ./test/mockupdb -python -m unittest discover -v diff --git a/test/mockupdb/test_handshake.py b/test/mockupdb/test_handshake.py index d3f8922c4..883d518f5 100644 --- a/test/mockupdb/test_handshake.py +++ b/test/mockupdb/test_handshake.py @@ -23,49 +23,6 @@ from pymongo.errors import OperationFailure from pymongo.server_api import ServerApi, ServerApiVersion -def test_hello_with_option(self, protocol, **kwargs): - hello = "ismaster" if isinstance(protocol(), OpQuery) else "hello" - # `db.command("hello"|"ismaster")` commands are the same for primaries and - # secondaries, so we only need one server. - primary = MockupDB() - # Set up a custom handler to save the first request from the driver. - self.handshake_req = None - - def respond(r): - # Only save the very first request from the driver. - if self.handshake_req is None: - self.handshake_req = r - load_balanced_kwargs = {"serviceId": ObjectId()} if kwargs.get("loadBalanced") else {} - return r.reply( - OpMsgReply(minWireVersion=0, maxWireVersion=13, **kwargs, **load_balanced_kwargs) - ) - - primary.autoresponds(respond) - primary.run() - self.addCleanup(primary.stop) - - # We need a special dict because MongoClient uses "server_api" and all - # of the commands use "apiVersion". - k_map = {("apiVersion", "1"): ("server_api", ServerApi(ServerApiVersion.V1))} - client = MongoClient( - "mongodb://" + primary.address_string, - appname="my app", # For _check_handshake_data() - **dict([k_map.get((k, v), (k, v)) for k, v in kwargs.items()]) # type: ignore[arg-type] - ) - - self.addCleanup(client.close) - - # We have an autoresponder luckily, so no need for `go()`. - assert client.db.command(hello) - - # We do this checking here rather than in the autoresponder `respond()` - # because it runs in another Python thread so there are some funky things - # with error handling within that thread, and we want to be able to use - # self.assertRaises(). - self.handshake_req.assert_matches(protocol(hello, **kwargs)) - _check_handshake_data(self.handshake_req) - - def _check_handshake_data(request): assert "client" in request data = request["client"] @@ -79,6 +36,48 @@ def _check_handshake_data(request): class TestHandshake(unittest.TestCase): + def hello_with_option_helper(self, protocol, **kwargs): + hello = "ismaster" if isinstance(protocol(), OpQuery) else "hello" + # `db.command("hello"|"ismaster")` commands are the same for primaries and + # secondaries, so we only need one server. + primary = MockupDB() + # Set up a custom handler to save the first request from the driver. + self.handshake_req = None + + def respond(r): + # Only save the very first request from the driver. + if self.handshake_req is None: + self.handshake_req = r + load_balanced_kwargs = {"serviceId": ObjectId()} if kwargs.get("loadBalanced") else {} + return r.reply( + OpMsgReply(minWireVersion=0, maxWireVersion=13, **kwargs, **load_balanced_kwargs) + ) + + primary.autoresponds(respond) + primary.run() + self.addCleanup(primary.stop) + + # We need a special dict because MongoClient uses "server_api" and all + # of the commands use "apiVersion". + k_map = {("apiVersion", "1"): ("server_api", ServerApi(ServerApiVersion.V1))} + client = MongoClient( + "mongodb://" + primary.address_string, + appname="my app", # For _check_handshake_data() + **dict([k_map.get((k, v), (k, v)) for k, v in kwargs.items()]) # type: ignore[arg-type] + ) + + self.addCleanup(client.close) + + # We have an autoresponder luckily, so no need for `go()`. + assert client.db.command(hello) + + # We do this checking here rather than in the autoresponder `respond()` + # because it runs in another Python thread so there are some funky things + # with error handling within that thread, and we want to be able to use + # self.assertRaises(). + self.handshake_req.assert_matches(protocol(hello, **kwargs)) + _check_handshake_data(self.handshake_req) + def test_client_handshake_data(self): primary, secondary = MockupDB(), MockupDB() for server in primary, secondary: @@ -208,21 +207,21 @@ class TestHandshake(unittest.TestCase): return def test_handshake_load_balanced(self): - test_hello_with_option(self, OpMsg, loadBalanced=True) + self.hello_with_option_helper(OpMsg, loadBalanced=True) with self.assertRaisesRegex(AssertionError, "does not match"): - test_hello_with_option(self, Command, loadBalanced=True) + self.hello_with_option_helper(Command, loadBalanced=True) def test_handshake_versioned_api(self): - test_hello_with_option(self, OpMsg, apiVersion="1") + self.hello_with_option_helper(OpMsg, apiVersion="1") with self.assertRaisesRegex(AssertionError, "does not match"): - test_hello_with_option(self, Command, apiVersion="1") + self.hello_with_option_helper(Command, apiVersion="1") def test_handshake_not_either(self): # If we don't specify either option then it should be using # OP_QUERY for the initial step of the handshake. - test_hello_with_option(self, Command) + self.hello_with_option_helper(Command) with self.assertRaisesRegex(AssertionError, "does not match"): - test_hello_with_option(self, OpMsg) + self.hello_with_option_helper(OpMsg) def test_handshake_max_wire(self): server = MockupDB() diff --git a/tox.ini b/tox.ini index ba53a2011..bdabf1770 100644 --- a/tox.ini +++ b/tox.ini @@ -121,3 +121,12 @@ deps = {[testenv:doc]deps} commands = sphinx-build -E -b linkcheck doc ./doc/_build/linkcheck + +[testenv:test-mockupdb] +description = run mockupdb tests +deps = + {[testenv:test]deps} + https://github.com/ajdavis/mongo-mockup-db/archive/master.zip +passenv = * +commands = + python -m pytest -v ./test/mockupdb