diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..d1ec1fd --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,51 @@ +name: tests + +on: + push: + branches: [v7.2] + pull_request: + branches: [v7.2] + workflow_dispatch: + +jobs: + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + # The embedded RavenDB server is a .NET application. + - name: Set up .NET 8 + uses: actions/setup-dotnet@v4 + with: + dotnet-version: "8.0" + + - name: Install package + run: | + python -m pip install --upgrade pip + pip install -e . + + - name: Check formatting (black) + run: | + pip install black + black --check . + + # Downloads + unpacks the bundled RavenDB server into ravendb_embedded/target/nuget + # (via the project's own sdist hook), which the tests copy from. setuptools is + # installed explicitly because it is not present in modern virtualenvs by default. + - name: Fetch bundled RavenDB server + run: | + pip install setuptools wheel + python setup.py sdist + + - name: Run tests + run: python -m unittest discover -s tests diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..55ec8d7 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,2 @@ +[tool.black] +line-length = 120 diff --git a/tests/test_custom_provider.py b/tests/test_custom_provider.py index 55fcd9a..bae95a7 100644 --- a/tests/test_custom_provider.py +++ b/tests/test_custom_provider.py @@ -1,3 +1,4 @@ +import shutil import tempfile from pathlib import Path from unittest import TestCase @@ -19,10 +20,16 @@ def configure_server_options(temp_dir: str, server_options: ServerOptions) -> Se def test_can_use_zip_as_external_server_source(self): with tempfile.TemporaryDirectory() as temp_dir: + # Zip the bundled server so the test does not depend on cwd or a pre-built archive. + server_zip = shutil.make_archive( + str(Path(temp_dir, "ravendb-server")), + "zip", + CopyServerFromNugetProvider().server_files, + ) with EmbeddedServer() as embedded: server_options = ServerOptions() server_options = self.configure_server_options(temp_dir, server_options) - server_options.with_external_server("ravendb_embedded/target/ravendb-server.zip") + server_options.with_external_server(server_zip) embedded.start_server(server_options) database_options = DatabaseOptions.from_database_name("Test") @@ -37,7 +44,7 @@ def test_can_use_directory_as_external_server_source(self): with EmbeddedServer() as embedded: server_options = ServerOptions() server_options = self.configure_server_options(temp_directory, server_options) - server_options.with_external_server(CopyServerFromNugetProvider.SERVER_FILES) + server_options.with_external_server(CopyServerFromNugetProvider().server_files) embedded.start_server(server_options) database_options = DatabaseOptions.from_database_name("Test") diff --git a/tests/test_runtime_framework_version_matcher.py b/tests/test_runtime_framework_version_matcher.py index c6fde32..e07d337 100644 --- a/tests/test_runtime_framework_version_matcher.py +++ b/tests/test_runtime_framework_version_matcher.py @@ -9,28 +9,19 @@ class TestRuntimeFrameworkVersionMatcher(TestCase): def test_match_1(self): - options = ServerOptions() - default_framework_version = ServerOptions.INSTANCE().framework_version + # Framework version is not enforced by default (see "Don't enforce framework version"): + # an empty/None framework version means the bundled server picks its own runtime, so the + # matcher returns the value unchanged instead of resolving an installed runtime. The + # version-resolution logic itself is covered by test_match_2/3/4. + self.assertFalse(ServerOptions.INSTANCE().framework_version) - self.assertIn(RuntimeFrameworkVersionMatcher.GREATER_OR_EQUAL, default_framework_version) + options = ServerOptions() options.framework_version = None self.assertIsNone(RuntimeFrameworkVersionMatcher.match(options)) - options = ServerOptions() - framework_version = RuntimeFrameworkVersion(options.framework_version) - framework_version.patch = None - - options.framework_version = framework_version.__str__() - match = RuntimeFrameworkVersionMatcher.match(options) - self.assertIsNotNone(match) - - match_framework_version = RuntimeFrameworkVersion(match) - self.assertIsNotNone(match_framework_version.major) - self.assertIsNotNone(match_framework_version.minor) - self.assertIsNotNone(match_framework_version.patch) - - self.assertTrue(framework_version.match(match_framework_version)) + options.framework_version = "" + self.assertEqual("", RuntimeFrameworkVersionMatcher.match(options)) def test_match_2(self): runtimes = self.get_runtimes() diff --git a/tests/test_secured_basic.py b/tests/test_secured_basic.py index ab83b39..5df6936 100644 --- a/tests/test_secured_basic.py +++ b/tests/test_secured_basic.py @@ -1,5 +1,7 @@ +import os import shutil import tempfile +import unittest from pathlib import Path from unittest import TestCase @@ -8,12 +10,19 @@ from ravendb_embedded.provide import CopyServerFromNugetProvider from tests import Person +# Secured mode needs locally-provisioned HTTPS certificates. Skip when they are absent +# (e.g. in CI); point these at your certificates to run it on a developer machine. +SERVER_CERTIFICATE_LOCATION = "C:\\RavenDB Clients\\Https\\server.pfx" +CA_CERTIFICATE_LOCATION = "C:\\RavenDB Clients\\Https\\ca.crt" +CLIENT_CERTIFICATE_LOCATION = "C:\\RavenDB Clients\\Https\\python.pem" +_CERTS_PRESENT = all( + os.path.exists(path) for path in (SERVER_CERTIFICATE_LOCATION, CA_CERTIFICATE_LOCATION, CLIENT_CERTIFICATE_LOCATION) +) + +@unittest.skipUnless(_CERTS_PRESENT, "local HTTPS certificates not available") class TestSecuredBasic(TestCase): def test_secured_embedded(self): - SERVER_CERTIFICATE_LOCATION = "C:\\RavenDB Clients\\Https\\server.pfx" - CA_CERTIFICATE_LOCATION = "C:\\RavenDB Clients\\Https\\ca.crt" - CLIENT_CERTIFICATE_LOCATION = "C:\\RavenDB Clients\\Https\\python.pem" temp_dir = tempfile.mkdtemp() try: with EmbeddedServer() as embedded: