summaryrefslogtreecommitdiff
path: root/rel/overlay/share/www/script/test/recreate_doc.js
blob: f9723793b3a6157dbb88cab510b4cc051aa8c350 (plain)
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
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

couchTests.recreate_doc = function(debug) {
  var db = new CouchDB("test_suite_db", {"X-Couch-Full-Commit":"false"});
  db.deleteDb();
  db.createDb();
  if (debug) debugger;

  // First create a new document with the ID "foo", and delete it again
  var doc = {_id: "foo", a: "bar", b: 42};
  var result = db.save(doc);
  T(result.ok);
  var firstRev = result.rev;
  T(db.deleteDoc(doc).ok);

  // Now create a new document with the same ID, save it, and then modify it
  for (var i = 0; i < 10; i++) {
    doc = {_id: "foo"};
    T(db.save(doc).ok);
    doc = db.open("foo");
    doc.a = "baz";
    T(db.save(doc).ok);
    T(db.deleteDoc(doc).rev != undefined);
  }

  try {
    // COUCHDB-292 now attempt to save the document with a prev that's since
    // been deleted and this should generate a conflict exception
    db.save({_id:"foo", _rev:firstRev, bar:1});
    T("no save conflict 1" && false); // we shouldn't hit here
  } catch (e) {
    T(e.error == "conflict");
  }
  
  var binAttDoc = {
    _id: "foo",
    _rev:firstRev,
    _attachments:{
      "foo.txt": {
        content_type:"text/plain",
        data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
      }
    }
  };
  try {
    // same as before, but with binary
    db.save(binAttDoc);
    T("no save conflict 2" && false); // we shouldn't hit here
  } catch (e) {
    T(e.error == "conflict");
  }


  try {
    // random non-existant prev rev
    db.save({_id:"foo", _rev:"1-asfafasdf", bar:1});
    T("no save conflict 3" && false); // we shouldn't hit here
  } catch (e) {
    T(e.error == "conflict");
  }
  
  try {
    // random non-existant prev rev with bin
    binAttDoc._rev = "1-aasasfasdf";
    db.save(binAttDoc);
    T("no save conflict 4" && false); // we shouldn't hit here
  } catch (e) {
    T(e.error == "conflict");
  }

  db.deleteDb();
  db.createDb();

  // Helper function to create a doc with multiple revisions
  // that are compacted away to ?REV_MISSING.

  var createDoc = function(docid) {
    var ret = [{_id: docid, count: 0}];
    T(db.save(ret[0]).ok);
    for(var i = 0; i < 2; i++) {
      ret[ret.length] = {
        _id: docid,
        _rev: ret[ret.length-1]._rev,
        count: ret[ret.length-1].count+1
      };
      T(db.save(ret[ret.length-1]).ok);
    }
    db.compact();
    while(db.info().compact_running) {}
    return ret;
  }

  // Helper function to check that there are no duplicates
  // in the changes feed and that it has proper update
  // sequence ordering.

  var checkChanges = function() {
    // Assert that there are no duplicates in _changes.
    var req = CouchDB.request("GET", "/test_suite_db/_changes");
    var resp = JSON.parse(req.responseText);
    var docids = {};
    var prev_seq = -1;
    for(var i = 0; i < resp.results.length; i++) {
      row = resp.results[i];
      T(row.seq > prev_seq, "Unordered _changes feed.");
      T(docids[row.id] === undefined, "Duplicates in _changes feed.");
      prev_seq = row.seq;
      docids[row.id] = true;
    }
  };

  // COUCHDB-1265 - Check that the changes feed remains proper
  // after we try and break the update_seq tree.

  // This first case is the one originally reported and "fixed"
  // in COUCHDB-1265. Reinserting an old revision into the
  // revision tree causes duplicates in the update_seq tree.

  var revs = createDoc("a");
  T(db.save(revs[1], {new_edits: false}).ok);
  T(db.save(revs[revs.length-1]).ok);
  checkChanges();

  // The original fix for COUCHDB-1265 is not entirely correct
  // as it didn't consider the possibility that a compaction
  // might run after the original tree screw up.

  revs = createDoc("b");
  T(db.save(revs[1], {new_edits: false}).ok);
  db.compact();
  while(db.info().compact_running) {}
  T(db.save(revs[revs.length-1]).ok);
  checkChanges();

};