1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
defmodule RecreateDocTest do
use CouchTestCase
@moduletag :recreate_doc
@moduletag kind: :single_node
@moduledoc """
Test CouchDB document recreation
This is a port of the recreate_doc.js suite
"""
@tag :with_db
test "recreate document", context do
db_name = context[:db_name]
# First create a new document with the ID "foo", and delete it again
doc = %{_id: "foo", a: "bar", b: 42}
{:ok, resp} = create_doc(db_name, doc)
first_rev = resp.body["rev"]
resp = Couch.delete("/#{db_name}/foo?rev=#{first_rev}")
assert resp.status_code == 200
# Now create a new document with the same ID, save it, and then modify it
doc = %{_id: "foo"}
for _i <- 0..9 do
{:ok, _} = create_doc(db_name, doc)
resp = Couch.get("/#{db_name}/foo")
updated_doc =
resp.body
|> Map.put("a", "baz")
resp = Couch.put("/#{db_name}/foo", body: updated_doc)
assert resp.status_code == 201
rev = resp.body["rev"]
resp = Couch.delete("/#{db_name}/foo?rev=#{rev}")
assert resp.status_code == 200
end
end
@tag :with_db
test "COUCHDB-292 - recreate a deleted document", context do
db_name = context[:db_name]
# First create a new document with the ID "foo", and delete it again
doc = %{_id: "foo", a: "bar", b: 42}
{:ok, resp} = create_doc(db_name, doc)
first_rev = resp.body["rev"]
resp = Couch.delete("/#{db_name}/foo?rev=#{first_rev}")
assert resp.status_code == 200
# COUCHDB-292 now attempt to save the document with a prev that's since
# been deleted and this should generate a conflict exception
updated_doc =
doc
|> Map.put(:_rev, first_rev)
resp = Couch.put("/#{db_name}/foo", body: updated_doc)
assert resp.status_code == 409
# same as before, but with binary
bin_att_doc = %{
_id: "foo",
_rev: first_rev,
_attachments: %{
"foo.txt": %{
content_type: "text/plain",
data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
}
}
}
resp = Couch.put("/#{db_name}/foo", body: bin_att_doc)
assert resp.status_code == 409
end
@tag :with_db
test "Recreate a deleted document with non-exsistant rev", context do
db_name = context[:db_name]
doc = %{_id: "foo", a: "bar", b: 42}
{:ok, resp} = create_doc(db_name, doc)
first_rev = resp.body["rev"]
resp = Couch.delete("/#{db_name}/foo?rev=#{first_rev}")
assert resp.status_code == 200
# random non-existant prev rev
updated_doc =
doc
|> Map.put(:_rev, "1-asfafasdf")
resp = Couch.put("/#{db_name}/foo", body: updated_doc)
assert resp.status_code == 409
# random non-existant prev rev with bin
bin_att_doc = %{
_id: "foo",
_rev: "1-aasasfasdf",
_attachments: %{
"foo.txt": %{
content_type: "text/plain",
data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
}
}
}
resp = Couch.put("/#{db_name}/foo", body: bin_att_doc)
assert resp.status_code == 409
end
@tag :with_db
test "COUCHDB-1265 - changes feed after we try and break the update_seq tree",
context do
db_name = context[:db_name]
# Test COUCHDB-1265 - Reinserting an old revision into the revision tree causes
# duplicates in the update_seq tree.
revs = create_rev_doc(db_name, "a", 3)
resp =
Couch.put("/#{db_name}/a",
body: Enum.at(revs, 0),
query: [new_edits: false]
)
assert resp.status_code == 201
resp =
Couch.put("/#{db_name}/a",
body: Enum.at(revs, -1)
)
assert resp.status_code == 201
resp = Couch.get("/#{db_name}/_changes")
assert resp.status_code == 200
assert length(resp.body["results"]) == 1
end
# function to create a doc with multiple revisions
defp create_rev_doc(db_name, id, num_revs) do
doc = %{_id: id, count: 0}
{: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
end
|