diff options
Diffstat (limited to 'test/elixir/test/conflicts_test.exs')
-rw-r--r-- | test/elixir/test/conflicts_test.exs | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/test/elixir/test/conflicts_test.exs b/test/elixir/test/conflicts_test.exs new file mode 100644 index 000000000..a27bd6fb6 --- /dev/null +++ b/test/elixir/test/conflicts_test.exs @@ -0,0 +1,102 @@ +defmodule RevisionTest do + use CouchTestCase + + @moduletag :conflicts + + @moduledoc """ + Test CouchDB conflicts + This is a port of conflicts.js + (but is arguably more focused on revisions than conflicts) + """ + + setup context do + # Generate a doc with _rev field for each test + doc = %{_id: "doc-1", a: 1, b: 1} + doc = rev(doc, put(context[:db_name], doc)) + %{doc: doc} + end + + @tag :with_db + test "multiple updates with same _rev raise conflict errors", context do + db = context[:db_name] + doc = context[:doc] + doc2 = %{doc | a: 2, b: 2} # doc and doc2 have same _rev + _doc = rev(doc, put(db, doc)) # doc updated with new _rev + assert_conflict Couch.put("/#{db}/#{doc2._id}", [body: doc2]) + + resp = Couch.get("/#{db}/_changes") + assert length(resp.body["results"]) == 1 + + doc2 = Map.delete(doc2, :_rev) + assert_conflict(Couch.put("/#{db}/#{doc2._id}", [body: doc2])) + end + + @tag :with_db + test "mismatched rev in body and query string returns error", context do + db = context[:db_name] + doc = context[:doc] + resp = Couch.put("/#{db}/#{doc._id}?rev=1-foobar", [body: doc]) + expected_reason = "Document rev from request body and query string " <> + "have different values" + assert_bad_request(resp, expected_reason) + end + + @tag :with_db + test "mismatched rev in body and etag returns error", context do + opts = [body: context[:doc], headers: [{:"If-Match", "1-foobar"}]] + resp = Couch.put("/#{context[:db_name]}/foobar", opts) + expected_reason = "Document rev and etag have different values" + assert_bad_request(resp, expected_reason) + end + + @tag :with_db + test "`new_edits: false` prevents bulk updates (COUCHDB-1178)", context do + db = context[:db_name] + + ddoc = %{_id: "_design/couchdb-1178", validate_doc_update: "function(){}"} + assert put(db, ddoc)["ok"] == true + + r0 = %{_id: "doc", val: "r0"} + r1 = %{_id: "doc", val: "r1", _rev: "1-47f3268e7546965196b57572099f4372"} + r2 = %{_id: "doc", val: "r2", _rev: "2-1d8171ab3a91475cfece749291e6f897"} + r3 = %{_id: "doc", val: "r3", _rev: "3-3fb0a342d2ce092fdcc77856dbe8a2ef"} + assert put(db, r0)["ok"] == true + assert put(db, r1)["ok"] == true + assert put(db, r2)["ok"] == true + # N.b. that we *do not* put r3 + + expected = %{ + "_id" => "doc", + "_rev" => r3._rev, + "_revisions" => %{ + "ids" => (for r <- [r3._rev, r2._rev, r1._rev], do: suffix(r)), + "start" => 3}, + "val" => r2.val} + assert Couch.get("/#{db}/doc?revs=true").body == expected + + opts = [body: %{docs: [r3, r2, r1], new_edits: false}] + assert Couch.post("/#{db}/_bulk_docs", opts).body == [] + end + + + defp put(db, doc) do + Couch.put("/#{db}/#{doc._id}", [body: doc]).body + end + + defp suffix(rev) do + hd(tl(String.split(rev, "-"))) + end + + defp assert_conflict(resp) do + assert resp.status_code == 409 + assert resp.body["error"] == "conflict" + assert resp.body["reason"] == "Document update conflict." + end + + defp assert_bad_request(resp, reason) do + assert resp.status_code == 400 + assert resp.body["error"] == "bad_request" + assert resp.body["reason"] == reason + end + +end |