From 32a242d53b2c1b18240a4f5928b886ea3196d604 Mon Sep 17 00:00:00 2001 From: Jan Lehnardt Date: Tue, 18 Nov 2025 16:12:10 +0100 Subject: [PATCH 1/5] Port hypothesis property check from 06-basic-text-test.py to PropCheck The current property is hardcoded at running 1_000 tests, which takes about 10s on my machine. I have run it up to 20_000 tests and it never failed so far. Run this with new command `make elixir-test-search-props` as I could not make it work with the test suite. Removes the existing test from the Python test file. NOTE: this currently runs against nouveau as I did not have a Clouseau setup handy, could someone wiggle things so they run with Clousau? --- .gitignore | 2 + Makefile | 16 +++++- erlang_ls.config | 5 ++ mix.exs | 8 +-- src/mango/test/06-basic-text-test.py | 36 ------------- test/elixir/test/config/test-config.ini | 2 +- .../test/mango/06_basic_text_prop_test.exs | 50 +++++++++++++++++++ 7 files changed, 78 insertions(+), 41 deletions(-) create mode 100644 test/elixir/test/mango/06_basic_text_prop_test.exs diff --git a/.gitignore b/.gitignore index d46777512b7..9ce3943c6f4 100644 --- a/.gitignore +++ b/.gitignore @@ -64,12 +64,14 @@ src/hqueue/ src/ibrowse/ src/idna/ src/jiffy/ +src/libgraph/ src/meck/ src/metrics/ src/mimerl/ src/mochiweb/ src/oauth/ src/parse_trans/ +src/propcheck/ src/proper/ src/rebar/ src/recon/ diff --git a/Makefile b/Makefile index 947371e3c65..4de4e080753 100644 --- a/Makefile +++ b/Makefile @@ -271,8 +271,12 @@ elixir-cluster-with-quorum: elixir-init devclean .PHONY: elixir # target: elixir - Run Elixir-based integration tests -elixir: export MIX_ENV=integration elixir: elixir-init devclean + @$(MAKE) elixir-test + +.PHONY: elixir-test +elixir-test: export MIX_ENV=integration +elixir-test: @dev/run "$(TEST_OPTS)" -n 1 -q -a adm:pass \ --enable-erlang-views \ --no-join \ @@ -300,6 +304,16 @@ else @echo "Warning: Clouseau is not enabled, \`elixir-search\` cannot be run." endif +.PHONY: elixir-test-search-props +elixir-test-search-props: export MIX_ENV=integration +elixir-test-search-props: + @dev/run "$(TEST_OPTS)" -n 1 -q -a adm:pass \ + --enable-erlang-views \ + --no-join \ + --locald-config test/elixir/test/config/test-config.ini \ + --erlang-config rel/files/eunit.config \ + --no-eval 'mix test --trace --only search_props $(EXUNIT_OPTS)' + .PHONY: elixir-source-checks # target: elixir-source-checks - Check source code formatting of Elixir test files elixir-source-checks: export MIX_ENV=integration diff --git a/erlang_ls.config b/erlang_ls.config index 94483cfec26..3464e6fdd39 100644 --- a/erlang_ls.config +++ b/erlang_ls.config @@ -3,3 +3,8 @@ apps_dirs: include_dirs: - "src" - "src/*/include" +macros: + - name: WITH_PROPER + value: true + - name: TEST + value: true diff --git a/mix.exs b/mix.exs index 4f0cb4ba3f9..1749758c594 100644 --- a/mix.exs +++ b/mix.exs @@ -66,12 +66,13 @@ defmodule CouchDBTest.Mixfile do tool: CoverTool, dirs: get_coverage_paths(), type: "html" - ] + ], + propcheck: [] ] end # Run "mix help compile.app" to learn about applications. - def application, do: [applications: [:logger, :httpotion]] + def application, do: [applications: [:logger, :httpotion, :propcheck]] # Specifies which paths to compile per environment. defp elixirc_paths(:test), do: ["test/elixir/lib", "test/elixir/test/support"] @@ -85,7 +86,8 @@ defmodule CouchDBTest.Mixfile do {:httpotion, ">= 3.2.0", only: [:dev, :test, :integration], runtime: false}, {:excoveralls, "~> 0.18.3", only: :test}, {:ibrowse, path: path("ibrowse"), override: true}, - {:credo, "~> 1.7.11", only: [:dev, :test, :integration], runtime: false} + {:credo, "~> 1.7.11", only: [:dev, :test, :integration], runtime: false}, + {:propcheck, "~> 1.5", only: [:dev, :test, :integration]} ] extra_deps = [:b64url, :jiffy, :jwtf, :meck, :mochiweb] diff --git a/src/mango/test/06-basic-text-test.py b/src/mango/test/06-basic-text-test.py index da3eb6ff58f..eb6f29894f4 100644 --- a/src/mango/test/06-basic-text-test.py +++ b/src/mango/test/06-basic-text-test.py @@ -564,39 +564,3 @@ def test_all_match(self): docs = self.db.find(q) assert len(docs) == 1 assert docs[0]["user_id"] == 15 - - -# Test numeric strings for $text -@unittest.skipUnless(mango.has_text_service(), "requires text service") -class NumStringTests(mango.DbPerClass): - @classmethod - def setUpClass(klass): - super(NumStringTests, klass).setUpClass() - klass.db.recreate() - klass.db.create_text_index() - - # not available for python 2.7.x - def isFinite(num): - not (math.isinf(num) or math.isnan(num)) - - @given(f=st.floats().filter(isFinite).map(str) | st.floats().map(lambda f: f.hex())) - @settings(deadline=1000) - @example("NaN") - @example("Infinity") - def test_floating_point_val(self, f): - doc = {"number_string": f} - self.db.save_doc(doc) - q = {"$text": f} - docs = self.db.find(q) - if len(docs) == 1: - assert docs[0]["number_string"] == f - if len(docs) == 2: - if docs[0]["number_string"] != f: - assert docs[1]["number_string"] == f - q = {"number_string": f} - docs = self.db.find(q) - if len(docs) == 1: - assert docs[0]["number_string"] == f - if len(docs) == 2: - if docs[0]["number_string"] != f: - assert docs[1]["number_string"] == f diff --git a/test/elixir/test/config/test-config.ini b/test/elixir/test/config/test-config.ini index 423cc492cb4..53ac2cac790 100644 --- a/test/elixir/test/config/test-config.ini +++ b/test/elixir/test/config/test-config.ini @@ -1,5 +1,5 @@ [log] -level = warn +level = notice [chttpd] authentication_handlers = {chttpd_auth, jwt_authentication_handler}, {chttpd_auth, proxy_authentication_handler}, {chttpd_auth, cookie_authentication_handler}, {chttpd_auth, default_authentication_handler} diff --git a/test/elixir/test/mango/06_basic_text_prop_test.exs b/test/elixir/test/mango/06_basic_text_prop_test.exs new file mode 100644 index 00000000000..57f9d9817f5 --- /dev/null +++ b/test/elixir/test/mango/06_basic_text_prop_test.exs @@ -0,0 +1,50 @@ +defmodule BasicTextTest do + use PropCheck + use CouchTestCase + + @moduletag :search_props + @db_name "changeme-proptest-db" + + property "test floating point value", + numtests: 1_000 do # takes about 10 seconds + MangoDatabase.recreate("/#{@db_name}") + forall f <- union([float(), "NaN", "Infinity"]) do + # create doc with float + :ok == test_float(f) + end + end + + # this is used to test the inner logic, as that + # is a bit tricky from inside the property + test "single floating point test" do + MangoDatabase.recreate("/#{@db_name}") + test_float(3.14) + end + + def test_float(f) do + doc = %{"number_string" => f} + # save doc + Couch.post("/#{@db_name}", body: doc) + # run find with same float as $text + {:ok, docs} = MangoDatabase.find(@db_name, %{"$text" => f}) + # if result length = 1, assert docs[0] == f + assert_result(docs, f) + # run find again with same float as field name match + {:ok, docs} = MangoDatabase.find(@db_name, %{"number_text" => f}) + # repeat same tests + assert_result(docs, f) + :ok + end + + def assert_result(docs, f) do + cond do + Enum.count(docs) == 1 -> + assert Enum.at(docs, 0)["number_string"] == f + Enum.count(docs) == 2 -> + if Enum.at(docs, 0)["number_string"] != f do + assert Enum.at(docs, 1)["number_string"] == f + end + true -> true + end + end +end From 71bd6942b282231f2c2320772268143892ea64ef Mon Sep 17 00:00:00 2001 From: Jan Lehnardt Date: Wed, 19 Nov 2025 12:53:32 +0100 Subject: [PATCH 2/5] chore: remove now unused hypothesis dependency --- .gitignore | 1 - README-DEV.rst | 4 ++-- src/mango/requirements.txt | 3 +-- src/mango/test/06-basic-text-test.py | 3 --- 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 9ce3943c6f4..8ccccf01b9c 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,6 @@ .vscode .rebar/ .eunit/ -.hypothesis/ cover/ /core debian/ diff --git a/README-DEV.rst b/README-DEV.rst index 6726db0055a..40cf17d5f53 100644 --- a/README-DEV.rst +++ b/README-DEV.rst @@ -100,7 +100,7 @@ Gentoo-based Systems :: sudo emerge gnupg coreutils pkgconfig help2man sphinx python - sudo pip install hypothesis requests nose + sudo pip install requests nose Centos 7 and RHEL 7 ~~~~~~~~~~~~~~~~~~~ @@ -136,7 +136,7 @@ FreeBSD :: pkg install help2man gnupg py27-sphinx node - pip install nose requests hypothesis + pip install nose requests Windows ~~~~~~~ diff --git a/src/mango/requirements.txt b/src/mango/requirements.txt index c8e8cff3796..481fc3418e5 100644 --- a/src/mango/requirements.txt +++ b/src/mango/requirements.txt @@ -1,5 +1,4 @@ -# nose2 0.13.0, requests, hypothesis version are driven +# nose2 0.13.0, requests version are driven # by the minimum version for python on centos 8 currently nose2==0.13.0 requests==2.32.4 -hypothesis==6.31.6 diff --git a/src/mango/test/06-basic-text-test.py b/src/mango/test/06-basic-text-test.py index eb6f29894f4..57a337ba980 100644 --- a/src/mango/test/06-basic-text-test.py +++ b/src/mango/test/06-basic-text-test.py @@ -15,9 +15,6 @@ import unittest import user_docs import math -from hypothesis import given, assume, example, settings -import hypothesis.strategies as st - @unittest.skipIf(mango.has_text_service(), "text service exists") class TextIndexCheckTests(mango.DbPerClass): From 3f77dfa44807092efca086e4c29fb6e62fc94f04 Mon Sep 17 00:00:00 2001 From: Jan Lehnardt Date: Wed, 19 Nov 2025 13:19:50 +0100 Subject: [PATCH 3/5] feat: use weighted_union to deprioritise NaN and Infinity --- test/elixir/test/mango/06_basic_text_prop_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/elixir/test/mango/06_basic_text_prop_test.exs b/test/elixir/test/mango/06_basic_text_prop_test.exs index 57f9d9817f5..26900bc6eb5 100644 --- a/test/elixir/test/mango/06_basic_text_prop_test.exs +++ b/test/elixir/test/mango/06_basic_text_prop_test.exs @@ -8,7 +8,7 @@ defmodule BasicTextTest do property "test floating point value", numtests: 1_000 do # takes about 10 seconds MangoDatabase.recreate("/#{@db_name}") - forall f <- union([float(), "NaN", "Infinity"]) do + forall f <- weighted_union([{100, float()}, {1, "NaN"}, {1, "Infinity"}]) do # create doc with float :ok == test_float(f) end From 9c71bebf334d4259cca6a9261ba0427b75c07a5f Mon Sep 17 00:00:00 2001 From: Alba Herrerias Date: Tue, 9 Dec 2025 15:28:18 +0000 Subject: [PATCH 4/5] Add elixir-test-search-props to windows Makefile --- Makefile.win | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Makefile.win b/Makefile.win index d510ee51df4..50a79e6e35b 100644 --- a/Makefile.win +++ b/Makefile.win @@ -240,9 +240,13 @@ elixir-cluster-with-quorum: elixir-init devclean .PHONY: elixir # target: elixir - Run Elixir-based integration tests -elixir: export MIX_ENV=integration -elixir: export COUCHDB_TEST_ADMIN_PARTY_OVERRIDE=1 elixir: elixir-init devclean + @$(MAKE) elixir-test + +.PHONY: elixir-test +elixir-test: export MIX_ENV=integration +elixir-test: export COUCHDB_TEST_ADMIN_PARTY_OVERRIDE=1 +elixir-test: elixir-init devclean @dev\run "$(TEST_OPTS)" -n 1 -q -a adm:pass \ --enable-erlang-views \ --no-join \ @@ -270,6 +274,16 @@ else @echo "Warning: Clouseau is not enabled, `elixir-search` cannot be run." endif +.PHONY: elixir-test-search-props +elixir-test-search-props: export MIX_ENV=integration +elixir-test-search-props: + @dev\run "$(TEST_OPTS)" -n 1 -q -a adm:pass \ + --enable-erlang-views \ + --no-join \ + --locald-config test/elixir/test/config/test-config.ini \ + --erlang-config rel/files/eunit.config \ + --no-eval 'mix test --trace --only search_props $(EXUNIT_OPTS)' + .PHONY: elixir-source-checks # target: elixir-source-checks - Check source code formatting of Elixir test files elixir-source-checks: export MIX_ENV=integration From 2f707d48f7cc04ec765202ff350e76db7d54f41a Mon Sep 17 00:00:00 2001 From: Alba Herrerias Date: Wed, 10 Dec 2025 14:18:52 +0000 Subject: [PATCH 5/5] Add NumStringTests to elixir search tests --- Makefile | 10 ---------- Makefile.win | 10 ---------- test/elixir/test/config/search.elixir | 3 +++ test/elixir/test/mango/06_basic_text_prop_test.exs | 4 ++-- 4 files changed, 5 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 4de4e080753..2cde8cad7c0 100644 --- a/Makefile +++ b/Makefile @@ -304,16 +304,6 @@ else @echo "Warning: Clouseau is not enabled, \`elixir-search\` cannot be run." endif -.PHONY: elixir-test-search-props -elixir-test-search-props: export MIX_ENV=integration -elixir-test-search-props: - @dev/run "$(TEST_OPTS)" -n 1 -q -a adm:pass \ - --enable-erlang-views \ - --no-join \ - --locald-config test/elixir/test/config/test-config.ini \ - --erlang-config rel/files/eunit.config \ - --no-eval 'mix test --trace --only search_props $(EXUNIT_OPTS)' - .PHONY: elixir-source-checks # target: elixir-source-checks - Check source code formatting of Elixir test files elixir-source-checks: export MIX_ENV=integration diff --git a/Makefile.win b/Makefile.win index 50a79e6e35b..339f8ee22e0 100644 --- a/Makefile.win +++ b/Makefile.win @@ -274,16 +274,6 @@ else @echo "Warning: Clouseau is not enabled, `elixir-search` cannot be run." endif -.PHONY: elixir-test-search-props -elixir-test-search-props: export MIX_ENV=integration -elixir-test-search-props: - @dev\run "$(TEST_OPTS)" -n 1 -q -a adm:pass \ - --enable-erlang-views \ - --no-join \ - --locald-config test/elixir/test/config/test-config.ini \ - --erlang-config rel/files/eunit.config \ - --no-eval 'mix test --trace --only search_props $(EXUNIT_OPTS)' - .PHONY: elixir-source-checks # target: elixir-source-checks - Check source code formatting of Elixir test files elixir-source-checks: export MIX_ENV=integration diff --git a/test/elixir/test/config/search.elixir b/test/elixir/test/config/search.elixir index 7d328c11260..a059ea8f906 100644 --- a/test/elixir/test/config/search.elixir +++ b/test/elixir/test/config/search.elixir @@ -52,5 +52,8 @@ ], "RegexVsTextIndexTest": [ "regex works with text index" + ], + "NumStringTests": [ + "single floating point test" ] } diff --git a/test/elixir/test/mango/06_basic_text_prop_test.exs b/test/elixir/test/mango/06_basic_text_prop_test.exs index 26900bc6eb5..0b648083ad4 100644 --- a/test/elixir/test/mango/06_basic_text_prop_test.exs +++ b/test/elixir/test/mango/06_basic_text_prop_test.exs @@ -1,10 +1,10 @@ -defmodule BasicTextTest do +defmodule NumStringTests do use PropCheck use CouchTestCase @moduletag :search_props @db_name "changeme-proptest-db" - + property "test floating point value", numtests: 1_000 do # takes about 10 seconds MangoDatabase.recreate("/#{@db_name}")