summaryrefslogtreecommitdiff
path: root/test/elixir/test/conflicts_test.exs
diff options
context:
space:
mode:
Diffstat (limited to 'test/elixir/test/conflicts_test.exs')
-rw-r--r--test/elixir/test/conflicts_test.exs102
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