'use strict'; var PouchDB = require('./pouchdb'); var should = require('chai').should(); var testUtils = require('./test.utils.js'); var adapters = ['local']; function makeDocs(start, end, templateDoc) { var templateDocSrc = templateDoc ? JSON.stringify(templateDoc) : '{}'; if (end === undefined) { end = start; start = 0; } var docs = []; for (var i = start; i < end; i++) { /*jshint evil:true */ var newDoc = eval('(' + templateDocSrc + ')'); newDoc._id = i.toString(); newDoc.integer = i; newDoc.string = i.toString(); docs.push(newDoc); } return docs; } adapters.forEach(function (adapter) { describe('test.bulk_docs.js-' + adapter, function () { var dbs = {}; beforeEach(function (done) { dbs.name = testUtils.adapterUrl(adapter, 'testdb'); testUtils.cleanup([dbs.name], done); }); after(function (done) { testUtils.cleanup([dbs.name], done); }); var authors = [ {name: 'Dale Harvey', commits: 253}, {name: 'Mikeal Rogers', commits: 42}, {name: 'Johannes J. Schmidt', commits: 13}, {name: 'Randall Leeds', commits: 9} ]; it('Testing bulk docs', function (done) { var db = new PouchDB(dbs.name); var docs = makeDocs(5); db.bulkDocs({ docs: docs }, function (err, results) { results.should.have.length(5, 'results length matches'); for (var i = 0; i < 5; i++) { results[i].id.should.equal(docs[i]._id, 'id matches'); should.exist(results[i].rev, 'rev is set'); // Update the doc docs[i]._rev = results[i].rev; docs[i].string = docs[i].string + '.00'; } db.bulkDocs({ docs: docs }, function (err, results) { results.should.have.length(5, 'results length matches'); for (i = 0; i < 5; i++) { results[i].id.should.equal(i.toString(), 'id matches again'); // set the delete flag to delete the docs in the next step docs[i]._rev = results[i].rev; docs[i]._deleted = true; } db.put(docs[0], function () { db.bulkDocs({ docs: docs }, function (err, results) { results[0].name.should.equal( 'conflict', 'First doc should be in conflict'); should.not.exist(results[0].rev, 'no rev in conflict'); for (i = 1; i < 5; i++) { results[i].id.should.equal(i.toString()); should.exist(results[i].rev); } done(); }); }); }); }); }); it('No id in bulk docs', function (done) { var db = new PouchDB(dbs.name); var newdoc = { '_id': 'foobar', 'body': 'baz' }; db.put(newdoc, function (err, doc) { should.exist(doc.ok); var docs = [ { '_id': newdoc._id, '_rev': newdoc._rev, 'body': 'blam' }, { '_id': newdoc._id, '_rev': newdoc._rev, '_deleted': true } ]; db.bulkDocs({ docs: docs }, function (err, results) { results[0].should.have.property('name', 'conflict'); results[1].should.have.property('name', 'conflict'); done(); }); }); }); it('No _rev and new_edits=false', function (done) { var db = new PouchDB(dbs.name); var docs = [{ _id: 'foo', integer: 1 }]; db.bulkDocs({ docs: docs }, { new_edits: false }, function (err) { should.exist(err, 'error reported'); done(); }); }); it('Test empty bulkDocs', function () { var db = new PouchDB(dbs.name); return db.bulkDocs([]); }); it('Test many bulkDocs', function () { var db = new PouchDB(dbs.name); var docs = []; for (var i = 0; i < 201; i++) { docs.push({_id: i.toString()}); } return db.bulkDocs(docs); }); it('Test errors on invalid doc id', function (done) { var db = new PouchDB(dbs.name); var docs = [{ '_id': '_invalid', foo: 'bar' }]; db.bulkDocs({ docs: docs }, function (err, info) { err.status.should.equal(PouchDB.Errors.RESERVED_ID.status, 'correct error status returned'); should.not.exist(info, 'info is empty'); done(); }); }); it('Test two errors on invalid doc id', function (done) { var docs = [ {'_id': '_invalid', foo: 'bar'}, {'_id': 123, foo: 'bar'} ]; var db = new PouchDB(dbs.name); db.bulkDocs({ docs: docs }, function (err, info) { err.status.should.equal(PouchDB.Errors.RESERVED_ID.status, 'correct error returned'); should.not.exist(info, 'info is empty'); done(); }); }); it('No docs', function (done) { var db = new PouchDB(dbs.name); db.bulkDocs({ 'doc': [{ 'foo': 'bar' }] }, function (err) { err.status.should.equal(PouchDB.Errors.MISSING_BULK_DOCS.status, 'correct error returned'); err.message.should.equal(PouchDB.Errors.MISSING_BULK_DOCS.message, 'correct error message returned'); done(); }); }); it('Jira 911', function (done) { var db = new PouchDB(dbs.name); var docs = [ {'_id': '0', 'a': 0}, {'_id': '1', 'a': 1}, {'_id': '1', 'a': 1}, {'_id': '3', 'a': 3} ]; db.bulkDocs({ docs: docs }, function (err, results) { results[1].id.should.equal('1', 'check ordering'); should.not.exist(results[1].name, 'first id succeded'); results[2].name.should.equal('conflict', 'second conflicted'); results.should.have.length(4, 'got right amount of results'); done(); }); }); it('Test multiple bulkdocs', function (done) { var db = new PouchDB(dbs.name); db.bulkDocs({ docs: authors }, function () { db.bulkDocs({ docs: authors }, function () { db.allDocs(function (err, result) { result.total_rows.should.equal(8, 'correct number of results'); done(); }); }); }); }); it('#2935 new_edits=false correct number', function () { var docs = [ { "_id": "EE35E", "_rev": "4-70b26", "_deleted": true, "_revisions": { "start": 4, "ids": ["70b26", "9f454", "914bf", "7fdf8"] } }, { "_id": "EE35E", "_rev": "3-f6d28", "_revisions": {"start": 3, "ids": ["f6d28", "914bf", "7fdf8"]} } ]; var db = new PouchDB(dbs.name); return db.bulkDocs({docs: docs, new_edits: false}).then(function (res) { res.should.deep.equal([]); return db.allDocs(); }).then(function (res) { res.total_rows.should.equal(1); return db.info(); }).then(function (info) { info.doc_count.should.equal(1); }); }); it('#2935 new_edits=false correct number 2', function () { var docs = [ { "_id": "EE35E", "_rev": "3-f6d28", "_revisions": {"start": 3, "ids": ["f6d28", "914bf", "7fdf8"]} }, { "_id": "EE35E", "_rev": "4-70b26", "_deleted": true, "_revisions": { "start": 4, "ids": ["70b26", "9f454", "914bf", "7fdf8"] } } ]; var db = new PouchDB(dbs.name); return db.bulkDocs({docs: docs, new_edits: false}).then(function (res) { res.should.deep.equal([]); return db.allDocs(); }).then(function (res) { res.total_rows.should.equal(1); return db.info(); }).then(function (info) { info.doc_count.should.equal(1); }); }); it('#2935 new_edits=false with single unauthorized', function (done) { testUtils.isCouchDB(function (isCouchDB) { if (adapter !== 'http' || !isCouchDB) { return done(); } var ddoc = { "_id": "_design/validate", "validate_doc_update": function (newDoc) { if (newDoc.foo === undefined) { throw {unauthorized: 'Document must have a foo.'}; } }.toString() }; var db = new PouchDB(dbs.name); db.put(ddoc).then(function () { return db.bulkDocs({ docs: [ { '_id': 'doc0', '_rev': '1-x', 'foo': 'bar', '_revisions': { 'start': 1, 'ids': ['x'] } }, { '_id': 'doc1', '_rev': '1-x', '_revisions': { 'start': 1, 'ids': ['x'] } }, { '_id': 'doc2', '_rev': '1-x', 'foo': 'bar', '_revisions': { 'start': 1, 'ids': ['x'] } } ] }, {new_edits: false}); }).then(function (res) { res.should.have.length(1); should.exist(res[0].error); res[0].id.should.equal('doc1'); }).then(done); }); }); it('Deleting _local docs with bulkDocs' , function () { var db = new PouchDB(dbs.name); var rev1; var rev2; var rev3; return db.put({_id: '_local/godzilla'}).then(function (info) { rev1 = info.rev; return db.put({_id: 'mothra'}); }).then(function (info) { rev2 = info.rev; return db.put({_id: 'rodan'}); }).then(function (info) { rev3 = info.rev; return db.bulkDocs([ {_id: 'mothra', _rev: rev2, _deleted: true}, {_id: '_local/godzilla', _rev: rev1, _deleted: true}, {_id: 'rodan', _rev: rev3, _deleted: true} ]); }).then(function () { return db.allDocs(); }).then(function (info) { info.rows.should.have.length(0); return db.get('_local/godzilla').then(function () { throw new Error('expected 404'); }, function (err) { should.exist(err); }); }); }); if (adapter === 'local') { // these tests crash CouchDB with a 500, neat // https://issues.apache.org/jira/browse/COUCHDB-2758 it('Deleting _local docs with bulkDocs, not found', function () { var db = new PouchDB(dbs.name); var rev2; var rev3; return db.put({_id: 'mothra'}).then(function (info) { rev2 = info.rev; return db.put({_id: 'rodan'}); }).then(function (info) { rev3 = info.rev; return db.bulkDocs([ {_id: 'mothra', _rev: rev2, _deleted: true}, {_id: '_local/godzilla', _rev: '1-fake', _deleted: true}, {_id: 'rodan', _rev: rev3, _deleted: true} ]); }).then(function (res) { should.not.exist(res[0].error); should.exist(res[1].error); should.not.exist(res[2].error); }); }); it('Deleting _local docs with bulkDocs, wrong rev', function () { var db = new PouchDB(dbs.name); var rev2; var rev3; return db.put({_id: '_local/godzilla'}).then(function () { return db.put({_id: 'mothra'}); }).then(function (info) { rev2 = info.rev; return db.put({_id: 'rodan'}); }).then(function (info) { rev3 = info.rev; return db.bulkDocs([ {_id: 'mothra', _rev: rev2, _deleted: true}, {_id: '_local/godzilla', _rev: '1-fake', _deleted: true}, {_id: 'rodan', _rev: rev3, _deleted: true} ]); }).then(function (res) { should.not.exist(res[0].error); should.exist(res[1].error); should.not.exist(res[2].error); }); }); } it('Bulk with new_edits=false', function (done) { var db = new PouchDB(dbs.name); var docs = [{ '_id': 'foo', '_rev': '2-x', '_revisions': { 'start': 2, 'ids': ['x', 'a'] } }, { '_id': 'foo', '_rev': '2-y', '_revisions': { 'start': 2, 'ids': ['y', 'a'] } }]; db.bulkDocs({docs: docs}, {new_edits: false}, function () { db.get('foo', {open_revs: 'all'}, function (err, res) { res.sort(function (a, b) { return a.ok._rev < b.ok._rev ? -1 : a.ok._rev > b.ok._rev ? 1 : 0; }); res.length.should.equal(2); res[0].ok._rev.should.equal('2-x', 'doc1 ok'); res[1].ok._rev.should.equal('2-y', 'doc2 ok'); done(); }); }); }); it('Testing successive new_edits to the same doc', function (done) { var db = new PouchDB(dbs.name); var docs = [{ '_id': 'foobar123', '_rev': '1-x', 'bar': 'huzzah', '_revisions': { 'start': 1, 'ids': ['x'] } }]; db.bulkDocs({docs: docs, new_edits: false}, function (err) { should.not.exist(err); db.bulkDocs({docs: docs, new_edits: false}, function (err) { should.not.exist(err); db.get('foobar123', function (err, res) { res._rev.should.equal('1-x'); done(); }); }); }); }); it('#3062 bulkDocs with staggered seqs', function () { return new PouchDB(dbs.name).then(function (db) { var docs = []; for (var i = 10; i <= 20; i++) { docs.push({ _id: 'doc-' + i}); } return db.bulkDocs({docs: docs}).then(function (infos) { docs.forEach(function (doc, i) { doc._rev = infos[i].rev; }); var docsToUpdate = docs.filter(function (doc, i) { return i % 2 === 1; }); docsToUpdate.reverse(); return db.bulkDocs({docs: docsToUpdate}); }).then(function (infos) { infos.map(function (x) { return {id: x.id, error: !!x.error, rev: (typeof x.rev)}; }).should.deep.equal([ { error: false, id: 'doc-19', rev: 'string'}, { error: false, id: 'doc-17', rev: 'string'}, { error: false, id: 'doc-15', rev: 'string'}, { error: false, id: 'doc-13', rev: 'string'}, { error: false, id: 'doc-11', rev: 'string'} ]); }); }); }); it('Testing successive new_edits to the same doc, different content', function (done) { var db = new PouchDB(dbs.name); var docsA = [{ '_id': 'foo321', '_rev': '1-x', 'bar' : 'baz', '_revisions': { 'start': 1, 'ids': ['x'] } }, { '_id' : 'fee321', 'bar': 'quux', '_rev': '1-x', '_revisions': { 'start': 1, 'ids': ['x'] } }]; var docsB = [{ '_id': 'foo321', '_rev': '1-x', 'bar' : 'zam', // this update should be rejected '_revisions': { 'start': 1, 'ids': ['x'] } }, { '_id' : 'faa321', '_rev': '1-x', 'bar': 'zul', '_revisions': { 'start': 1, 'ids': ['x'] } }]; db.bulkDocs({docs: docsA, new_edits: false}, function (err) { should.not.exist(err); db.changes().on('complete', function (result) { var ids = result.results.map(function (row) { return row.id; }); ids.should.include("foo321"); ids.should.include("fee321"); ids.should.not.include("faa321"); var update_seq = result.last_seq; db.bulkDocs({docs: docsB, new_edits: false}, function (err) { should.not.exist(err); db.changes({ since: update_seq }).on('complete', function (result) { var ids = result.results.map(function (row) { return row.id; }); ids.should.not.include("foo321"); ids.should.not.include("fee321"); ids.should.include("faa321"); db.get('foo321', function (err, res) { res._rev.should.equal('1-x'); res.bar.should.equal("baz"); db.info(function (err, info) { info.doc_count.should.equal(3); done(); }); }); }).on('error', done); }); }).on('error', done); }); }); it('Testing successive new_edits to two doc', function () { var db = new PouchDB(dbs.name); var doc1 = { '_id': 'foo', '_rev': '1-x', '_revisions': { 'start': 1, 'ids': ['x'] } }; var doc2 = { '_id': 'bar', '_rev': '1-x', '_revisions': { 'start': 1, 'ids': ['x'] } }; return db.put(doc1, {new_edits: false}).then(function () { return db.put(doc2, {new_edits: false}); }).then(function () { return db.put(doc1, {new_edits: false}); }).then(function () { return db.get('foo'); }).then(function () { return db.get('bar'); }); }); it('Deletion with new_edits=false', function () { var db = new PouchDB(dbs.name); var doc1 = { '_id': 'foo', '_rev': '1-x', '_revisions': { 'start': 1, 'ids': ['x'] } }; var doc2 = { '_deleted': true, '_id': 'foo', '_rev': '2-y', '_revisions': { 'start': 2, 'ids': ['y', 'x'] } }; return db.put(doc1, {new_edits: false}).then(function () { return db.put(doc2, {new_edits: false}); }).then(function () { return db.allDocs({keys: ['foo']}); }).then(function (res) { res.rows[0].value.rev.should.equal('2-y'); res.rows[0].value.deleted.should.equal(true); }); }); it('Deletion with new_edits=false, no history', function () { var db = new PouchDB(dbs.name); var doc1 = { '_id': 'foo', '_rev': '1-x', '_revisions': { 'start': 1, 'ids': ['x'] } }; var doc2 = { '_deleted': true, '_id': 'foo', '_rev': '2-y' }; return db.put(doc1, {new_edits: false}).then(function () { return db.put(doc2, {new_edits: false}); }).then(function () { return db.allDocs({keys: ['foo']}); }).then(function (res) { res.rows[0].value.rev.should.equal('1-x'); should.equal(!!res.rows[0].value.deleted, false); }); }); it('Modification with new_edits=false, no history', function () { var db = new PouchDB(dbs.name); var doc1 = { '_id': 'foo', '_rev': '1-x', '_revisions': { 'start': 1, 'ids': ['x'] } }; var doc2 = { '_id': 'foo', '_rev': '2-y' }; return db.put(doc1, {new_edits: false}).then(function () { return db.put(doc2, {new_edits: false}); }).then(function () { return db.allDocs({keys: ['foo']}); }).then(function (res) { res.rows[0].value.rev.should.equal('2-y'); }); }); it('Deletion with new_edits=false, no history, no revisions', function () { var db = new PouchDB(dbs.name); var doc = { '_deleted': true, '_id': 'foo', '_rev': '2-y' }; return db.put(doc, {new_edits: false}).then(function () { return db.allDocs({keys: ['foo']}); }).then(function (res) { res.rows[0].value.rev.should.equal('2-y'); res.rows[0].value.deleted.should.equal(true); }); }); it('Testing new_edits=false in req body', function (done) { var db = new PouchDB(dbs.name); var docs = [{ '_id': 'foo', '_rev': '2-x', '_revisions': { 'start': 2, 'ids': ['x', 'a'] } }, { '_id': 'foo', '_rev': '2-y', '_revisions': { 'start': 2, 'ids': ['y', 'a'] } }]; db.bulkDocs({docs: docs, new_edits: false}, function () { db.get('foo', {open_revs: 'all'}, function (err, res) { res.sort(function (a, b) { return a.ok._rev < b.ok._rev ? -1 : a.ok._rev > b.ok._rev ? 1 : 0; }); res.length.should.equal(2); res[0].ok._rev.should.equal('2-x', 'doc1 ok'); res[1].ok._rev.should.equal('2-y', 'doc2 ok'); done(); }); }); }); it('656 regression in handling deleted docs', function (done) { var db = new PouchDB(dbs.name); db.bulkDocs({ docs: [{ _id: 'foo', _rev: '1-a', _deleted: true }] }, { new_edits: false }, function () { db.get('foo', function (err) { should.exist(err, 'deleted'); err.status.should.equal(PouchDB.Errors.MISSING_DOC.status, 'correct error status returned'); err.message.should.equal(PouchDB.Errors.MISSING_DOC.message, 'correct error message returned'); // todo: does not work in pouchdb-server. // err.reason.should.equal('deleted', // 'correct error reason returned'); done(); }); }); }); it('Test quotes in doc ids', function (done) { var db = new PouchDB(dbs.name); var docs = [{ _id: '\'your_sql_injection_script_here\'' }]; db.bulkDocs({docs: docs}, function (err) { should.not.exist(err, 'got error: ' + JSON.stringify(err)); db.get('foo', function (err) { should.exist(err, 'deleted'); done(); }); }); }); it('Bulk docs empty list', function (done) { var db = new PouchDB(dbs.name); db.bulkDocs({ docs: [] }, function (err) { done(err); }); }); it('handles simultaneous writes', function (done) { var db1 = new PouchDB(dbs.name); var db2 = new PouchDB(dbs.name); var id = 'fooId'; var errorNames = []; var ids = []; var numDone = 0; function callback(err, res) { should.not.exist(err); if (res[0].error) { errorNames.push(res[0].name); } else { ids.push(res[0].id); } if (++numDone === 2) { errorNames.should.deep.equal(['conflict']); ids.should.deep.equal([id]); done(); } } db1.bulkDocs({docs : [{_id : id}]}, callback); db2.bulkDocs({docs : [{_id : id}]}, callback); }); it('bulk docs input by array', function (done) { var db = new PouchDB(dbs.name); var docs = makeDocs(5); db.bulkDocs(docs, function (err, results) { results.should.have.length(5, 'results length matches'); for (var i = 0; i < 5; i++) { results[i].id.should.equal(docs[i]._id, 'id matches'); should.exist(results[i].rev, 'rev is set'); // Update the doc docs[i]._rev = results[i].rev; docs[i].string = docs[i].string + '.00'; } db.bulkDocs(docs, function (err, results) { results.should.have.length(5, 'results length matches'); for (i = 0; i < 5; i++) { results[i].id.should.equal(i.toString(), 'id matches again'); // set the delete flag to delete the docs in the next step docs[i]._rev = results[i].rev; docs[i]._deleted = true; } db.put(docs[0], function () { db.bulkDocs(docs, function (err, results) { results[0].name.should.equal( 'conflict', 'First doc should be in conflict'); should.not.exist(results[0].rev, 'no rev in conflict'); for (i = 1; i < 5; i++) { results[i].id.should.equal(i.toString()); should.exist(results[i].rev); } done(); }); }); }); }); }); it('Bulk empty list', function (done) { var db = new PouchDB(dbs.name); db.bulkDocs([], function (err) { done(err); }); }); it('Bulk docs not an array', function (done) { var db = new PouchDB(dbs.name); db.bulkDocs({ docs: 'foo' }, function (err) { should.exist(err, 'error reported'); err.status.should.equal(PouchDB.Errors.MISSING_BULK_DOCS.status, 'correct error status returned'); err.message.should.equal(PouchDB.Errors.MISSING_BULK_DOCS.message, 'correct error message returned'); done(); }); }); it('Bulk docs not an object', function (done) { var db = new PouchDB(dbs.name); db.bulkDocs({ docs: ['foo'] }, function (err) { should.exist(err, 'error reported'); err.status.should.equal(PouchDB.Errors.NOT_AN_OBJECT.status, 'correct error status returned'); err.message.should.equal(PouchDB.Errors.NOT_AN_OBJECT.message, 'correct error message returned'); }); db.bulkDocs({ docs: [[]] }, function (err) { should.exist(err, 'error reported'); err.status.should.equal(PouchDB.Errors.NOT_AN_OBJECT.status, 'correct error status returned'); err.message.should.equal(PouchDB.Errors.NOT_AN_OBJECT.message, 'correct error message returned'); done(); }); }); it('Bulk docs two different revisions to same document id', function(done) { var db = new PouchDB(dbs.name); var docid = "mydoc"; function uuid() { return PouchDB.utils.uuid(32, 16).toLowerCase(); } // create a few of rando, good revisions var numRevs = 3; var uuids = []; for (var i = 0; i < numRevs - 1; i++) { uuids.push(uuid()); } // branch 1 var a_conflict = uuid(); var a_doc = { _id: docid, _rev: numRevs + '-' + a_conflict, _revisions: { start: numRevs, ids: [ a_conflict ].concat(uuids) } }; // branch 2 var b_conflict = uuid(); var b_doc = { _id: docid, _rev: numRevs + '-' + b_conflict, _revisions: { start: numRevs, ids: [ b_conflict ].concat(uuids) } }; // push the conflicted documents return db.bulkDocs([ a_doc, b_doc ], { new_edits: false }) .then(function() { return db.get(docid, { open_revs: "all" }).then(function(resp) { resp.length.should.equal(2, 'correct number of open revisions'); resp[0].ok._id.should.equal(docid, 'rev 1, correct document id'); resp[1].ok._id.should.equal(docid, 'rev 2, correct document id'); // order of revisions is not specified ((resp[0].ok._rev === a_doc._rev && resp[1].ok._rev === b_doc._rev) || (resp[0].ok._rev === b_doc._rev && resp[1].ok._rev === a_doc._rev)).should.equal(true); }); }) .then(function() { done(); }, done); }); it('4204 respect revs_limit', function () { var db = new PouchDB(dbs.name); // simulate 5000 normal commits with two conflicts at the very end function uuid() { return PouchDB.utils.uuid(32, 16).toLowerCase(); } var isSafari = (typeof process === 'undefined' || process.browser) && /Safari/.test(window.navigator.userAgent) && !/Chrome/.test(window.navigator.userAgent); var numRevs = isSafari ? 10 : 5000; var expected = isSafari ? 10 : 1000; var uuids = []; for (var i = 0; i < numRevs - 1; i++) { uuids.push(uuid()); } var conflict1 = 'a' + uuid(); var doc1 = { _id: 'doc', _rev: numRevs + '-' + conflict1, _revisions: { start: numRevs, ids: [conflict1].concat(uuids) } }; return db.bulkDocs([doc1], {new_edits: false}).then(function () { return db.get('doc', {revs: true}); }).then(function (doc) { doc._revisions.ids.length.should.equal(expected); }); }); it('2839 implement revs_limit', function (done) { // We only implement revs_limit locally if (adapter === 'http') { return done(); } var LIMIT = 50; var db = new PouchDB(dbs.name, {revs_limit: LIMIT}); // simulate 5000 normal commits with two conflicts at the very end function uuid() { return PouchDB.utils.uuid(32, 16).toLowerCase(); } var numRevs = 5000; var uuids = []; for (var i = 0; i < numRevs - 1; i++) { uuids.push(uuid()); } var conflict1 = 'a' + uuid(); var doc1 = { _id: 'doc', _rev: numRevs + '-' + conflict1, _revisions: { start: numRevs, ids: [conflict1].concat(uuids) } }; db.bulkDocs([doc1], {new_edits: false}).then(function () { return db.get('doc', {revs: true}); }).then(function (doc) { doc._revisions.ids.length.should.equal(LIMIT); done(); }).catch(done); }); it('4372 revs_limit deletes old revisions of the doc', function (done) { // We only implement revs_limit locally if (adapter === 'http') { return done(); } var db = new PouchDB(dbs.name, {revs_limit: 2}); // old revisions are always deleted with auto compaction if (db.auto_compaction) { return done(); } var revs = []; db.put({v: 1}, 'doc').then(function (v1) { revs.push(v1.rev); return db.put({v: 2}, 'doc', revs[0]); }).then(function (v2) { revs.push(v2.rev); return db.put({v: 3}, 'doc', revs[1]); }).then(function () { // the v2 revision is still in the db return db.get('doc', {rev: revs[1]}); }).then(function (v2) { v2.v.should.equal(2); return db.get('doc', {rev: revs[0]}).then(function () { // the v1 revision is not in the db anymore done(new Error('v1 should be missing')); }).catch(function (error) { error.message.should.equal('missing'); done(); }); }).catch(done); }); it('4712 invalid rev for new doc generates conflict', function () { // CouchDB 1.X has a bug which allows this insertion via bulk_docs // (which PouchDB uses for all document insertions) if (adapter === 'http' && !testUtils.isCouchMaster()) { return; } var db = new PouchDB(dbs.name); var newdoc = { '_id': 'foobar', '_rev': '1-123' }; return db.bulkDocs({ docs: [newdoc] }).then (function (results) { results[0].should.have.property('status', 409); }); }); }); });