This is an automated email from the ASF dual-hosted git repository. vatamane pushed a commit to branch add-concurrent-test-with-intermettent-view-queries in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit d1d258ffe7b78ba553992095d3f1e0e81caa1e5f Author: Nick Vatamaniuc <[email protected]> AuthorDate: Thu Mar 18 16:33:44 2021 -0400 Add more concurrent write tests * `Secondary data tests with updates and queries`: This one is just like the `Secondary data tests with updates` but adds intermettent queries while updates are taking place. * `Secondary data tests with deletes and queries`: This one deletes and queries intermetently. This one was specifically crafted to trigger the `ebtree:lookup_multi/3` error and hopefully other similar ones. The retry_until section at the end was added to differentiate between the case were we returna partial view and when the view is actually broken and it will never "catch up". Once we start returning only completed views, we remove that section. --- test/elixir/test/concurrent_writes_test.exs | 76 +++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/test/elixir/test/concurrent_writes_test.exs b/test/elixir/test/concurrent_writes_test.exs index 397c5e8..8bc33df 100644 --- a/test/elixir/test/concurrent_writes_test.exs +++ b/test/elixir/test/concurrent_writes_test.exs @@ -72,4 +72,80 @@ defmodule ConcurrentWritesTest do assert result == Enum.sum(2..n + 1) end + @tag :with_db + test "Secondary data tests with updates and queries", context do + n = 120 + query_every_n = 40 + db_name = context[:db_name] + map_fun = "function(doc) { emit(null, doc.a); }" + red_fun = "_sum" + ddoc_id = "_design/foo" + ddoc = %{:views => %{:foo => %{:map => map_fun, :reduce => red_fun}}} + Couch.put("/#{db_name}/#{ddoc_id}", body: ddoc) + parent = self() + Enum.each(1..n, + fn x -> spawn fn -> + r = Couch.put("/#{db_name}/doc#{x}", body: %{:a => x}) + assert r.status_code == 201 + rev = r.body["rev"] + if rem(x, query_every_n) == 0 do + r = Couch.get("/#{db_name}/#{ddoc_id}/_view/foo") + assert r.status_code == 200 + end + r = Couch.put("/#{db_name}/doc#{x}", body: %{:_rev => rev, :a => x + 1}) + assert r.status_code == 201 + send parent, :done + end end) + Enum.each(1..n, fn _x -> receive do :done -> :done end end) + rows = Couch.get("/#{db_name}/#{ddoc_id}/_view/foo").body["rows"] + result = hd(rows)["value"] + assert result == Enum.sum(2..n + 1) + end + + # The following test was specifically crafted to trigger the issue fixed in: + # https://github.com/apache/couchdb/commit/ec4b2132918338d893a800a823cf5f12d5b2efd5 + # + @tag :with_db + test "Secondary data tests with deletes and queries", context do + n = 120 + query_every_n = 40 + db_name = context[:db_name] + map_fun = "function(doc) { emit(null, doc.a); }" + red_fun = "_sum" + ddoc_id = "_design/foo" + ddoc = %{:views => %{:foo => %{:map => map_fun, :reduce => red_fun}}} + Couch.put("/#{db_name}/#{ddoc_id}", body: ddoc) + parent = self() + Enum.each(1..n, + fn x -> spawn fn -> + r = Couch.put("/#{db_name}/doc#{x}", body: %{:a => x}) + assert r.status_code == 201 + rev = r.body["rev"] + :timer.sleep(:rand.uniform(1000)) + r = Couch.delete("/#{db_name}/doc#{x}?rev=#{rev}") + assert r.status_code == 200 + if rem(x, query_every_n) == 0 do + r = Couch.get("/#{db_name}/#{ddoc_id}/_view/foo") + assert r.status_code == 200 + end + send parent, :done + end end) + Enum.each(1..n, fn _x -> receive do :done -> :done end end) + + # Keep trying to query the view for a bit to account for the case when + # partial view results can be returned. After the following commits merges + # `retry_until` can be removed: + # https://github.com/apache/couchdb/pull/3391/commits/5a82664d1b0b58dd6c9fe6a79faa51e89211969e + # + try do + retry_until(fn -> + [] == Couch.get("/#{db_name}/#{ddoc_id}/_view/foo").body["rows"] + end, 1000, 5000) + rescue + RuntimeError -> :ok + end + + assert [] == Couch.get("/#{db_name}/#{ddoc_id}/_view/foo").body["rows"] + end + end
