blob: 8a47bd18ce26c10182b8159ef61328310fb9fdf1 [file] [log] [blame]
'use strict';
var adapters = ['http', 'local'];
adapters.forEach(function (adapter) {
describe('test.conflicts.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);
});
it('Testing conflicts', function (done) {
var db = new PouchDB(dbs.name);
var doc = {_id: 'foo', a: 1, b: 1};
db.put(doc, function (err, res) {
doc._rev = res.rev;
should.exist(res.ok, 'Put first document');
db.get('foo', function (err, doc2) {
doc._id.should.equal(doc2._id);
doc.should.have.property('_rev');
doc2.should.have.property('_rev');
doc.a = 2;
doc2.a = 3;
db.put(doc, function (err, res) {
should.exist(res.ok, 'Put second doc');
db.put(doc2, function (err) {
err.name.should.equal('conflict', 'Put got a conflicts');
db.changes().on('complete', function (results) {
results.results.should.have.length(1);
doc2._rev = undefined;
db.put(doc2, function (err) {
err.name.should.equal('conflict', 'Another conflict');
done();
});
}).on('error', done);
});
});
});
});
});
it('Testing conflicts', function (done) {
var doc = {_id: 'fubar', a: 1, b: 1};
var db = new PouchDB(dbs.name);
db.put(doc, function (err, ndoc) {
doc._rev = ndoc.rev;
db.remove(doc, function () {
delete doc._rev;
db.put(doc, function (err, ndoc) {
if (err) {
return done(err);
}
should.exist(ndoc.ok, 'written previously deleted doc without rev');
done();
});
});
});
});
it('#2882/#2883 last_seq for empty db', function () {
// CouchDB 2.0 sequence numbers are not
// incremental so skip this test
if (testUtils.isCouchMaster()) {
return true;
}
var db = new PouchDB(dbs.name);
return db.changes().then(function (changes) {
changes.last_seq.should.equal(0);
changes.results.should.have.length(0);
return db.info();
}).then(function (info) {
info.update_seq.should.equal(0);
});
});
it('#2882/#2883 last_seq when putting parent before leaf', function () {
// CouchDB 2.0 sequence numbers are not
// incremental so skip this test
if (testUtils.isCouchMaster()) {
return true;
}
var db = new PouchDB(dbs.name);
var lastSeq;
return db.bulkDocs({
docs: [
{
_id: 'fubar',
_rev: '2-a2',
_revisions: { start: 2, ids: [ 'a2', 'a1' ] }
}, {
_id: 'fubar',
_rev: '1-a1',
_revisions: { start: 1, ids: [ 'a1' ] }
}
],
new_edits: false
}).then(function () {
return db.changes();
}).then(function (changes) {
lastSeq = changes.last_seq;
changes.results[0].changes[0].rev.should.equal('2-a2');
changes.results[0].seq.should.equal(lastSeq);
return db.info();
}).then(function (info) {
info.update_seq.should.equal(lastSeq);
});
});
// Each revision includes a list of previous revisions. The
// revision with the longest revision history list becomes the
// winning revision. If they are the same, the _rev values are
// compared in ASCII sort order, and the highest wins. So, in our
// example, 2-de0ea16f8621cbac506d23a0fbbde08a beats
// 2-7c971bb974251ae8541b8fe045964219.
it('Conflict resolution 1', function () {
var docs = [
{
_id: 'fubar',
_rev: '1-a',
_revisions: {
start: 1,
ids: [ 'a' ]
}
}, {
_id: 'fubar',
_rev: '1-b',
_revisions: {
start: 1,
ids: [ 'b' ]
}
}, {
_id: 'fubar',
_rev: '1-1',
_revisions: {
start: 1,
ids: [ '1' ]
}
}
];
var db = new PouchDB(dbs.name);
return db.bulkDocs({ docs: docs, new_edits: false }).then(function () {
return db.get('fubar');
}).then(function (doc) {
doc._rev.should.equal('1-b', 'Correct revision wins');
return db.bulkDocs({
new_edits: false,
docs: [{
_id: 'fubar',
_rev: '2-2',
_revisions: {
start: 2,
ids: [ '2', '1' ]
}
}]
});
}).then(function () {
return db.get('fubar');
}).then(function (doc) {
doc._rev.should.equal('2-2', 'Correct revision wins');
});
});
it('Conflict resolution 2', function () {
var docs = [
{
_id: 'fubar',
_rev: '2-a',
_revisions: {
start: 2,
ids: [ 'a' ]
}
}, {
_id: 'fubar',
_rev: '1-b',
_revisions: {
start: 1,
ids: [ 'b' ]
}
}
];
var db = new PouchDB(dbs.name);
return db.bulkDocs({ docs: docs, new_edits: false }).then(function () {
return db.get('fubar');
}).then(function (doc) {
doc._rev.should.equal('2-a', 'Correct revision wins');
return db.info();
}).then(function (info) {
info.doc_count.should.equal(1, 'Correct number of docs');
});
});
it('Conflict resolution 3', function () {
var docs = [
{
_id: 'fubar',
_rev: '10-a',
_revisions: {
start: 10,
ids: [ 'a' ]
}
}, {
_id: 'fubar',
_rev: '2-b',
_revisions: {
start: 2,
ids: [ 'b' ]
}
}
];
var db = new PouchDB(dbs.name);
return db.bulkDocs({ docs: docs, new_edits: false }).then(function () {
return db.get('fubar');
}).then(function (doc) {
doc._rev.should.equal('10-a', 'Correct revision wins');
return db.info();
}).then(function (info) {
info.doc_count.should.equal(1, 'Correct number of docs');
});
});
it('Conflict resolution 4-a', function () {
var docs = [
{
_id: 'fubar',
_rev: '1-a1',
_revisions: { start: 1, ids: [ 'a1' ] }
}, {
_id: 'fubar',
_rev: '2-a2',
_revisions: { start: 2, ids: [ 'a2', 'a1' ] }
}, {
_id: 'fubar',
_deleted: true,
_rev: '3-a3',
_revisions: { start: 3, ids: [ 'a3', 'a2', 'a1' ] }
}, {
_id: 'fubar',
_rev: '1-b1',
_revisions: { start: 1, ids: [ 'b1' ] }
}
];
var db = new PouchDB(dbs.name);
return db.bulkDocs({ docs: docs, new_edits: false }).then(function () {
return db.get('fubar');
}).then(function (doc) {
doc._rev.should.equal('1-b1', 'Correct revision wins');
return db.info();
}).then(function (info) {
info.doc_count.should.equal(1, 'Correct number of docs');
});
});
it('Conflict resolution 4-b', function () {
var docs = [
{
_id: 'fubar',
_deleted: true,
_rev: '3-a3',
_revisions: { start: 3, ids: [ 'a3', 'a2', 'a1' ] }
}, {
_id: 'fubar',
_rev: '2-a2',
_revisions: { start: 2, ids: [ 'a2', 'a1' ] }
}, {
_id: 'fubar',
_rev: '1-a1',
_revisions: { start: 1, ids: [ 'a1' ] }
}, {
_id: 'fubar',
_rev: '1-b1',
_revisions: { start: 1, ids: [ 'b1' ] }
}
];
var db = new PouchDB(dbs.name);
return db.bulkDocs({ docs: docs, new_edits: false }).then(function () {
return db.get('fubar');
}).then(function (doc) {
doc._rev.should.equal('1-b1', 'Correct revision wins');
return db.info();
}).then(function (info) {
info.doc_count.should.equal(1, 'Correct number of docs');
});
});
it('Conflict resolution 4-c', function () {
var docs = [
{
_id: 'fubar',
_rev: '1-a1',
_revisions: { start: 1, ids: [ 'a1' ] }
}, {
_id: 'fubar',
_rev: '1-b1',
_revisions: { start: 1, ids: [ 'b1' ] }
}, {
_id: 'fubar',
_rev: '2-a2',
_revisions: { start: 2, ids: [ 'a2', 'a1' ] }
}, {
_id: 'fubar',
_deleted: true,
_rev: '3-a3',
_revisions: { start: 3, ids: [ 'a3', 'a2', 'a1' ] }
}
];
var db = new PouchDB(dbs.name);
return db.bulkDocs({ docs: docs, new_edits: false }).then(function () {
return db.get('fubar');
}).then(function (doc) {
doc._rev.should.equal('1-b1', 'Correct revision wins');
return db.info();
}).then(function (info) {
info.doc_count.should.equal(1, 'Correct number of docs');
});
});
it('Conflict resolution 4-d', function () {
var docs = [
{
_id: 'fubar',
_rev: '1-a1',
_revisions: { start: 1, ids: [ 'a1' ] }
}, {
_id: 'fubar',
_rev: '1-b1',
_revisions: { start: 1, ids: [ 'b1' ] }
}, {
_id: 'fubar',
_rev: '2-a2',
_revisions: { start: 2, ids: [ 'a2', 'a1' ] }
}, {
_id: 'fubar',
_deleted: true,
_rev: '3-a3',
_revisions: { start: 3, ids: [ 'a3', 'a2', 'a1' ] }
}
];
var db = new PouchDB(dbs.name);
return db.bulkDocs({ docs: docs, new_edits: false }).then(function () {
return db.get('fubar');
}).then(function (doc) {
doc._rev.should.equal('1-b1', 'Correct revision wins');
return db.info();
}).then(function (info) {
info.doc_count.should.equal(1, 'Correct number of docs');
});
});
it('Conflict resolution 4-e', function () {
var docs = [
{
_id: 'fubar',
_deleted: true,
_rev: '3-a3',
_revisions: { start: 3, ids: [ 'a3', 'a2', 'a1' ] }
}, {
_id: 'fubar',
_rev: '2-a2',
_revisions: { start: 2, ids: [ 'a2', 'a1' ] }
}, {
_id: 'fubar',
_rev: '1-b1',
_revisions: { start: 1, ids: [ 'b1' ] }
}, {
_id: 'fubar',
_rev: '1-a1',
_revisions: { start: 1, ids: [ 'a1' ] }
}
];
var db = new PouchDB(dbs.name);
return db.bulkDocs({ docs: docs, new_edits: false }).then(function () {
return db.get('fubar');
}).then(function (doc) {
doc._rev.should.equal('1-b1', 'Correct revision wins');
return db.info();
}).then(function (info) {
info.doc_count.should.equal(1, 'Correct number of docs');
});
});
it('Conflict resolution 5-a', function () {
var docs = [
{
_id: 'fubar',
_rev: '2-a2',
_revisions: { start: 2, ids: [ 'a2', 'a1' ] }
}, {
_id: 'fubar',
_deleted: true,
_rev: '1-b1',
_revisions: { start: 1, ids: [ 'b1' ] }
}, {
_id: 'fubar',
_deleted: true,
_rev: '1-c1',
_revisions: { start: 1, ids: [ 'c1' ] }
}
];
var db = new PouchDB(dbs.name);
return db.bulkDocs({ docs: docs, new_edits: false }).then(function () {
return db.get('fubar');
}).then(function (doc) {
doc._rev.should.equal('2-a2', 'Correct revision wins');
return db.info();
}).then(function (info) {
info.doc_count.should.equal(1, 'Correct number of docs');
});
});
it('Conflict resolution 5-b', function () {
var docs = [
{
_id: 'fubar',
_deleted: true,
_rev: '1-b1',
_revisions: { start: 1, ids: [ 'b1' ] }
}, {
_id: 'fubar',
_rev: '2-a2',
_revisions: { start: 2, ids: [ 'a2', 'a1' ] }
}, {
_id: 'fubar',
_deleted: true,
_rev: '1-c1',
_revisions: { start: 1, ids: [ 'c1' ] }
}
];
var db = new PouchDB(dbs.name);
return db.bulkDocs({ docs: docs, new_edits: false }).then(function () {
return db.get('fubar');
}).then(function (doc) {
doc._rev.should.equal('2-a2', 'Correct revision wins');
return db.info();
}).then(function (info) {
info.doc_count.should.equal(1, 'Correct number of docs');
});
});
it('Conflict resolution 5-c', function () {
var docs = [
{
_id: 'fubar',
_deleted: true,
_rev: '1-b1',
_revisions: { start: 1, ids: [ 'b1' ] }
}, {
_id: 'fubar',
_deleted: true,
_rev: '1-c1',
_revisions: { start: 1, ids: [ 'c1' ] }
}, {
_id: 'fubar',
_rev: '2-a2',
_revisions: { start: 2, ids: [ 'a2', 'a1' ] }
}
];
var db = new PouchDB(dbs.name);
return db.bulkDocs({ docs: docs, new_edits: false }).then(function () {
return db.get('fubar');
}).then(function (doc) {
doc._rev.should.equal('2-a2', 'Correct revision wins');
return db.info();
}).then(function (info) {
info.doc_count.should.equal(1, 'Correct number of docs');
});
});
it('#2543 excessive recursion with merging', function () {
var chain = testUtils.Promise.resolve();
var db = new PouchDB(dbs.name);
function addTask(batch) {
return function () {
var docs = [];
for (var i = 0; i < 50; i++) {
var hash = batch + 'a' + i;
docs.push({
_id: 'foo',
_rev: '2-' + hash,
_revisions: {
start: 2,
ids: [hash, 'a']
}
});
}
return db.bulkDocs(docs, {new_edits: false});
};
}
chain = chain.then(function () {
return db.bulkDocs([{
_id: 'foo',
_rev: '1-a'
}], {new_edits: false});
});
for (var i = 0; i < 10; i++) {
chain = chain.then(addTask(i));
}
return chain;
});
it('local conflicts', function () {
if (testUtils.isCouchMaster()) {
return true;
}
var db = new PouchDB(dbs.name);
return db.put({foo: 'bar'}, '_local/baz').then(function (result) {
return db.put({foo: 'bar'}, '_local/baz', result.res);
}).then(function () {
return db.put({foo: 'bar'}, '_local/baz');
}, function (e) {
should.not.exist(e, 'shouldn\'t error yet');
throw e;
}).then(undefined, function (e) {
should.exist(e, 'error when you have a conflict');
});
});
it('5832 - update losing leaf returns correct rev', function () {
// given
var docs = [
{
_id: 'fubar',
_rev: '1-a1',
_revisions: { start: 1, ids: [ 'a1' ] }
}, {
_id: 'fubar',
_rev: '2-a2',
_revisions: { start: 2, ids: [ 'a2', 'a1' ] }
}, {
_id: 'fubar',
_rev: '2-b2',
_revisions: { start: 2, ids: [ 'b2', 'a1' ] }
}
];
var db = new PouchDB(dbs.name);
return db.bulkDocs({
docs: docs, new_edits: false
}).then(function () {
return db.get('fubar', { conflicts: true });
})
.then(function (doc) {
return db.remove(doc);
})
.then(function (result) {
result.rev[0].should.equal('3');
});
});
});
});