From 7dcfafa9b19baec8aaa70655bc177ae8d33e477e Mon Sep 17 00:00:00 2001 From: Gracjan Sadowicz Date: Thu, 23 Jul 2026 01:33:42 +0200 Subject: [PATCH 01/16] RavenDB-27069 Add attach-to-external-server mode to the test driver configure_external_server(url) / RAVENDB_TEST_SERVER_URL make run_server attach to an existing server instead of booting the embedded one, so tests need no .NET (good for Docker/testcontainers CI). Database-per-test isolation and wait_for_indexing are unchanged. Also inlines the removed CommandLineArgumentEscaper no-op. --- ravendb_test_driver/raven_test_driver.py | 27 +++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/ravendb_test_driver/raven_test_driver.py b/ravendb_test_driver/raven_test_driver.py index b78d36f..08bb6a4 100644 --- a/ravendb_test_driver/raven_test_driver.py +++ b/ravendb_test_driver/raven_test_driver.py @@ -25,7 +25,6 @@ from ravendb.serverwide.database_record import DatabaseRecord from ravendb.serverwide.operations.common import DeleteDatabaseOperation from ravendb_embedded import EmbeddedServer, ServerOptions -from ravendb_embedded.raven_server_runner import CommandLineArgumentEscaper from ravendb_test_driver.options import GetDocumentStoreOptions @@ -36,6 +35,7 @@ class RavenTestDriver: _INDEX = 0 _GLOBAL_SERVER_OPTIONS: Optional[ServerOptions] = None _EMPTY_SETTINGS_FILE_NAME: Optional[str] = None + _EXTERNAL_SERVER_URL: Optional[str] = None def __init__(self) -> None: self.disposed = False @@ -66,6 +66,19 @@ def configure_server(options: ServerOptions) -> None: ) RavenTestDriver._GLOBAL_SERVER_OPTIONS = options + @staticmethod + def configure_external_server(url: str) -> None: + # Attach to a server you run yourself (Docker, testcontainers, a shared CI service) + # instead of booting the embedded one, so no .NET is needed on the machine. The driver + # still gives every test its own database. Also settable via the + # RAVENDB_TEST_SERVER_URL environment variable. Call before the first get_document_store. + if RavenTestDriver._TEST_SERVER_STORE.is_value_created: + raise RuntimeError( + "Cannot configure the server after it was started. " + "Call 'configure_external_server' before any 'get_document_store'." + ) + RavenTestDriver._EXTERNAL_SERVER_URL = url + def get_document_store( self, options: Optional[GetDocumentStoreOptions] = None, @@ -232,16 +245,20 @@ def cleanup_temp_dirs() -> None: @classmethod def run_server(cls) -> DocumentStore: + external_url = cls._EXTERNAL_SERVER_URL or os.environ.get("RAVENDB_TEST_SERVER_URL") + if external_url: + # Attach to an existing server; do not boot the embedded one (no .NET needed). + store = DocumentStore(external_url, None) + store.initialize() + return store + try: options = RavenTestDriver._GLOBAL_SERVER_OPTIONS or RavenTestDriver.default_server_options() command_line_args = options.command_line_args command_line_args.insert(0, "-c") - command_line_args.insert( - 1, - CommandLineArgumentEscaper.escape_single_arg(RavenTestDriver._get_empty_settings_file()), - ) + command_line_args.insert(1, RavenTestDriver._get_empty_settings_file()) except Exception as e: raise RavenException(f"Unable to start server: {e}") From 2f9270d154fe530eafe6e6da7799b229fff6527b Mon Sep 17 00:00:00 2001 From: Gracjan Sadowicz Date: Thu, 23 Jul 2026 01:40:12 +0200 Subject: [PATCH 02/16] RavenDB-27069 CI: net10-only embedded job + Dockerized attach (path C) job The bundled 7.2 server is net10.0, so the embedded job installs .NET 10 (was a fake .NET 8). A new 'attach' job runs a RavenDB service container and points the driver at it with NO .NET, proving the attach path end-to-end (verified locally against ravendb/ravendb:7.2-ubuntu-latest). --- .github/workflows/tests.yml | 57 ++++++++++++++++++++++++++++++------- tests/test_attach.py | 32 +++++++++++++++++++++ 2 files changed, 78 insertions(+), 11 deletions(-) create mode 100644 tests/test_attach.py diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b1ff8b5..a710aee 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,30 +8,28 @@ on: workflow_dispatch: jobs: - test: + embedded: + # Path A: the driver boots the embedded server (a .NET app). The 7.2 server targets + # net10.0, so install .NET 10 explicitly (7.1 was net8.0). The attach test skips here + # (no RAVENDB_TEST_SERVER_URL). runs-on: ${{ matrix.os }} strategy: fail-fast: false - # Latest Python only (the ravendb client requires 3.10+); covers ubuntu + windows. matrix: - include: - - { os: ubuntu-latest, python: "3.13" } - - { os: windows-latest, python: "3.13" } + os: [ubuntu-latest, windows-latest] steps: - uses: actions/checkout@v4 - - name: Set up Python ${{ matrix.python }} + - name: Set up Python 3.13 uses: actions/setup-python@v5 with: - python-version: ${{ matrix.python }} + python-version: "3.13" - # The test driver runs the embedded RavenDB server (a .NET application); - # the server binaries ship inside the ravendb-embedded dependency wheel. - - name: Set up .NET 8 + - name: Set up .NET 10 uses: actions/setup-dotnet@v4 with: - dotnet-version: "8.0" + dotnet-version: "10.0" - name: Install package run: | @@ -45,3 +43,40 @@ jobs: - name: Run tests run: python -m unittest discover -s tests + + attach: + # Path C: attach to a RavenDB server running in Docker, with NO .NET installed. Proves the + # driver needs no runtime when it does not boot the embedded server. + runs-on: ubuntu-latest + services: + ravendb: + image: ravendb/ravendb:7.2-ubuntu-latest + ports: + - 8080:8080 + env: + RAVEN_Setup_Mode: None + RAVEN_License_Eula_Accepted: "true" + RAVEN_Security_UnsecuredAccessAllowed: PublicNetwork + RAVEN_ServerUrl: http://0.0.0.0:8080 + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python 3.13 + uses: actions/setup-python@v5 + with: + python-version: "3.13" + + - name: Install package + run: | + python -m pip install --upgrade pip + pip install -e . + + - name: Wait for RavenDB + run: curl --retry 60 --retry-delay 2 --retry-all-errors -sf http://localhost:8080/build/version + + - name: Attach test (path C, no .NET) + env: + RAVENDB_TEST_SERVER_URL: http://localhost:8080 + RAVENDB_TEST_REQUIRE_ATTACH: "1" + run: python -m unittest tests.test_attach -v diff --git a/tests/test_attach.py b/tests/test_attach.py new file mode 100644 index 0000000..8ac4445 --- /dev/null +++ b/tests/test_attach.py @@ -0,0 +1,32 @@ +import os +import unittest +from unittest import TestCase + +from ravendb_test_driver import RavenTestDriver + +# Path C: attach to a server you run yourself (Docker, testcontainers, shared CI) instead of +# booting the embedded one, so no .NET is needed. Point RAVENDB_TEST_SERVER_URL at a running +# server to run this. It must run in its own process (the driver's server is a process-wide +# singleton), which is exactly how CI invokes it. CI also sets RAVENDB_TEST_REQUIRE_ATTACH=1 so +# a missing URL fails loudly there instead of skipping silently. +SERVER_URL = os.environ.get("RAVENDB_TEST_SERVER_URL") +_REQUIRE = os.environ.get("RAVENDB_TEST_REQUIRE_ATTACH") == "1" + + +class TestAttachToExternalServer(TestCase): + def setUp(self): + if not SERVER_URL: + message = "set RAVENDB_TEST_SERVER_URL to a running server to run the attach test" + if _REQUIRE: + self.fail(message) + self.skipTest(message) + + def test_attach_gives_isolated_database(self): + driver = RavenTestDriver() + with driver.get_document_store() as store: + self.assertIn(SERVER_URL.rstrip("/"), store.urls[0]) + with store.open_session() as session: + session.store({"name": "attached"}, "people/1") + session.save_changes() + with store.open_session() as session: + self.assertEqual("attached", session.load("people/1", dict)["name"]) From f8617bd46affbb421f7f2d4c9de4d565791a195d Mon Sep 17 00:00:00 2001 From: Gracjan Sadowicz Date: Thu, 23 Jul 2026 01:40:12 +0200 Subject: [PATCH 03/16] RavenDB-27069 Require Python >=3.10 (ravendb client cannot import on 3.9) --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 3923ff2..4e19b2f 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ url="https://github.com/ravendb/ravendb-python-testdriver", license="MIT", keywords=["ravendb", "nosql", "database", "test", "driver"], - python_requires="~=3.9", + python_requires=">=3.10", license_files="LICENSE", install_requires=["ravendb-embedded==7.2.3", "ravendb~=7.2.3"], ) From ccbad205c0dc70805c894fd9a8404356345d91b6 Mon Sep 17 00:00:00 2001 From: Gracjan Sadowicz Date: Thu, 23 Jul 2026 01:42:00 +0200 Subject: [PATCH 04/16] RavenDB-27069 Add Lab 03: attach to a self-run server (Docker/testcontainers), path C --- labs/03-attach-to-server.md | 77 +++++++++++++++++++++++++++++++++++++ labs/03_attach_to_server.py | 44 +++++++++++++++++++++ labs/README.md | 14 +++++++ 3 files changed, 135 insertions(+) create mode 100644 labs/03-attach-to-server.md create mode 100644 labs/03_attach_to_server.py create mode 100644 labs/README.md diff --git a/labs/03-attach-to-server.md b/labs/03-attach-to-server.md new file mode 100644 index 0000000..d1caa49 --- /dev/null +++ b/labs/03-attach-to-server.md @@ -0,0 +1,77 @@ +# Lab 03: Attach to a server you run yourself + +**For:** containerized CI, or anyone who does not want the driver to boot the embedded server +(and therefore wants no .NET on the machine). You run RavenDB yourself (Docker, testcontainers, +a shared CI service) and point the driver at its URL. The driver still creates a fresh, isolated +database per test and cleans it up afterwards. + +## Point the driver at a server + +Two equivalent ways: + +```python +from ravendb_test_driver import RavenTestDriver + +# 1. Explicit, before the first get_document_store(): +RavenTestDriver.configure_external_server("http://localhost:8080") + +# 2. Or set an environment variable (nice for CI): +# RAVENDB_TEST_SERVER_URL=http://localhost:8080 +``` + +Then use the driver exactly as with the embedded server: + +```python +with RavenTestDriver() as driver: + with driver.get_document_store() as store: # isolated database on the attached server + ... +``` + +The complete runnable example is [`03_attach_to_server.py`](03_attach_to_server.py). + +## Run a server with Docker + +```bash +docker run -d -p 8080:8080 \ + -e RAVEN_Setup_Mode=None -e RAVEN_License_Eula_Accepted=true \ + -e RAVEN_Security_UnsecuredAccessAllowed=PublicNetwork -e RAVEN_ServerUrl=http://0.0.0.0:8080 \ + ravendb/ravendb:7.2-ubuntu-latest + +RAVENDB_TEST_SERVER_URL=http://localhost:8080 python labs/03_attach_to_server.py +``` + +## Run a server with testcontainers-python + +There is no dedicated RavenDB module yet, so use the generic container: + +```python +from testcontainers.core.container import DockerContainer +from testcontainers.core.waiting_utils import wait_for_logs + +raven = ( + DockerContainer("ravendb/ravendb:7.2-ubuntu-latest") + .with_env("RAVEN_Setup_Mode", "None") + .with_env("RAVEN_License_Eula_Accepted", "true") + .with_env("RAVEN_Security_UnsecuredAccessAllowed", "PublicNetwork") + .with_env("RAVEN_ServerUrl", "http://0.0.0.0:8080") + .with_exposed_ports(8080) +) +raven.start() +wait_for_logs(raven, "Server available on") +url = f"http://{raven.get_container_host_ip()}:{raven.get_exposed_port(8080)}" + +from ravendb_test_driver import RavenTestDriver +RavenTestDriver.configure_external_server(url) +``` + +## In CI + +This repo's own CI uses a GitHub Actions service container (see `.github/workflows/tests.yml`, +the `attach` job): it runs `ravendb/ravendb:7.2-ubuntu-latest`, waits for it, then runs the +attach test with `RAVENDB_TEST_SERVER_URL` set and no .NET installed. + +## Takeaway + +No embedded server and no .NET, at the cost of running RavenDB yourself. For the embedded +options (with or without .NET), see the labs in the `ravendb-python-embedded` repository +(Lab 01 and Lab 02). diff --git a/labs/03_attach_to_server.py b/labs/03_attach_to_server.py new file mode 100644 index 0000000..ec9a08b --- /dev/null +++ b/labs/03_attach_to_server.py @@ -0,0 +1,44 @@ +"""Lab 03: Attach to a server you run yourself (Docker / testcontainers / shared CI). + +For: containerized CI, or any setup where you do NOT want the driver to boot the embedded +server (so you need no .NET). You run RavenDB yourself and point the driver at its URL; the +driver still gives every test its own isolated database. + +Start a server, for example with Docker: + docker run -d -p 8080:8080 \ + -e RAVEN_Setup_Mode=None -e RAVEN_License_Eula_Accepted=true \ + -e RAVEN_Security_UnsecuredAccessAllowed=PublicNetwork -e RAVEN_ServerUrl=http://0.0.0.0:8080 \ + ravendb/ravendb:7.2-ubuntu-latest + +Then run: + RAVENDB_TEST_SERVER_URL=http://localhost:8080 python labs/03_attach_to_server.py +""" + +import os +import sys + +from ravendb_test_driver import RavenTestDriver + +URL = os.environ.get("RAVENDB_TEST_SERVER_URL") or (sys.argv[1] if len(sys.argv) > 1 else None) +if not URL: + sys.exit("Set RAVENDB_TEST_SERVER_URL (or pass a URL) to a running RavenDB server. See the header.") + + +def main() -> None: + # Attach explicitly (equivalent to setting RAVENDB_TEST_SERVER_URL); call before the + # first get_document_store. + RavenTestDriver.configure_external_server(URL) + + with RavenTestDriver() as driver: + with driver.get_document_store() as store: # a fresh, isolated database on the attached server + with store.open_session() as session: + session.store({"name": "Ayende"}, "people/1") + session.save_changes() + with store.open_session() as session: + assert session.load("people/1", dict)["name"] == "Ayende" + + print("Lab 03 OK: attached to an external server, no embedded boot and no .NET.") + + +if __name__ == "__main__": + main() diff --git a/labs/README.md b/labs/README.md new file mode 100644 index 0000000..598ec20 --- /dev/null +++ b/labs/README.md @@ -0,0 +1,14 @@ +# ravendb-test-driver: server labs + +Ways to provide a RavenDB server for your tests, from most convenient to most portable. + +| Lab | Path | For whom | Needs system .NET? | +|-----|------|----------|--------------------| +| [03](03-attach-to-server.md) | Attach to a server you run yourself (Docker, testcontainers, shared CI) | Containerized CI pipelines | No | + +The embedded options live in the `ravendb-python-embedded` repository: + +- Lab 01 - embedded, zero-config (needs a system .NET) +- Lab 02 - external self-contained server (no .NET) + +Every lab ships a runnable script next to it, so you can run the exact code the guide shows. From b50bee24455761f3dcad794ffa2b35c7e1ee5e1d Mon Sep 17 00:00:00 2001 From: Gracjan Sadowicz Date: Thu, 23 Jul 2026 01:43:10 +0200 Subject: [PATCH 05/16] RavenDB-27069 Document .NET requirement, Python 3.10+, and the attach option (link Lab 03) --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index 2427285..685dfdb 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,27 @@ Install from PyPi: `pip install ravendb-test-driver` +### Requirements + +Python 3.10+ is required. + +By default the driver boots an **embedded** RavenDB server, which is a .NET application, so a matching .NET runtime must be installed: + +- `ravendb-test-driver` 7.2.x requires **.NET 10** +- `ravendb-test-driver` 7.1.x requires **.NET 8** + +If you would rather not manage .NET, attach the driver to a server you run yourself (Docker, testcontainers, a shared CI service), with no runtime on the machine: + +```python +from ravendb_test_driver import RavenTestDriver + +RavenTestDriver.configure_external_server("http://localhost:8080") +# or set the RAVENDB_TEST_SERVER_URL environment variable +``` + +Each test still gets its own database. See [`labs/03-attach-to-server.md`](labs/03-attach-to-server.md) for a runnable Docker / testcontainers guide (and the `ravendb-python-embedded` repo for the embedded and self-contained options). + + ### Usage Inherit `RavenTestDriver` to your test class or create an instance within your class. From 2b15bc2e954b87c98e3e34e91c315b35c13b200c Mon Sep 17 00:00:00 2001 From: Gracjan Sadowicz Date: Thu, 23 Jul 2026 02:06:19 +0200 Subject: [PATCH 06/16] RavenDB-27069 Fix stale .gitignore package name (ravendb_testdriver -> ravendb_test_driver) --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 3a67088..db43a53 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ /.idea /test.py /dist -/ravendb_testdriver.egg-info -/ravendb_testdriver/target +/ravendb_test_driver.egg-info +/ravendb_test_driver/target *.pyc *.log *.raven-topology From c13437f02ca1063ea95a8b90045173eb8d15117c Mon Sep 17 00:00:00 2001 From: Gracjan Sadowicz Date: Thu, 23 Jul 2026 02:36:48 +0200 Subject: [PATCH 07/16] RavenDB-27069 Trim comments to critical one-liners; drop unused import --- ravendb_test_driver/raven_test_driver.py | 8 ++++---- tests/test_attach.py | 11 +++++------ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/ravendb_test_driver/raven_test_driver.py b/ravendb_test_driver/raven_test_driver.py index 08bb6a4..12d103c 100644 --- a/ravendb_test_driver/raven_test_driver.py +++ b/ravendb_test_driver/raven_test_driver.py @@ -68,10 +68,10 @@ def configure_server(options: ServerOptions) -> None: @staticmethod def configure_external_server(url: str) -> None: - # Attach to a server you run yourself (Docker, testcontainers, a shared CI service) - # instead of booting the embedded one, so no .NET is needed on the machine. The driver - # still gives every test its own database. Also settable via the - # RAVENDB_TEST_SERVER_URL environment variable. Call before the first get_document_store. + """Attach to a server you run yourself (no embedded boot, no .NET); still one database per test. + + Equivalent to setting RAVENDB_TEST_SERVER_URL. Call before the first get_document_store. + """ if RavenTestDriver._TEST_SERVER_STORE.is_value_created: raise RuntimeError( "Cannot configure the server after it was started. " diff --git a/tests/test_attach.py b/tests/test_attach.py index 8ac4445..c1ac567 100644 --- a/tests/test_attach.py +++ b/tests/test_attach.py @@ -1,14 +1,13 @@ +"""Attach path (no embedded boot, no .NET): point RAVENDB_TEST_SERVER_URL at a running server. + +Skips when unset, unless RAVENDB_TEST_REQUIRE_ATTACH=1 (CI) makes a missing URL fail loudly. +""" + import os -import unittest from unittest import TestCase from ravendb_test_driver import RavenTestDriver -# Path C: attach to a server you run yourself (Docker, testcontainers, shared CI) instead of -# booting the embedded one, so no .NET is needed. Point RAVENDB_TEST_SERVER_URL at a running -# server to run this. It must run in its own process (the driver's server is a process-wide -# singleton), which is exactly how CI invokes it. CI also sets RAVENDB_TEST_REQUIRE_ATTACH=1 so -# a missing URL fails loudly there instead of skipping silently. SERVER_URL = os.environ.get("RAVENDB_TEST_SERVER_URL") _REQUIRE = os.environ.get("RAVENDB_TEST_REQUIRE_ATTACH") == "1" From d0249427af63d1e800794c6dde6992538b23f2e0 Mon Sep 17 00:00:00 2001 From: Gracjan Sadowicz Date: Thu, 23 Jul 2026 02:40:06 +0200 Subject: [PATCH 08/16] RavenDB-27069 Rewrite README around usage cases (why/how + link labs) --- README.md | 85 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 685dfdb..a16b63d 100644 --- a/README.md +++ b/README.md @@ -1,59 +1,88 @@ -## RavenDB Test Driver +# RavenDB Test Driver -`ravendb-test-driver` is a package for writing integration tests against RavenDB server. +`ravendb-test-driver` runs your integration tests against a **real** RavenDB server instead of a +mock. Each test gets its own isolated database, created on demand and torn down afterwards, so +tests do not leak state into one another. You write ordinary `ravendb` client code; the driver +handles the server and the per-test database lifecycle. -### Setup +## Install -Install from PyPi: +```bash +pip install ravendb-test-driver +``` + +Python 3.10+ is required. -`pip install ravendb-test-driver` +## Providing a server: pick one +The driver needs a RavenDB server to talk to. There are two ways to give it one; choose based on +whether you want .NET on the test machine. -### Requirements +### 1. Embedded server (default, needs .NET) -Python 3.10+ is required. +Out of the box the driver boots an **embedded** RavenDB server (via `ravendb-embedded`). Nothing +to configure, but the embedded server is a .NET application, so a matching runtime must be +installed: -By default the driver boots an **embedded** RavenDB server, which is a .NET application, so a matching .NET runtime must be installed: +| `ravendb-test-driver` version | Required runtime | +|-------------------------------|------------------| +| 7.2.x | .NET 10 | +| 7.1.x | .NET 8 | -- `ravendb-test-driver` 7.2.x requires **.NET 10** -- `ravendb-test-driver` 7.1.x requires **.NET 8** +Check with `dotnet --list-runtimes`. The requirement tracks the embedded server and can change on +a minor upgrade, so re-check it when you bump versions. -If you would rather not manage .NET, attach the driver to a server you run yourself (Docker, testcontainers, a shared CI service), with no runtime on the machine: +### 2. Attach to a server you run yourself (no .NET) + +If you would rather not put .NET on the test machine (containerized CI, locked-down hosts), run +RavenDB yourself (Docker, testcontainers, a shared CI service) and point the driver at its URL. +The driver skips the embedded boot entirely and still creates an isolated database per test. ```python from ravendb_test_driver import RavenTestDriver RavenTestDriver.configure_external_server("http://localhost:8080") -# or set the RAVENDB_TEST_SERVER_URL environment variable +# or set RAVENDB_TEST_SERVER_URL in the environment (handy for CI) ``` -Each test still gets its own database. See [`labs/03-attach-to-server.md`](labs/03-attach-to-server.md) for a runnable Docker / testcontainers guide (and the `ravendb-python-embedded` repo for the embedded and self-contained options). - - -### Usage +Call it once, before the first `get_document_store()`. A runnable Docker / testcontainers guide +is in [`labs/03-attach-to-server.md`](labs/03-attach-to-server.md). For the embedded and +self-contained server options, see the +[`ravendb-python-embedded`](https://github.com/ravendb/ravendb-python-embedded) repository. -Inherit `RavenTestDriver` to your test class or create an instance within your class. +## Usage -Unittest example: +Subclass `RavenTestDriver` (or hold an instance) and call `get_document_store()` in each test to +get a store backed by a fresh database: ```python -from ravendb_test_driver import RavenTestDriver from unittest import TestCase +from ravendb_test_driver import RavenTestDriver + class TestBasic(TestCase): def setUp(self): - super().setUp() self.test_driver = RavenTestDriver() - def test_1(self): - with self.test_driver.get_document_store() as store: + def test_stores_a_document(self): + with self.test_driver.get_document_store() as store: # isolated database with store.open_session() as session: - person = {"Name": "John"} - session.store(person, "people1") + session.store({"Name": "John"}, "people/1") session.save_changes() ``` -### PyPi -https://pypi.org/project/ravendb-test-driver/ -### Github -https://github.com/ravendb/ravendb-python-testdriver +### Seeding data and waiting for indexes + +- Override `setup_database(self, store)` to seed or configure every database the driver hands + out (indexes, reference data, and so on). +- `get_document_store(options)` accepts `GetDocumentStoreOptions`; set a + `wait_for_indexing_timeout` to block until indexing settles, or call + `wait_for_indexing(store)` yourself. +- `wait_for_user_to_continue_the_test(store)` opens RavenDB Studio so you can inspect the data + mid-test. + +## Links + +- PyPI: https://pypi.org/project/ravendb-test-driver/ +- GitHub: https://github.com/ravendb/ravendb-python-testdriver +- Server and self-contained options: https://github.com/ravendb/ravendb-python-embedded From bd8e05d7ba22ad82c62e8c98a2a9e562840714b4 Mon Sep 17 00:00:00 2001 From: Gracjan Sadowicz Date: Thu, 23 Jul 2026 03:43:56 +0200 Subject: [PATCH 09/16] RavenDB-27069 Bump to 7.2.5; pin deps (ravendb-embedded==7.2.3 published, ravendb==7.2.3.post1) --- setup.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 4e19b2f..a87be8f 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name="ravendb-test-driver", packages=find_packages(exclude=["*.tests.*", "tests", "*.tests", "tests.*"]), - version="7.2.3", + version="7.2.5", description="RavenDB package for writing integration tests against RavenDB server", long_description_content_type="text/markdown", long_description=open("README.md").read(), @@ -14,5 +14,7 @@ keywords=["ravendb", "nosql", "database", "test", "driver"], python_requires=">=3.10", license_files="LICENSE", - install_requires=["ravendb-embedded==7.2.3", "ravendb~=7.2.3"], + # ravendb-embedded pinned to the latest PUBLISHED release; Dependabot bumps it to 7.2.5 once + # that is on PyPI (embedded and this package release together, embedded first). + install_requires=["ravendb-embedded==7.2.3", "ravendb==7.2.3.post1"], ) From 7e1ed38bd8a4d7f919bd608af5e3534c11282985 Mon Sep 17 00:00:00 2001 From: Gracjan Sadowicz Date: Thu, 23 Jul 2026 03:43:56 +0200 Subject: [PATCH 10/16] RavenDB-27069 Pin GitHub Actions to commit SHA; add Dependabot (actions + pip) --- .github/dependabot.yml | 15 +++++++++++++++ .github/workflows/tests.yml | 10 +++++----- 2 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..b8a5b00 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,15 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + groups: + github-actions: + patterns: + - "*" + + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a710aee..63cb67b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -19,15 +19,15 @@ jobs: os: [ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - name: Set up Python 3.13 - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: "3.13" - name: Set up .NET 10 - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 with: dotnet-version: "10.0" @@ -60,10 +60,10 @@ jobs: RAVEN_ServerUrl: http://0.0.0.0:8080 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - name: Set up Python 3.13 - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: "3.13" From 63f2642aee47d41a7931993bd97c9dacfa8bc178 Mon Sep 17 00:00:00 2001 From: Gracjan Sadowicz Date: Thu, 23 Jul 2026 03:49:42 +0200 Subject: [PATCH 11/16] RavenDB-27069 Give test-driver its own lab numbering (attach = Lab 01) --- README.md | 2 +- ...ch-to-server.md => 01-attach-to-server.md} | 12 +++++------ ...ch_to_server.py => 01_attach_to_server.py} | 6 +++--- labs/README.md | 20 +++++++++---------- 4 files changed, 19 insertions(+), 21 deletions(-) rename labs/{03-attach-to-server.md => 01-attach-to-server.md} (87%) rename labs/{03_attach_to_server.py => 01_attach_to_server.py} (88%) diff --git a/README.md b/README.md index a16b63d..964221d 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ RavenTestDriver.configure_external_server("http://localhost:8080") ``` Call it once, before the first `get_document_store()`. A runnable Docker / testcontainers guide -is in [`labs/03-attach-to-server.md`](labs/03-attach-to-server.md). For the embedded and +is in [`labs/01-attach-to-server.md`](labs/01-attach-to-server.md). For the embedded and self-contained server options, see the [`ravendb-python-embedded`](https://github.com/ravendb/ravendb-python-embedded) repository. diff --git a/labs/03-attach-to-server.md b/labs/01-attach-to-server.md similarity index 87% rename from labs/03-attach-to-server.md rename to labs/01-attach-to-server.md index d1caa49..c93d14a 100644 --- a/labs/03-attach-to-server.md +++ b/labs/01-attach-to-server.md @@ -1,4 +1,4 @@ -# Lab 03: Attach to a server you run yourself +# Lab 01: Attach to a server you run yourself **For:** containerized CI, or anyone who does not want the driver to boot the embedded server (and therefore wants no .NET on the machine). You run RavenDB yourself (Docker, testcontainers, @@ -27,7 +27,7 @@ with RavenTestDriver() as driver: ... ``` -The complete runnable example is [`03_attach_to_server.py`](03_attach_to_server.py). +The complete runnable example is [`01_attach_to_server.py`](01_attach_to_server.py). ## Run a server with Docker @@ -37,7 +37,7 @@ docker run -d -p 8080:8080 \ -e RAVEN_Security_UnsecuredAccessAllowed=PublicNetwork -e RAVEN_ServerUrl=http://0.0.0.0:8080 \ ravendb/ravendb:7.2-ubuntu-latest -RAVENDB_TEST_SERVER_URL=http://localhost:8080 python labs/03_attach_to_server.py +RAVENDB_TEST_SERVER_URL=http://localhost:8080 python labs/01_attach_to_server.py ``` ## Run a server with testcontainers-python @@ -72,6 +72,6 @@ attach test with `RAVENDB_TEST_SERVER_URL` set and no .NET installed. ## Takeaway -No embedded server and no .NET, at the cost of running RavenDB yourself. For the embedded -options (with or without .NET), see the labs in the `ravendb-python-embedded` repository -(Lab 01 and Lab 02). +No embedded server and no .NET, at the cost of running RavenDB yourself. If you would rather +have the driver run the server for you (with or without .NET), see the embedded options in the +`ravendb-python-embedded` repository. diff --git a/labs/03_attach_to_server.py b/labs/01_attach_to_server.py similarity index 88% rename from labs/03_attach_to_server.py rename to labs/01_attach_to_server.py index ec9a08b..3157822 100644 --- a/labs/03_attach_to_server.py +++ b/labs/01_attach_to_server.py @@ -1,4 +1,4 @@ -"""Lab 03: Attach to a server you run yourself (Docker / testcontainers / shared CI). +"""Lab 01: Attach to a server you run yourself (Docker / testcontainers / shared CI). For: containerized CI, or any setup where you do NOT want the driver to boot the embedded server (so you need no .NET). You run RavenDB yourself and point the driver at its URL; the @@ -11,7 +11,7 @@ ravendb/ravendb:7.2-ubuntu-latest Then run: - RAVENDB_TEST_SERVER_URL=http://localhost:8080 python labs/03_attach_to_server.py + RAVENDB_TEST_SERVER_URL=http://localhost:8080 python labs/01_attach_to_server.py """ import os @@ -37,7 +37,7 @@ def main() -> None: with store.open_session() as session: assert session.load("people/1", dict)["name"] == "Ayende" - print("Lab 03 OK: attached to an external server, no embedded boot and no .NET.") + print("Lab 01 OK: attached to an external server, no embedded boot and no .NET.") if __name__ == "__main__": diff --git a/labs/README.md b/labs/README.md index 598ec20..e4a0dc4 100644 --- a/labs/README.md +++ b/labs/README.md @@ -1,14 +1,12 @@ -# ravendb-test-driver: server labs +# ravendb-test-driver: labs -Ways to provide a RavenDB server for your tests, from most convenient to most portable. +Runnable, self-checking guides for using the test driver. Each lab ships a script next to it, so +you can run the exact code the guide shows. -| Lab | Path | For whom | Needs system .NET? | -|-----|------|----------|--------------------| -| [03](03-attach-to-server.md) | Attach to a server you run yourself (Docker, testcontainers, shared CI) | Containerized CI pipelines | No | +| Lab | Covers | Needs system .NET? | +|-----|--------|--------------------| +| [01](01-attach-to-server.md) | Attach to a server you run yourself (Docker, testcontainers, shared CI) | No | -The embedded options live in the `ravendb-python-embedded` repository: - -- Lab 01 - embedded, zero-config (needs a system .NET) -- Lab 02 - external self-contained server (no .NET) - -Every lab ships a runnable script next to it, so you can run the exact code the guide shows. +Looking for how to run RavenDB itself (embedded, or self-contained without .NET)? That belongs to +the [`ravendb-python-embedded`](https://github.com/ravendb/ravendb-python-embedded) package and +has its own labs there. From 025c92eb3d707110f1d5618283af745fb50186cd Mon Sep 17 00:00:00 2001 From: Gracjan Sadowicz Date: Thu, 23 Jul 2026 04:53:10 +0200 Subject: [PATCH 12/16] RavenDB-27069 Fix wait_for_indexing: it returned before stale indexes settled --- ravendb_test_driver/raven_test_driver.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ravendb_test_driver/raven_test_driver.py b/ravendb_test_driver/raven_test_driver.py index 12d103c..4c953ba 100644 --- a/ravendb_test_driver/raven_test_driver.py +++ b/ravendb_test_driver/raven_test_driver.py @@ -140,15 +140,15 @@ def wait_for_indexing( while time.monotonic() - start_time < timeout.total_seconds(): database_statistics = admin.send(GetStatisticsOperation()) - indexes = [ + stale = [ x for x in database_statistics.indexes if x.state != IndexState.DISABLED - and not x.stale + and x.stale and not x.name.startswith(Documents.Indexing.SIDE_BY_SIDE_INDEX_NAME_PREFIX) ] - if all(indexes): + if not stale: return if any(index.state == IndexState.ERROR for index in database_statistics.indexes): From 838e94057454845c3a14fc316ff9ddd6e925d11b Mon Sep 17 00:00:00 2001 From: Gracjan Sadowicz Date: Thu, 23 Jul 2026 04:53:13 +0200 Subject: [PATCH 13/16] RavenDB-27069 Add Lab 02 (embedded per-test) and Lab 03 (seeding + indexes); run both in CI --- .github/workflows/tests.yml | 11 ++++++++ README.md | 4 +++ labs/02-embedded-per-test.md | 38 ++++++++++++++++++++++++++++ labs/02_embedded_per_test.py | 31 +++++++++++++++++++++++ labs/03-seeding-indexes.md | 49 ++++++++++++++++++++++++++++++++++++ labs/03_seeding_indexes.py | 48 +++++++++++++++++++++++++++++++++++ labs/README.md | 2 ++ 7 files changed, 183 insertions(+) create mode 100644 labs/02-embedded-per-test.md create mode 100644 labs/02_embedded_per_test.py create mode 100644 labs/03-seeding-indexes.md create mode 100644 labs/03_seeding_indexes.py diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 63cb67b..cbd548f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -44,6 +44,12 @@ jobs: - name: Run tests run: python -m unittest discover -s tests + - name: Run Lab 02 (embedded per-test) + run: python labs/02_embedded_per_test.py + + - name: Run Lab 03 (seeding + indexes) + run: python labs/03_seeding_indexes.py + attach: # Path C: attach to a RavenDB server running in Docker, with NO .NET installed. Proves the # driver needs no runtime when it does not boot the embedded server. @@ -80,3 +86,8 @@ jobs: RAVENDB_TEST_SERVER_URL: http://localhost:8080 RAVENDB_TEST_REQUIRE_ATTACH: "1" run: python -m unittest tests.test_attach -v + + - name: Run Lab 01 (attach, no .NET) + env: + RAVENDB_TEST_SERVER_URL: http://localhost:8080 + run: python labs/01_attach_to_server.py diff --git a/README.md b/README.md index 964221d..d9044f7 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,8 @@ class TestBasic(TestCase): session.save_changes() ``` +Runnable example: [`labs/02-embedded-per-test.md`](labs/02-embedded-per-test.md). + ### Seeding data and waiting for indexes - Override `setup_database(self, store)` to seed or configure every database the driver hands @@ -81,6 +83,8 @@ class TestBasic(TestCase): - `wait_for_user_to_continue_the_test(store)` opens RavenDB Studio so you can inspect the data mid-test. +Runnable example: [`labs/03-seeding-indexes.md`](labs/03-seeding-indexes.md). + ## Links - PyPI: https://pypi.org/project/ravendb-test-driver/ diff --git a/labs/02-embedded-per-test.md b/labs/02-embedded-per-test.md new file mode 100644 index 0000000..3a7f6ef --- /dev/null +++ b/labs/02-embedded-per-test.md @@ -0,0 +1,38 @@ +# Lab 02: Embedded server, one isolated database per test (the default) + +**For:** the normal way to write tests with the driver. Subclass `RavenTestDriver` (or hold an +instance); each `get_document_store()` returns a store backed by a fresh, isolated database that +is cleaned up afterwards, so tests never see each other's data. This path boots the embedded +server and needs a matching .NET (see the README). + +## Run it + +```bash +pip install ravendb-test-driver +python labs/02_embedded_per_test.py +``` + +The complete example is [`02_embedded_per_test.py`](02_embedded_per_test.py). In a real test: + +```python +from unittest import TestCase +from ravendb_test_driver import RavenTestDriver + +class TestThings(TestCase): + def setUp(self): + self.driver = RavenTestDriver() + + def test_it(self): + with self.driver.get_document_store() as store: # fresh isolated database + with store.open_session() as session: + session.store({"name": "John"}, "people/1") + session.save_changes() +``` + +Two `get_document_store()` calls give two different databases, so data written to one is invisible +to the other. That isolation is what keeps tests independent. + +## Takeaway + +No server to manage in your tests: the driver runs one and gives each test its own database. To +run without .NET, attach to a server you start yourself (Lab 01). diff --git a/labs/02_embedded_per_test.py b/labs/02_embedded_per_test.py new file mode 100644 index 0000000..e13b8f1 --- /dev/null +++ b/labs/02_embedded_per_test.py @@ -0,0 +1,31 @@ +"""Lab 02: Embedded server, one isolated database per test (the default). + +For: the normal way to write tests with the driver. Subclass RavenTestDriver (or hold an +instance); each get_document_store() returns a store backed by a fresh, isolated database that is +cleaned up afterwards, so tests never see each other's data. This path boots the embedded server +and therefore needs a matching .NET (see the README). + +Run: python labs/02_embedded_per_test.py +""" + +from ravendb_test_driver import RavenTestDriver + + +def main() -> None: + with RavenTestDriver() as driver: + with driver.get_document_store() as first, driver.get_document_store() as second: + assert first.database != second.database, (first.database, second.database) + + with first.open_session() as session: + session.store({"name": "only in first"}, "people/1") + session.save_changes() + + # The second store is a different database, so it cannot see the first store's data. + with second.open_session() as session: + assert session.load("people/1", dict) is None + + print("Lab 02 OK: two stores, two isolated databases, no cross-test leakage.") + + +if __name__ == "__main__": + main() diff --git a/labs/03-seeding-indexes.md b/labs/03-seeding-indexes.md new file mode 100644 index 0000000..d98f085 --- /dev/null +++ b/labs/03-seeding-indexes.md @@ -0,0 +1,49 @@ +# Lab 03: Seed data and query an index in tests + +**For:** tests that need pre-seeded data and a defined index, and must wait for indexing to settle +before asserting. Override `setup_database()` to seed and create the index for every database the +driver hands out; call `wait_for_indexing()` before querying so the assertion is not racing the +indexer. + +## Run it + +```bash +pip install ravendb-test-driver +python labs/03_seeding_indexes.py +``` + +The complete example is [`03_seeding_indexes.py`](03_seeding_indexes.py). The core is: + +```python +from ravendb.documents.indexes.abstract_index_creation_tasks import AbstractIndexCreationTask +from ravendb_test_driver import RavenTestDriver + +class People_ByName(AbstractIndexCreationTask): + def __init__(self): + super().__init__() + self.map = "from p in docs.People select new { p.name }" + +class SeedingDriver(RavenTestDriver): + def setup_database(self, store): # runs for every database the driver creates + store.execute_index(People_ByName()) + with store.open_session() as session: + session.store(Person(name="Seeded"), "people/1") + session.save_changes() + +with SeedingDriver() as driver: + with driver.get_document_store() as store: + driver.wait_for_indexing(store) # block until no index is stale + with store.open_session() as session: + hits = list(session.query_index_type(People_ByName, Person).where_equals("name", "Seeded")) +``` + +## Why `wait_for_indexing` + +RavenDB indexes are updated asynchronously, so right after you write, an index query can return +stale (empty) results. `wait_for_indexing()` blocks until no index is stale, making index-backed +assertions deterministic instead of flaky. + +## Takeaway + +`setup_database()` is the single place to seed data and register indexes for every test database; +`wait_for_indexing()` removes the race between writing and querying an index. diff --git a/labs/03_seeding_indexes.py b/labs/03_seeding_indexes.py new file mode 100644 index 0000000..adf7527 --- /dev/null +++ b/labs/03_seeding_indexes.py @@ -0,0 +1,48 @@ +"""Lab 03: Seed data and query an index in tests. + +For: tests that need pre-seeded data and a defined index, and must wait for indexing to settle +before asserting. Override setup_database() to seed and create the index for every database the +driver hands out; call wait_for_indexing() before querying so the assertion is not racing the +indexer. Boots the embedded server (needs .NET). + +Run: python labs/03_seeding_indexes.py +""" + +from ravendb.documents.indexes.abstract_index_creation_tasks import AbstractIndexCreationTask + +from ravendb_test_driver import RavenTestDriver + + +class Person: + def __init__(self, Id=None, name=None): + self.Id = Id + self.name = name + + +class People_ByName(AbstractIndexCreationTask): + def __init__(self): + super().__init__() + self.map = "from p in docs.People select new { p.name }" + + +class SeedingDriver(RavenTestDriver): + def setup_database(self, store) -> None: # runs for every database the driver creates + store.execute_index(People_ByName()) + with store.open_session() as session: + session.store(Person(name="Seeded"), "people/1") + session.save_changes() + + +def main() -> None: + with SeedingDriver() as driver: + with driver.get_document_store() as store: + driver.wait_for_indexing(store) # block until the index is no longer stale + with store.open_session() as session: + hits = list(session.query_index_type(People_ByName, Person).where_equals("name", "Seeded")) + assert len(hits) == 1 and hits[0].name == "Seeded", hits + + print("Lab 03 OK: setup_database seeded data + index, wait_for_indexing settled, query returned it.") + + +if __name__ == "__main__": + main() diff --git a/labs/README.md b/labs/README.md index e4a0dc4..f6eada6 100644 --- a/labs/README.md +++ b/labs/README.md @@ -6,6 +6,8 @@ you can run the exact code the guide shows. | Lab | Covers | Needs system .NET? | |-----|--------|--------------------| | [01](01-attach-to-server.md) | Attach to a server you run yourself (Docker, testcontainers, shared CI) | No | +| [02](02-embedded-per-test.md) | Embedded server, one isolated database per test (the default) | Yes | +| [03](03-seeding-indexes.md) | Seed data and query an index (`setup_database`, `wait_for_indexing`) | Yes | Looking for how to run RavenDB itself (embedded, or self-contained without .NET)? That belongs to the [`ravendb-python-embedded`](https://github.com/ravendb/ravendb-python-embedded) package and From b4615ffdb1bafb50ed7071828e0beed682b0e9a4 Mon Sep 17 00:00:00 2001 From: Gracjan Sadowicz Date: Thu, 23 Jul 2026 05:09:23 +0200 Subject: [PATCH 14/16] RavenDB-27069 Drop redundant requirements.txt (duplicated and drifted from setup.py) --- requirements.txt | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 6d227a9..0000000 --- a/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -ravendb~=7.2.3 -ravendb-embedded==7.2.3 -setuptools~=68.0.0 \ No newline at end of file From 89c60e9ae6a101c64b1c78f6eb319ea9b638fc00 Mon Sep 17 00:00:00 2001 From: Gracjan Sadowicz Date: Tue, 28 Jul 2026 03:14:37 +0200 Subject: [PATCH 15/16] RavenDB-27069 Attach: support secured (https) servers via client cert; document cleanup on shared servers (review) --- labs/01-attach-to-server.md | 11 +++++++++++ ravendb_test_driver/raven_test_driver.py | 15 +++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/labs/01-attach-to-server.md b/labs/01-attach-to-server.md index c93d14a..64a7953 100644 --- a/labs/01-attach-to-server.md +++ b/labs/01-attach-to-server.md @@ -19,6 +19,10 @@ RavenTestDriver.configure_external_server("http://localhost:8080") # RAVENDB_TEST_SERVER_URL=http://localhost:8080 ``` +For a secured (https) server, pass the client certificate: `configure_external_server(url, +certificate_pem_path=...)` (or set `RAVENDB_TEST_SERVER_CERT`); attaching to https without one +fails fast with a clear message. + Then use the driver exactly as with the embedded server: ```python @@ -70,6 +74,13 @@ This repo's own CI uses a GitHub Actions service container (see `.github/workflo the `attach` job): it runs `ravendb/ravendb:7.2-ubuntu-latest`, waits for it, then runs the attach test with `RAVENDB_TEST_SERVER_URL` set and no .NET installed. +## Cleanup on a shared server + +Each test's database is deleted when its store closes, so dispose the driver (use it as a +context manager). If a run is hard-killed before that, per-test `test_*` databases can be left +behind on a shared server and a rerun may collide with them; prefer a fresh or per-run server, +and prune leftover `test_*` databases between runs. + ## Takeaway No embedded server and no .NET, at the cost of running RavenDB yourself. If you would rather diff --git a/ravendb_test_driver/raven_test_driver.py b/ravendb_test_driver/raven_test_driver.py index 4c953ba..dbe8cd2 100644 --- a/ravendb_test_driver/raven_test_driver.py +++ b/ravendb_test_driver/raven_test_driver.py @@ -36,6 +36,7 @@ class RavenTestDriver: _GLOBAL_SERVER_OPTIONS: Optional[ServerOptions] = None _EMPTY_SETTINGS_FILE_NAME: Optional[str] = None _EXTERNAL_SERVER_URL: Optional[str] = None + _EXTERNAL_SERVER_CERT: Optional[str] = None def __init__(self) -> None: self.disposed = False @@ -67,10 +68,11 @@ def configure_server(options: ServerOptions) -> None: RavenTestDriver._GLOBAL_SERVER_OPTIONS = options @staticmethod - def configure_external_server(url: str) -> None: + def configure_external_server(url: str, certificate_pem_path: str = None) -> None: """Attach to a server you run yourself (no embedded boot, no .NET); still one database per test. - Equivalent to setting RAVENDB_TEST_SERVER_URL. Call before the first get_document_store. + For a secured (https) server, pass the client certificate `.pem`. Equivalent to setting + RAVENDB_TEST_SERVER_URL (and RAVENDB_TEST_SERVER_CERT). Call before the first get_document_store. """ if RavenTestDriver._TEST_SERVER_STORE.is_value_created: raise RuntimeError( @@ -78,6 +80,7 @@ def configure_external_server(url: str) -> None: "Call 'configure_external_server' before any 'get_document_store'." ) RavenTestDriver._EXTERNAL_SERVER_URL = url + RavenTestDriver._EXTERNAL_SERVER_CERT = certificate_pem_path def get_document_store( self, @@ -248,7 +251,15 @@ def run_server(cls) -> DocumentStore: external_url = cls._EXTERNAL_SERVER_URL or os.environ.get("RAVENDB_TEST_SERVER_URL") if external_url: # Attach to an existing server; do not boot the embedded one (no .NET needed). + certificate = cls._EXTERNAL_SERVER_CERT or os.environ.get("RAVENDB_TEST_SERVER_CERT") + if external_url.lower().startswith("https") and not certificate: + raise RavenException( + f"Attaching to a secured server ({external_url}) needs a client certificate; pass " + "configure_external_server(url, certificate_pem_path=...) or set RAVENDB_TEST_SERVER_CERT." + ) store = DocumentStore(external_url, None) + if certificate: + store.certificate_pem_path = certificate store.initialize() return store From 9b59a575bdec0ba3f073ddc4dadea0becb8018fc Mon Sep 17 00:00:00 2001 From: Gracjan Sadowicz Date: Tue, 28 Jul 2026 04:03:13 +0200 Subject: [PATCH 16/16] RavenDB-27069 Pin ravendb-embedded 7.2.5 for release --- setup.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/setup.py b/setup.py index a87be8f..e1629ef 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,5 @@ keywords=["ravendb", "nosql", "database", "test", "driver"], python_requires=">=3.10", license_files="LICENSE", - # ravendb-embedded pinned to the latest PUBLISHED release; Dependabot bumps it to 7.2.5 once - # that is on PyPI (embedded and this package release together, embedded first). - install_requires=["ravendb-embedded==7.2.3", "ravendb==7.2.3.post1"], + install_requires=["ravendb-embedded==7.2.5", "ravendb==7.2.3.post1"], )