summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuanjo Rodriguez <juanjo@apache.org>2020-05-09 20:31:15 +0200
committerJuanjo Rodriguez <jjrodrig@gmail.com>2020-05-27 00:25:17 +0200
commitdbed92e2431ca646aff8da39223a34c4891d75bc (patch)
treeec7f57230b6e1c77a7321f87d82e7d0cad0a087b
parentef160d6f32353522f1bfc031b40cd55f5b34d3bb (diff)
downloadcouchdb-dbed92e2431ca646aff8da39223a34c4891d75bc.tar.gz
Port rev_stemming into elixir
-rw-r--r--test/elixir/README.md2
-rw-r--r--test/elixir/test/rev_stemming_test.exs193
-rw-r--r--test/javascript/tests/rev_stemming.js1
3 files changed, 195 insertions, 1 deletions
diff --git a/test/elixir/README.md b/test/elixir/README.md
index 07ad01078..8d73cda16 100644
--- a/test/elixir/README.md
+++ b/test/elixir/README.md
@@ -87,7 +87,7 @@ X means done, - means partially
- [ ] Port replicator_db_update_security.js
- [ ] Port replicator_db_user_ctx.js
- [ ] Port replicator_db_write_auth.js
- - [ ] Port rev_stemming.js
+ - [X] Port rev_stemming.js
- [X] Port rewrite.js
- [ ] Port rewrite_js.js
- [X] Port security_validation.js
diff --git a/test/elixir/test/rev_stemming_test.exs b/test/elixir/test/rev_stemming_test.exs
new file mode 100644
index 000000000..51e959b48
--- /dev/null
+++ b/test/elixir/test/rev_stemming_test.exs
@@ -0,0 +1,193 @@
+defmodule RevStemmingTest do
+ use CouchTestCase
+
+ @moduletag :revs
+
+ @moduledoc """
+ This is a port of the rev_stemming.js suite
+ """
+
+ @new_limit 5
+
+ @tag :with_db
+ test "revs limit update", context do
+ db_name = context[:db_name]
+
+ resp = Couch.get("/#{db_name}/_revs_limit")
+ assert resp.body == 1000
+
+ create_rev_doc(db_name, "foo", @new_limit + 1)
+ resp = Couch.get("/#{db_name}/foo?revs=true")
+ assert length(resp.body["_revisions"]["ids"]) == @new_limit + 1
+
+ resp =
+ Couch.put("/#{db_name}/_revs_limit",
+ body: "#{@new_limit}",
+ headers: ["Content-type": "application/json"]
+ )
+
+ assert resp.status_code == 200
+
+ create_rev_doc(db_name, "foo", @new_limit + 1)
+ resp = Couch.get("/#{db_name}/foo?revs=true")
+ assert length(resp.body["_revisions"]["ids"]) == @new_limit
+ end
+
+ @tag :with_db
+ test "revs limit produces replication conflict ", context do
+ db_name = context[:db_name]
+
+ db_name_b = "#{db_name}_b"
+ create_db(db_name_b)
+ delete_db_on_exit([db_name_b])
+
+ resp =
+ Couch.put("/#{db_name}/_revs_limit",
+ body: "#{@new_limit}",
+ headers: ["Content-type": "application/json"]
+ )
+
+ assert resp.status_code == 200
+
+ create_rev_doc(db_name, "foo", @new_limit + 1)
+ resp = Couch.get("/#{db_name}/foo?revs=true")
+ assert length(resp.body["_revisions"]["ids"]) == @new_limit
+
+ # If you replicate after you make more edits than the limit, you'll
+ # cause a spurious edit conflict.
+ replicate(db_name, db_name_b)
+ resp = Couch.get("/#{db_name_b}/foo?conflicts=true")
+ assert not Map.has_key?(resp.body, "_conflicts")
+
+ create_rev_doc(db_name, "foo", @new_limit - 1)
+
+ # one less edit than limit, no conflict
+ replicate(db_name, db_name_b)
+ resp = Couch.get("/#{db_name_b}/foo?conflicts=true")
+ assert not Map.has_key?(resp.body, "_conflicts")
+ prev_conflicted_rev = resp.body["_rev"]
+
+ # now we hit the limit
+ create_rev_doc(db_name, "foo", @new_limit + 1)
+
+ replicate(db_name, db_name_b)
+ resp = Couch.get("/#{db_name_b}/foo?conflicts=true")
+ assert Map.has_key?(resp.body, "_conflicts")
+
+ conflicted_rev =
+ resp.body["_conflicts"]
+ |> Enum.at(0)
+
+ # we have a conflict, but the previous replicated rev is always the losing
+ # conflict
+ assert conflicted_rev == prev_conflicted_rev
+ end
+
+ @tag :with_db
+ test "revs limit is kept after compaction", context do
+ db_name = context[:db_name]
+
+ create_rev_doc(db_name, "bar", @new_limit + 1)
+ resp = Couch.get("/#{db_name}/bar?revs=true")
+ assert length(resp.body["_revisions"]["ids"]) == @new_limit + 1
+
+ resp =
+ Couch.put("/#{db_name}/_revs_limit",
+ body: "#{@new_limit}",
+ headers: ["Content-type": "application/json"]
+ )
+
+ assert resp.status_code == 200
+
+ # We having already updated bar before setting the limit, so it's still got
+ # a long rev history. compact to stem the revs.
+ resp = Couch.get("/#{db_name}/bar?revs=true")
+ assert length(resp.body["_revisions"]["ids"]) == @new_limit
+
+ compact(db_name)
+ wait_until_compact_complete(db_name)
+
+ # force reload because ETags don't honour compaction
+ resp =
+ Couch.get("/#{db_name}/bar?revs=true",
+ headers: ["if-none-match": "pommes"]
+ )
+
+ assert length(resp.body["_revisions"]["ids"]) == @new_limit
+ end
+
+ # function to create a doc with multiple revisions
+ defp create_rev_doc(db_name, id, num_revs) do
+ resp = Couch.get("/#{db_name}/#{id}")
+
+ doc =
+ if resp.status_code == 200 do
+ resp.body
+ else
+ %{_id: id, count: 0}
+ end
+
+ {:ok, resp} = create_doc(db_name, doc)
+ create_rev_doc(db_name, id, num_revs, [Map.put(doc, :_rev, resp.body["rev"])])
+ end
+
+ defp create_rev_doc(db_name, id, num_revs, revs) do
+ if length(revs) < num_revs do
+ doc = %{_id: id, _rev: Enum.at(revs, -1)[:_rev], count: length(revs)}
+ {:ok, resp} = create_doc(db_name, doc)
+
+ create_rev_doc(
+ db_name,
+ id,
+ num_revs,
+ revs ++ [Map.put(doc, :_rev, resp.body["rev"])]
+ )
+ else
+ revs
+ end
+ end
+
+ defp build_uri(db_name) do
+ username = System.get_env("EX_USERNAME") || "adm"
+ password = System.get_env("EX_PASSWORD") || "pass"
+
+ "/#{db_name}"
+ |> Couch.process_url()
+ |> URI.parse()
+ |> Map.put(:userinfo, "#{username}:#{password}")
+ |> URI.to_string()
+ end
+
+ defp replicate(src, tgt) do
+ src_uri = build_uri(src)
+ tgt_uri = build_uri(tgt)
+
+ body = %{source: src_uri, target: tgt_uri}
+
+ resp = Couch.post("/_replicate", body: body)
+ assert resp.status_code == 200
+ resp.body
+ end
+
+ def delete_db_on_exit(db_names) when is_list(db_names) do
+ on_exit(fn ->
+ Enum.each(db_names, fn name ->
+ delete_db(name)
+ end)
+ end)
+ end
+
+ defp compact(db_name) do
+ resp = Couch.post("/#{db_name}/_compact")
+ assert resp.status_code == 202
+ resp.body
+ end
+
+ defp wait_until_compact_complete(db_name) do
+ retry_until(
+ fn -> Map.get(info(db_name), "compact_running") == false end,
+ 200,
+ 10_000
+ )
+ end
+end
diff --git a/test/javascript/tests/rev_stemming.js b/test/javascript/tests/rev_stemming.js
index 238868f60..725c0f1c9 100644
--- a/test/javascript/tests/rev_stemming.js
+++ b/test/javascript/tests/rev_stemming.js
@@ -10,6 +10,7 @@
// License for the specific language governing permissions and limitations under
// the License.
+couchTests.elixir = true;
couchTests.rev_stemming = function(debug) {
var db_name_orig = get_random_db_name();