| 'use strict'; |
| |
| var adapters = [ |
| ['local', 'http'], |
| ['http', 'http'], |
| ['http', 'local'], |
| ['local', 'local'] |
| ]; |
| |
| if ('saucelabs' in testUtils.params()) { |
| adapters = [['local', 'http'], ['http', 'local']]; |
| } |
| |
| var downAdapters = ['local']; |
| |
| adapters.forEach(function (adapters) { |
| describe('test.replication.js-' + adapters[0] + '-' + adapters[1], |
| function () { |
| |
| var dbs = {}; |
| |
| beforeEach(function (done) { |
| dbs.name = testUtils.adapterUrl(adapters[0], 'testdb'); |
| dbs.remote = testUtils.adapterUrl(adapters[1], 'test_repl_remote'); |
| testUtils.cleanup([dbs.name, dbs.remote], done); |
| }); |
| |
| after(function (done) { |
| testUtils.cleanup([dbs.name, dbs.remote], done); |
| }); |
| |
| |
| var docs = [ |
| {_id: '0', integer: 0, string: '0'}, |
| {_id: '1', integer: 1, string: '1'}, |
| {_id: '2', integer: 2, string: '2'} |
| ]; |
| |
| it('Test basic pull replication', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| remote.bulkDocs({ docs: docs }, {}, function (err, results) { |
| db.replicate.from(dbs.remote, function (err, result) { |
| result.ok.should.equal(true); |
| result.docs_written.should.equal(docs.length); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(3, 'update_seq'); |
| info.doc_count.should.equal(3, 'doc_count'); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Test basic pull replication plain api', function (done) { |
| var remote = new PouchDB(dbs.remote); |
| remote.bulkDocs({ docs: docs }, {}, function (err, results) { |
| PouchDB.replicate(dbs.remote, dbs.name, {}, function (err, result) { |
| result.ok.should.equal(true); |
| result.docs_written.should.equal(docs.length); |
| new PouchDB(dbs.name).info(function (err, info) { |
| info.update_seq.should.equal(3, 'update_seq'); |
| info.doc_count.should.equal(3, 'doc_count'); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Test basic pull replication plain api 2', function (done) { |
| var remote = new PouchDB(dbs.remote); |
| remote.bulkDocs({ docs: docs }, {}, function (err, results) { |
| PouchDB.replicate(dbs.remote, dbs.name, { |
| complete: function (err, result) { |
| result.ok.should.equal(true); |
| result.docs_written.should.equal(docs.length); |
| new PouchDB(dbs.name).info(function (err, info) { |
| info.update_seq.should.equal(3, 'update_seq'); |
| info.doc_count.should.equal(3, 'doc_count'); |
| done(); |
| }); |
| } |
| }); |
| }); |
| }); |
| |
| it('Test pull replication with many changes', function (done) { |
| this.timeout(20000); |
| var remote = new PouchDB(dbs.remote); |
| |
| var numDocs = 201; |
| var docs = []; |
| for (var i = 0; i < numDocs; i++) { |
| docs.push({_id: i.toString()}); |
| } |
| |
| remote.bulkDocs({ docs: docs }, {}, function (err) { |
| should.not.exist(err); |
| PouchDB.replicate(dbs.remote, dbs.name, { |
| complete: function (err, result) { |
| result.ok.should.equal(true); |
| result.docs_written.should.equal(docs.length); |
| new PouchDB(dbs.name).info(function (err, info) { |
| info.update_seq.should.equal(numDocs, 'update_seq'); |
| info.doc_count.should.equal(numDocs, 'doc_count'); |
| done(); |
| }); |
| } |
| }); |
| }); |
| }); |
| |
| it('Test pull replication with many conflicts', function (done) { |
| this.timeout(20000); |
| var remote = new PouchDB(dbs.remote); |
| |
| var numRevs = 200; // repro "url too long" error with open_revs |
| var docs = []; |
| for (var i = 0; i < numRevs; i++) { |
| var rev = '1-' + PouchDB.utils.uuid(32, 16).toLowerCase(); |
| docs.push({_id: 'doc', _rev: rev}); |
| } |
| |
| remote.bulkDocs({ docs: docs }, {new_edits: false}, function (err) { |
| should.not.exist(err); |
| PouchDB.replicate(dbs.remote, dbs.name, { |
| complete: function (err, result) { |
| result.ok.should.equal(true); |
| result.docs_written.should.equal(docs.length); |
| var db = new PouchDB(dbs.name); |
| db.info(function (err, info) { |
| should.not.exist(err); |
| info.doc_count.should.equal(1, 'doc_count'); |
| db.get('doc', {open_revs: "all"}, function (err, docs) { |
| should.not.exist(err); |
| var okDocs = docs.filter(function (doc) { return doc.ok; }); |
| okDocs.should.have.length(numRevs); |
| done(); |
| }); |
| }); |
| } |
| }); |
| }); |
| }); |
| |
| it('Test correct # docs replicated with staggered revs', function (done) { |
| // ensure we don't just process all the open_revs with |
| // every replication; we should only process the current subset |
| var remote = new PouchDB(dbs.remote); |
| |
| var docs = [{_id: 'doc', _rev: '1-a'}, {_id: 'doc', _rev: '1-b'}]; |
| remote.bulkDocs({ docs: docs }, {new_edits: false}, function (err) { |
| should.not.exist(err); |
| PouchDB.replicate(dbs.remote, dbs.name, { |
| complete: function (err, result) { |
| result.ok.should.equal(true); |
| result.docs_written.should.equal(2); |
| result.docs_read.should.equal(2); |
| var docs = [{_id: 'doc', _rev: '1-c'}, {_id: 'doc', _rev: '1-d'}]; |
| remote.bulkDocs({ docs: docs }, {new_edits: false}, function (err) { |
| should.not.exist(err); |
| PouchDB.replicate(dbs.remote, dbs.name, { |
| complete: function (err, result) { |
| result.docs_written.should.equal(2); |
| result.docs_read.should.equal(2); |
| var db = new PouchDB(dbs.name); |
| db.info(function (err, info) { |
| should.not.exist(err); |
| info.doc_count.should.equal(1, 'doc_count'); |
| db.get('doc', {open_revs: "all"}, function (err, docs) { |
| should.not.exist(err); |
| var okDocs = docs.filter(function (doc) { |
| return doc.ok; |
| }); |
| okDocs.should.have.length(4); |
| done(); |
| }); |
| }); |
| } |
| }); |
| }); |
| } |
| }); |
| }); |
| }); |
| |
| it('Local DB contains documents', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| remote.bulkDocs({ docs: docs }, {}, function (err, _) { |
| db.bulkDocs({ docs: docs }, {}, function (err, _) { |
| db.replicate.from(dbs.remote, function (err, _) { |
| db.allDocs(function (err, result) { |
| result.rows.length.should.equal(docs.length); |
| db.info(function (err, info) { |
| info.update_seq.should.be.above(2, 'update_seq local'); |
| info.doc_count.should.equal(3, 'doc_count local'); |
| remote.info(function (err, info) { |
| info.update_seq.should.be.above(2, 'update_seq remote'); |
| info.doc_count.should.equal(3, 'doc_count remote'); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Test basic push replication', function (done) { |
| var db = new PouchDB(dbs.name); |
| db.bulkDocs({ docs: docs }, {}, function (err, results) { |
| db.replicate.to(dbs.remote, function (err, result) { |
| result.ok.should.equal(true); |
| result.docs_written.should.equal(docs.length); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(3); |
| info.doc_count.should.equal(3); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Test basic push replication take 2', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| db.bulkDocs({ docs: docs }, {}, function (err, _) { |
| db.replicate.to(dbs.remote, function (err, _) { |
| remote.allDocs(function (err, result) { |
| result.rows.length.should.equal(docs.length); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(3); |
| info.doc_count.should.equal(3); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Test basic push replication sequence tracking', function (done) { |
| var db = new PouchDB(dbs.name); |
| var doc1 = {_id: 'adoc', foo: 'bar'}; |
| db.put(doc1, function (err, result) { |
| db.replicate.to(dbs.remote, function (err, result) { |
| result.docs_read.should.equal(1); |
| db.replicate.to(dbs.remote, function (err, result) { |
| result.docs_read.should.equal(0); |
| db.replicate.to(dbs.remote, function (err, result) { |
| result.docs_read.should.equal(0); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(1); |
| info.doc_count.should.equal(1); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Test checkpoint', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| remote.bulkDocs({ docs: docs }, {}, function (err, results) { |
| db.replicate.from(dbs.remote, function (err, result) { |
| result.ok.should.equal(true); |
| result.docs_written.should.equal(docs.length); |
| db.replicate.from(dbs.remote, function (err, result) { |
| result.ok.should.equal(true); |
| result.docs_written.should.equal(0); |
| result.docs_read.should.equal(0); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(3); |
| info.doc_count.should.equal(3); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Test live pull checkpoint', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| remote.bulkDocs({ docs: docs }, {}, function (err, results) { |
| var changeCount = docs.length; |
| var changes = db.changes({ |
| live: true, |
| onChange: function (change) { |
| if (--changeCount) { |
| return; |
| } |
| replication.cancel(); |
| changes.cancel(); |
| }, |
| complete: function () { |
| db.replicate.from(dbs.remote, { |
| complete: function (err, details) { |
| details.docs_read.should.equal(0); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(3); |
| info.doc_count.should.equal(3); |
| done(); |
| }); |
| } |
| }); |
| } |
| }); |
| var replication = db.replicate.from(dbs.remote, { live: true }); |
| }); |
| }); |
| |
| it('Test live push checkpoint', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| db.bulkDocs({ docs: docs }, {}, function (err, results) { |
| var changeCount = docs.length; |
| var finished = 0; |
| var isFinished = function () { |
| if (++finished !== 2) { |
| return; |
| } |
| db.replicate.to(dbs.remote, { |
| complete: function (err, details) { |
| details.docs_read.should.equal(0); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(3); |
| info.doc_count.should.equal(3); |
| done(); |
| }); |
| } |
| }); |
| }; |
| var changes = remote.changes({ |
| live: true, |
| onChange: function (change) { |
| if (--changeCount) { |
| return; |
| } |
| replication.cancel(); |
| changes.cancel(); |
| }, |
| complete: isFinished |
| }); |
| var replication = db.replicate.to(dbs.remote, { |
| live: true, |
| complete: isFinished |
| }); |
| }); |
| }); |
| |
| it('Test checkpoint 2', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var doc = {_id: '3', count: 0}; |
| remote.put(doc, {}, function (err, results) { |
| db.replicate.from(dbs.remote, function (err, result) { |
| result.ok.should.equal(true); |
| doc._rev = results.rev; |
| doc.count++; |
| remote.put(doc, {}, function (err, results) { |
| doc._rev = results.rev; |
| doc.count++; |
| remote.put(doc, {}, function (err, results) { |
| db.replicate.from(dbs.remote, function (err, result) { |
| result.ok.should.equal(true); |
| result.docs_written.should.equal(1); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(2); |
| info.doc_count.should.equal(1); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Test checkpoint 3 :)', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var doc = {_id: '3', count: 0}; |
| db.put(doc, {}, function (err, results) { |
| PouchDB.replicate(db, remote, {}, function (err, result) { |
| result.ok.should.equal(true); |
| doc._rev = results.rev; |
| doc.count++; |
| db.put(doc, {}, function (err, results) { |
| doc._rev = results.rev; |
| doc.count++; |
| db.put(doc, {}, function (err, results) { |
| PouchDB.replicate(db, remote, {}, function (err, result) { |
| result.ok.should.equal(true); |
| result.docs_written.should.equal(1); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(3); |
| info.doc_count.should.equal(1); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Test checkpoint read only 3 :)', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var put = function (doc) { |
| return db.bulkDocs({docs: [doc]}).then(function (resp) { |
| return resp[0]; |
| }); |
| }; |
| var err = { |
| "message": "_writer access is required for this request", |
| "name": "unauthorized", |
| "status": 401 |
| }; |
| db.put = function () { |
| if (typeof arguments[arguments.length - 1] === 'function') { |
| arguments[arguments.length - 1](err); |
| } else { |
| return PouchDB.utils.Promise.reject(err); |
| } |
| }; |
| var doc = {_id: '3', count: 0}; |
| put(doc).then(function (results) { |
| return PouchDB.replicate(db, remote).then(function (result) { |
| result.ok.should.equal(true); |
| doc._rev = results.rev; |
| doc.count++; |
| return put(doc); |
| }); |
| }).then(function (results) { |
| doc._rev = results.rev; |
| doc.count++; |
| return put(doc); |
| }).then(function () { |
| return PouchDB.replicate(db, remote); |
| }).then(function (result) { |
| result.ok.should.equal(true); |
| result.docs_written.should.equal(1); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(3); |
| info.doc_count.should.equal(1); |
| done(); |
| }); |
| }, function (a) { |
| done(JSON.stringify(a, false, 4)); |
| }); |
| }); |
| |
| it('Testing allDocs with some conflicts (issue #468)', function (done) { |
| var db1 = new PouchDB(dbs.name); |
| var db2 = new PouchDB(dbs.remote); |
| // we indeed needed replication to create failing test here! |
| var doc = {_id: 'foo', _rev: '1-a', value: 'generic'}; |
| db1.put(doc, { new_edits: false }, function (err, res) { |
| db2.put(doc, { new_edits: false }, function (err, res) { |
| testUtils.putAfter(db2, { |
| _id: 'foo', |
| _rev: '2-b', |
| value: 'db2' |
| }, '1-a', function (err, res) { |
| testUtils.putAfter(db1, { |
| _id: 'foo', |
| _rev: '2-c', |
| value: 'whatever' |
| }, '1-a', function (err, res) { |
| testUtils.putAfter(db1, { |
| _id: 'foo', |
| _rev: '3-c', |
| value: 'db1' |
| }, '2-c', function (err, res) { |
| db1.get('foo', function (err, doc) { |
| doc.value.should.equal('db1'); |
| db2.get('foo', function (err, doc) { |
| doc.value.should.equal('db2'); |
| PouchDB.replicate(db1, db2, function () { |
| PouchDB.replicate(db2, db1, function () { |
| db1.get('foo', function (err, doc) { |
| doc.value.should.equal('db1'); |
| db2.get('foo', function (err, doc) { |
| doc.value.should.equal('db1'); |
| db1.allDocs({ include_docs: true }, |
| function (err, res) { |
| res.rows.should.have.length.above(0, 'first'); |
| // redundant but we want to test it |
| res.rows[0].doc.value.should.equal('db1'); |
| db2.allDocs({ include_docs: true }, |
| function (err, res) { |
| res.rows.should.have.length.above(0, 'second'); |
| res.rows[0].doc.value.should.equal('db1'); |
| db1.info(function (err, info) { |
| info.update_seq.should.equal(4); |
| info.doc_count.should.equal(1); |
| db2.info(function (err, info2) { |
| info2.update_seq.should.equal(3); |
| info2.doc_count.should.equal(1); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| // CouchDB will not generate a conflict here, it uses a deteministic |
| // method to generate the revision number, however we cannot copy its |
| // method as it depends on erlangs internal data representation |
| it('Test basic conflict', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var doc1 = {_id: 'adoc', foo: 'bar'}; |
| var doc2 = {_id: 'adoc', bar: 'baz'}; |
| db.put(doc1, function (err, localres) { |
| remote.put(doc2, function (err, remoteres) { |
| db.replicate.to(dbs.remote, function (err, _) { |
| remote.get('adoc', { conflicts: true }, function (err, result) { |
| result.should.have.property('_conflicts'); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(1); |
| info.doc_count.should.equal(1); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Test _conflicts key', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var doc1 = {_id: 'adoc', foo: 'bar'}; |
| var doc2 = {_id: 'adoc', bar: 'baz'}; |
| db.put(doc1, function (err, localres) { |
| remote.put(doc2, function (err, remoteres) { |
| db.replicate.to(dbs.remote, function (err, _) { |
| var queryFun = { |
| map: function (doc) { |
| if (doc._conflicts) { |
| emit(doc._id, [doc._rev].concat(doc._conflicts)); |
| } |
| } |
| }; |
| remote.query(queryFun, { |
| reduce: false, |
| conflicts: true |
| }, function (_, res) { |
| res.rows.length.should.equal(1); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(1); |
| info.doc_count.should.equal(1); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Test basic live pull replication', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var doc1 = {_id: 'adoc', foo: 'bar'}; |
| remote.bulkDocs({ docs: docs }, {}, function (err, results) { |
| var count = 0; |
| var finished = 0; |
| var isFinished = function () { |
| if (++finished !== 2) { |
| return; |
| } |
| db.info(function (err, info) { |
| info.update_seq.should.equal(4); |
| info.doc_count.should.equal(4); |
| done(); |
| }); |
| }; |
| var rep = db.replicate.from(dbs.remote, { |
| live: true, |
| complete: isFinished |
| }); |
| var changes = db.changes({ |
| onChange: function (change) { |
| ++count; |
| if (count === 3) { |
| return remote.put(doc1); |
| } |
| if (count === 4) { |
| rep.cancel(); |
| changes.cancel(); |
| } |
| }, |
| live: true, |
| complete: isFinished |
| }); |
| }); |
| }); |
| |
| it('Test basic live push replication', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var doc1 = {_id: 'adoc', foo: 'bar'}; |
| db.bulkDocs({ docs: docs }, {}, function (err, results) { |
| var count = 0; |
| var finished = 0; |
| var isFinished = function () { |
| if (++finished !== 2) { |
| return; |
| } |
| db.info(function (err, info) { |
| info.update_seq.should.equal(4); |
| info.doc_count.should.equal(4); |
| done(); |
| }); |
| }; |
| var rep = remote.replicate.from(db, { |
| live: true, |
| complete: isFinished |
| }); |
| var changes = remote.changes({ |
| onChange: function (change) { |
| ++count; |
| if (count === 3) { |
| return db.put(doc1); |
| } |
| if (count === 4) { |
| rep.cancel(); |
| changes.cancel(); |
| } |
| }, |
| live: true, |
| complete: isFinished |
| }); |
| }); |
| }); |
| |
| it('test-cancel-pull-replication', function (done) { |
| new PouchDB(dbs.remote, function (err, remote) { |
| var db = new PouchDB(dbs.name); |
| var docs = [ |
| {_id: '0', integer: 0, string: '0'}, |
| {_id: '1', integer: 1, string: '1'}, |
| {_id: '2', integer: 2, string: '2'} |
| ]; |
| var doc1 = {_id: 'adoc', foo: 'bar' }; |
| var doc2 = {_id: 'anotherdoc', foo: 'baz'}; |
| remote.bulkDocs({ docs: docs }, {}, function (err, results) { |
| var count = 0; |
| var replicate = db.replicate.from(remote, { |
| live: true, |
| complete: function () { |
| remote.put(doc2); |
| setTimeout(function () { |
| changes.cancel(); |
| }, 100); |
| } |
| }); |
| var changes = db.changes({ |
| live: true, |
| complete: function (err, reason) { |
| count.should.equal(4); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(4); |
| info.doc_count.should.equal(4); |
| done(); |
| }); |
| }, |
| onChange: function (change) { |
| ++count; |
| if (count === 3) { |
| remote.put(doc1); |
| } |
| if (count === 4) { |
| replicate.cancel(); |
| } |
| } |
| }); |
| }); |
| }); |
| }); |
| |
| it('Test basic events', function (done) { |
| var db = new PouchDB(dbs.name); |
| db.bulkDocs({ docs: docs }).then(function () { |
| db.replicate.to(dbs.remote) |
| .on('complete', function (res) { |
| should.exist(res); |
| db.replicate.to('http://0.0.0.0:0') |
| .on('error', function (res) { |
| should.exist(res); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Replication filter', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var docs1 = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2}, |
| {_id: '3', integer: 3} |
| ]; |
| remote.bulkDocs({ docs: docs1 }, function (err, info) { |
| db.replicate.from(remote, { |
| complete: function (err, res) { |
| if (err) { |
| done(err); |
| } |
| db.allDocs(function (err, docs) { |
| if (err) { done(err); } |
| docs.rows.length.should.equal(2); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(2); |
| info.doc_count.should.equal(2); |
| done(); |
| }); |
| }); |
| }, |
| filter: function (doc) { |
| return doc.integer % 2 === 0; |
| } |
| }); |
| }); |
| }); |
| |
| it('Replication with different filters', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var more_docs = [ |
| {_id: '3', integer: 3, string: '3'}, |
| {_id: '4', integer: 4, string: '4'} |
| ]; |
| remote.bulkDocs({ docs: docs }, function (err, info) { |
| db.replicate.from(remote, { |
| filter: function (doc) { |
| return doc.integer % 2 === 0; |
| } |
| }, function (err, response) { |
| remote.bulkDocs({ docs: more_docs }, function (err, info) { |
| db.replicate.from(remote, {}, function (err, response) { |
| response.docs_written.should.equal(3); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(5); |
| info.doc_count.should.equal(5); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Replication doc ids', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var thedocs = [ |
| {_id: '3', integer: 3, string: '3'}, |
| {_id: '4', integer: 4, string: '4'}, |
| {_id: '5', integer: 5, string: '5'} |
| ]; |
| remote.bulkDocs({ docs: thedocs }, function (err, info) { |
| db.replicate.from(remote, { |
| doc_ids: ['3', '4'] |
| }, function (err, response) { |
| response.docs_written.should.equal(2); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(2); |
| info.doc_count.should.equal(2); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Replication since', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var thedocs = [ |
| {_id: '1', integer: 1, string: '1'}, |
| {_id: '2', integer: 2, string: '2'}, |
| {_id: '3', integer: 3, string: '3'}, |
| {_id: '4', integer: 4, string: '4'}, |
| {_id: '5', integer: 5, string: '5'} |
| ]; |
| remote.bulkDocs({ docs: thedocs }, function (err, info) { |
| db.replicate.from(remote, { |
| since: 3, |
| complete: function (err, result) { |
| should.not.exist(err); |
| result.docs_written.should.equal(2); |
| db.replicate.from(remote, { |
| since: 0, |
| complete: function (err, result) { |
| should.not.exist(err); |
| result.docs_written.should.equal(3); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(5); |
| info.doc_count.should.equal(5); |
| done(); |
| }); |
| } |
| }); |
| } |
| }); |
| }); |
| }); |
| |
| it('Replication with same filters', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var more_docs = [ |
| {_id: '3', integer: 3, string: '3'}, |
| {_id: '4', integer: 4, string: '4'} |
| ]; |
| remote.bulkDocs({ docs: docs }, function (err, info) { |
| db.replicate.from(remote, { |
| filter: function (doc) { |
| return doc.integer % 2 === 0; |
| } |
| }, function (err, response) { |
| remote.bulkDocs({ docs: more_docs }, function (err, info) { |
| db.replicate.from(remote, { |
| filter: function (doc) { |
| return doc.integer % 2 === 0; |
| } |
| }, function (err, response) { |
| response.docs_written.should.equal(1); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(3); |
| info.doc_count.should.equal(3); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Replication with deleted doc', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var docs1 = [ |
| {_id: '0', integer: 0}, |
| {_id: '1', integer: 1}, |
| {_id: '2', integer: 2}, |
| {_id: '3', integer: 3}, |
| {_id: '4', integer: 4, _deleted: true} |
| ]; |
| remote.bulkDocs({ docs: docs1 }, function (err, info) { |
| db.replicate.from(remote, function () { |
| db.allDocs(function (err, res) { |
| res.total_rows.should.equal(4); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(5); |
| info.doc_count.should.equal(4); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Replication with doc deleted twice', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| remote.bulkDocs({ docs: docs }).then(function (info) { |
| return remote.get('0'); |
| }).then(function (doc) { |
| return remote.remove(doc); |
| }).then(function () { |
| return db.replicate.from(remote); |
| }).then(function () { |
| return db.allDocs(); |
| }).then(function (res) { |
| res.total_rows.should.equal(2); |
| return remote.allDocs({ keys: [ '0' ] }); |
| }).then(function (res) { |
| var row = res.rows[0]; |
| should.not.exist(row.error); |
| // set rev to latest so we go at the end (otherwise new |
| // rev is 1 and the subsequent remove below won't win) |
| var doc = { |
| _id: '0', |
| integer: 10, |
| string: '10', |
| _rev: row.value.rev |
| }; |
| return remote.put(doc); |
| }).then(function () { |
| return remote.get('0'); |
| }).then(function (doc) { |
| return remote.remove(doc); |
| }).then(function () { |
| return db.replicate.from(remote); |
| }).then(function () { |
| return db.allDocs(); |
| }).then(function (res) { |
| res.total_rows.should.equal(2); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(4); |
| info.doc_count.should.equal(2); |
| done(); |
| }); |
| }).catch(function (err) { |
| done(JSON.stringify(err, false, 4)); |
| }); |
| }); |
| |
| it('Replication notifications', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var changes = 0; |
| var onChange = function (c) { |
| changes++; |
| if (changes === 3) { |
| db.info(function (err, info) { |
| info.update_seq.should.equal(3); |
| info.doc_count.should.equal(3); |
| done(); |
| }); |
| } |
| }; |
| remote.bulkDocs({ docs: docs }, {}, function (err, results) { |
| db.replicate.from(dbs.remote, { onChange: onChange }); |
| }); |
| }); |
| |
| it('Replication with remote conflict', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var doc = {_id: 'test', test: 'Remote 1'}, winningRev; |
| remote.post(doc, function (err, resp) { |
| doc._rev = resp.rev; |
| PouchDB.replicate(remote, db, function (err, resp) { |
| doc.test = 'Local 1'; |
| db.put(doc, function (err, resp) { |
| doc.test = 'Remote 2'; |
| remote.put(doc, function (err, resp) { |
| doc._rev = resp.rev; |
| doc.test = 'Remote 3'; |
| remote.put(doc, function (err, resp) { |
| winningRev = resp.rev; |
| PouchDB.replicate(db, remote, function (err, resp) { |
| PouchDB.replicate(remote, db, function (err, resp) { |
| remote.get('test', { revs_info: true }, |
| function (err, remotedoc) { |
| db.get('test', { revs_info: true }, |
| function (err, localdoc) { |
| localdoc._rev.should.equal(winningRev); |
| remotedoc._rev.should.equal(winningRev); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(3); |
| info.doc_count.should.equal(1); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Replication of multiple remote conflicts (#789)', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var doc = {_id: '789', _rev: '1-a', value: 'test'}; |
| function createConflicts(db, callback) { |
| db.put(doc, { new_edits: false }, function (err, res) { |
| testUtils.putAfter(db, { |
| _id: '789', |
| _rev: '2-a', |
| value: 'v1' |
| }, '1-a', function (err, res) { |
| testUtils.putAfter(db, { |
| _id: '789', |
| _rev: '2-b', |
| value: 'v2' |
| }, '1-a', function (err, res) { |
| testUtils.putAfter(db, { |
| _id: '789', |
| _rev: '2-c', |
| value: 'v3' |
| }, '1-a', function (err, res) { |
| callback(); |
| }); |
| }); |
| }); |
| }); |
| } |
| createConflicts(remote, function () { |
| db.replicate.from(remote, function (err, result) { |
| result.ok.should.equal(true); |
| // in this situation, all the conflicting revisions should be read and |
| // written to the target database (this is consistent with CouchDB) |
| result.docs_written.should.equal(3); |
| result.docs_read.should.equal(3); |
| db.info(function (err, info) { |
| info.update_seq.should.be.above(0); |
| info.doc_count.should.equal(1); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Replicate large number of docs', function (done) { |
| if ('saucelabs' in testUtils.params()) { |
| return done(); |
| } |
| this.timeout(15000); |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var docs = []; |
| var num = 30; |
| for (var i = 0; i < num; i++) { |
| docs.push({ |
| _id: 'doc_' + i, |
| foo: 'bar_' + i |
| }); |
| } |
| remote.bulkDocs({ docs: docs }, function (err, info) { |
| db.replicate.from(remote, {}, function () { |
| db.allDocs(function (err, res) { |
| res.total_rows.should.equal(num); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(30); |
| info.doc_count.should.equal(30); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it.skip('Changes error', function (done) { |
| if ('saucelabs' in testUtils.params()) { |
| return done(); |
| } |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var docs = []; |
| var num = 80; |
| for (var i = 0; i < num; i++) { |
| docs.push({ |
| _id: 'doc_' + i, |
| foo: 'bar_' + i |
| }); |
| } |
| remote.bulkDocs({docs: docs}, {}, function (err, results) { |
| var changes = remote.changes; |
| var doc_count = 0; |
| |
| // Mock remote.get to fail writing doc_3 |
| remote.changes = function (opts) { |
| var onChange = opts.onChange; |
| opts.onChange = function () { |
| doc_count++; |
| onChange.apply(this, arguments); |
| }; |
| var complete = opts.complete; |
| opts.complete = function () { |
| complete.apply(this, [{ |
| status: 500, |
| error: 'mock changes error', |
| reason: 'simulate and error from changes' |
| }]); |
| }; |
| changes.apply(this, arguments); |
| }; |
| |
| // Replicate and confirm failure |
| db.replicate.from(remote, function (err, result) { |
| should.exist(err); |
| doc_count.should.equal(result.docs_read); |
| remote.changes = changes; |
| db.info(function (err, info) { |
| info.update_seq.should.equal(3); |
| info.doc_count.should.equal(3); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Ensure checkpoint after deletion', function (done) { |
| var db1name = dbs.name; |
| var adoc = { '_id': 'adoc' }; |
| var newdoc = { '_id': 'newdoc' }; |
| var db1 = new PouchDB(dbs.name); |
| var db2 = new PouchDB(dbs.remote); |
| db1.post(adoc, function () { |
| PouchDB.replicate(db1, db2, { |
| complete: function () { |
| PouchDB.destroy(db1name, function () { |
| var fresh = new PouchDB(db1name); |
| fresh.post(newdoc, function () { |
| PouchDB.replicate(fresh, db2, { |
| complete: function () { |
| db2.allDocs(function (err, docs) { |
| docs.rows.length.should.equal(2); |
| done(); |
| }); |
| } |
| }); |
| }); |
| }); |
| } |
| }); |
| }); |
| }); |
| |
| it('issue #1001 cb as 3rd argument', function (done) { |
| PouchDB.replicate('http://example.com', dbs.name, function (err, result) { |
| should.exist(err); |
| done(); |
| }); |
| }); |
| |
| it('issue #1001 cb in options', function (done) { |
| PouchDB.replicate('http://example.com', dbs.name, { |
| complete: function (err, result) { |
| should.exist(err); |
| done(); |
| } |
| }); |
| }); |
| |
| it('issue #1001 cb as 4th argument', function (done) { |
| PouchDB.replicate( |
| 'http://example.com', |
| dbs.name, |
| {}, |
| function (err, result) { |
| should.exist(err); |
| done(); |
| } |
| ); |
| }); |
| |
| it('issue #909 Filtered replication bails at paging limit', |
| function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var docs = []; |
| var num = 100; |
| for (var i = 0; i < num; i++) { |
| docs.push({ |
| _id: 'doc_' + i, |
| foo: 'bar_' + i |
| }); |
| } |
| num = 100; |
| var docList = []; |
| for (i = 0; i < num; i += 5) { |
| docList.push('doc_' + i); |
| } |
| // uncomment this line to test only docs higher than paging limit |
| docList = [ |
| 'doc_33', |
| 'doc_60', |
| 'doc_90' |
| ]; |
| remote.bulkDocs({ docs: docs }, {}, function (err, results) { |
| db.replicate.from(dbs.remote, { |
| live: false, |
| doc_ids: docList |
| }, function (err, result) { |
| result.docs_written.should.equal(docList.length); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(3); |
| info.doc_count.should.equal(3); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| |
| it.skip('(#1240) - get error', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| // 10 test documents |
| var num = 10; |
| var docs = []; |
| for (var i = 0; i < num; i++) { |
| docs.push({ |
| _id: 'doc_' + i, |
| foo: 'bar_' + i |
| }); |
| } |
| // Initialize remote with test documents |
| remote.bulkDocs({ docs: docs }, {}, function (err, results) { |
| var get = remote.get; |
| function first_replicate() { |
| // Mock remote.get to fail writing doc_3 (fourth doc) |
| remote.get = function () { |
| // Simulate failure to get the document with id 'doc_4' |
| // This should block the replication at seq 4 |
| if (arguments[0] === 'doc_4') { |
| arguments[2].apply(null, [{}]); |
| } else { |
| get.apply(this, arguments); |
| } |
| }; |
| // Replicate and confirm failure, docs_written and target docs |
| db.replicate.from(remote, function (err, result) { |
| should.exist(err); |
| should.exist(result); |
| result.docs_written.should.equal(4); |
| function check_docs(id, result) { |
| if (!id) { |
| second_replicate(); |
| return; |
| } |
| db.get(id, function (err, exists) { |
| if (exists) { |
| should.not.exist(err); |
| } else { |
| should.exist(err); |
| } |
| check_docs(docs.shift()); |
| }); |
| } |
| var docs = [ |
| [ |
| 'doc_0', |
| true |
| ], |
| [ |
| 'doc_1', |
| true |
| ], |
| [ |
| 'doc_2', |
| true |
| ], |
| [ |
| 'doc_3', |
| false |
| ], |
| [ |
| 'doc_4', |
| false |
| ], |
| [ |
| 'doc_5', |
| false |
| ], |
| [ |
| 'doc_6', |
| false |
| ], |
| [ |
| 'doc_7', |
| false |
| ], |
| [ |
| 'doc_8', |
| false |
| ], |
| [ |
| 'doc_9', |
| false |
| ] |
| ]; |
| check_docs(docs.shift()); |
| }); |
| } |
| function second_replicate() { |
| // Restore remote.get to original |
| remote.get = get; |
| // Replicate and confirm success, docs_written and target docs |
| db.replicate.from(remote, function (err, result) { |
| should.not.exist(err); |
| should.exist(result); |
| result.docs_written.should.equal(6); |
| function check_docs(id, exists) { |
| if (!id) { |
| db.info(function (err, info) { |
| info.update_seq.should.equal(6); |
| info.doc_count.should.equal(6); |
| done(); |
| }); |
| return; |
| } |
| db.get(id, function (err, result) { |
| if (exists) { |
| should.not.exist(err); |
| } else { |
| should.exist(err); |
| } |
| check_docs(docs.shift()); |
| }); |
| } |
| var docs = [ |
| [ |
| 'doc_0', |
| true |
| ], |
| [ |
| 'doc_1', |
| true |
| ], |
| [ |
| 'doc_2', |
| true |
| ], |
| [ |
| 'doc_3', |
| true |
| ], |
| [ |
| 'doc_4', |
| true |
| ], |
| [ |
| 'doc_5', |
| true |
| ], |
| [ |
| 'doc_6', |
| true |
| ], |
| [ |
| 'doc_7', |
| true |
| ], |
| [ |
| 'doc_8', |
| true |
| ], |
| [ |
| 'doc_9', |
| true |
| ] |
| ]; |
| check_docs(docs.shift()); |
| }); |
| } |
| // Done the test |
| first_replicate(); |
| }); |
| }); |
| |
| it.skip('Get error 2', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| // 10 test documents |
| var num = 10; |
| var docs = []; |
| for (var i = 0; i < num; i++) { |
| docs.push({ |
| _id: 'doc_' + i, |
| foo: 'bar_' + i |
| }); |
| } |
| // Initialize remote with test documents |
| remote.bulkDocs({ docs: docs }, {}, function (err, results) { |
| var get = remote.get; |
| function first_replicate() { |
| // Mock remote.get to fail writing doc_3 (fourth doc) |
| remote.get = function () { |
| // Simulate failure to get the document with id 'doc_4' |
| // This should block the replication at seq 4 |
| if (arguments[0] === 'doc_4') { |
| arguments[2].apply(null, [{ |
| status: 500, |
| error: 'mock error', |
| reason: 'mock get failure' |
| }]); |
| } else { |
| get.apply(this, arguments); |
| } |
| }; |
| // Replicate and confirm failure, docs_written and target docs |
| db.replicate.from(remote, function (err, result) { |
| err.status.should.equal(500); |
| err.error.should.equal('Replication aborted'); |
| err.reason.should.equal('src.get completed with error'); |
| err.details.status.should.equal(500); |
| err.details.error.should.equal('mock error'); |
| err.details.reason.should.equal('mock get failure'); |
| result.errors[0].status.should.equal(500); |
| result.errors[0].error.should.equal('mock error'); |
| result.errors[0].reason.should.equal('mock get failure'); |
| result.docs_written.should.equal(4); |
| function check_docs(id, result) { |
| if (!id) { |
| second_replicate(); |
| return; |
| } |
| db.get(id, function (err, exists) { |
| if (exists) { |
| should.not.exist(err); |
| } else { |
| should.exist(err); |
| } |
| check_docs(docs.shift()); |
| }); |
| } |
| var docs = [ |
| [ |
| 'doc_0', |
| true |
| ], |
| [ |
| 'doc_1', |
| true |
| ], |
| [ |
| 'doc_2', |
| true |
| ], |
| [ |
| 'doc_3', |
| false |
| ], |
| [ |
| 'doc_4', |
| false |
| ], |
| [ |
| 'doc_5', |
| false |
| ], |
| [ |
| 'doc_6', |
| false |
| ], |
| [ |
| 'doc_7', |
| false |
| ], |
| [ |
| 'doc_8', |
| false |
| ], |
| [ |
| 'doc_9', |
| false |
| ] |
| ]; |
| check_docs(docs.shift()); |
| }); |
| } |
| function second_replicate() { |
| // Restore remote.get to original |
| remote.get = get; |
| // Replicate and confirm success, docs_written and target docs |
| db.replicate.from(remote, function (err, result) { |
| should.not.exist(err); |
| should.exist(result); |
| result.docs_written.should.equal(6); |
| function check_docs(id, exists) { |
| if (!id) { |
| db.info(function (err, info) { |
| info.update_seq.should.equal(6); |
| info.doc_count.should.equal(6); |
| done(); |
| }); |
| return; |
| } |
| db.get(id, function (err, result) { |
| if (exists) { |
| should.not.exist(err); |
| } else { |
| should.exist(err); |
| } |
| check_docs(docs.shift()); |
| }); |
| } |
| var docs = [ |
| [ |
| 'doc_0', |
| true |
| ], |
| [ |
| 'doc_1', |
| true |
| ], |
| [ |
| 'doc_2', |
| true |
| ], |
| [ |
| 'doc_3', |
| true |
| ], |
| [ |
| 'doc_4', |
| true |
| ], |
| [ |
| 'doc_5', |
| true |
| ], |
| [ |
| 'doc_6', |
| true |
| ], |
| [ |
| 'doc_7', |
| true |
| ], |
| [ |
| 'doc_8', |
| true |
| ], |
| [ |
| 'doc_9', |
| true |
| ] |
| ]; |
| check_docs(docs.shift()); |
| }); |
| } |
| // Done the test |
| first_replicate(); |
| }); |
| }); |
| |
| it.skip("error updating checkpoint", function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| remote.bulkDocs({docs: docs}, {}, function (err, results) { |
| var get = remote.get; |
| var local_count = 0; |
| // Mock remote.get to fail writing doc_3 (fourth doc) |
| remote.get = function () { |
| // Simulate failure to get the checkpoint |
| if (arguments[0].slice(0, 6) === '_local') { |
| local_count++; |
| if (local_count === 2) { |
| arguments[1].apply(null, [{ |
| status: 500, |
| error: 'mock get error', |
| reason: 'simulate an error updating the checkpoint' |
| }]); |
| } else { |
| get.apply(this, arguments); |
| } |
| } else { |
| get.apply(this, arguments); |
| } |
| }; |
| |
| db.replicate.from(remote, { |
| complete: function (err, result) { |
| should.exist(err); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(2); |
| info.doc_count.should.equal(2); |
| done(); |
| }); |
| } |
| }); |
| }); |
| }); |
| |
| it('(#1307) - replicate empty database', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| db.replicate.from(remote, function (err, result) { |
| should.not.exist(err); |
| should.exist(result); |
| result.docs_written.should.equal(0); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(0); |
| info.doc_count.should.equal(0); |
| done(); |
| }); |
| }); |
| }); |
| |
| |
| // This fails as it somehow triggers an xhr abort in the http adapter in |
| // node which doesnt have xhr.... |
| it.skip('Syncing should stop if one replication fails (issue 838)', |
| function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var doc1 = {_id: 'adoc', foo: 'bar'}; |
| var doc2 = {_id: 'anotherdoc', foo: 'baz'}; |
| var finished = false; |
| var replications = db.replicate.sync(remote, { |
| live: true, |
| complete: function () { |
| if (finished) { |
| return; |
| } |
| finished = true; |
| remote.put(doc2, function (err) { |
| setTimeout(function () { |
| db.allDocs(function (err, res) { |
| res.total_rows.should.be.below(2); |
| done(); |
| }); |
| }, 100); |
| }); |
| } |
| }); |
| db.put(doc1, function (err) { |
| replications.pull.cancel(); |
| }); |
| }); |
| |
| it("Reporting write failures (#942)", function (done) { |
| var docs = [{_id: 'a', _rev: '1-a'}, {_id: 'b', _rev: '1-b'}]; |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| db.bulkDocs({docs: docs}, {new_edits: false}, function (err, _) { |
| var bulkDocs = remote.bulkDocs; |
| remote.bulkDocs = function (content, opts, callback) { |
| return new PouchDB.utils.Promise(function (fulfill, reject) { |
| if (typeof callback !== 'function') { |
| callback = function (err, resp) { |
| if (err) { |
| reject(err); |
| } else { |
| fulfill(resp); |
| } |
| }; |
| } |
| var ids = content.docs.map(function (doc) { return doc._id; }); |
| if (ids.indexOf('a') >= 0) { |
| callback(null, [{ok: true, id: 'a', rev: '1-a'}]); |
| } else if (ids.indexOf('b') >= 0) { |
| callback(null, [{ |
| id: 'b', |
| error: 'internal server error', |
| reason: 'test document write error' |
| }]); |
| } else { |
| bulkDocs.apply(remote, [content, opts, callback]); |
| } |
| }); |
| }; |
| |
| db.replicate.to(remote, { batch_size: 1 }, function (err, result) { |
| should.not.exist(result); |
| should.exist(err); |
| err.result.docs_read.should.equal(2, 'docs_read'); |
| err.result.docs_written.should.equal(1, 'docs_written'); |
| err.result.doc_write_failures.should.equal(1, 'doc_write_failures'); |
| remote.bulkDocs = bulkDocs; |
| db.replicate.to(remote, { batch_size: 1 }, function (err, result) { |
| // checkpoint should not be moved past first doc |
| // should continue from this point and retry second doc |
| result.docs_read.should.equal(1, 'second replication, docs_read'); |
| result.docs_written.should |
| .equal(1, 'second replication, docs_written'); |
| result.doc_write_failures.should |
| .equal(0, 'second replication, doc_write_failures'); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(2); |
| info.doc_count.should.equal(2); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it("Reporting write failures if whole saving fails (#942)", |
| function (done) { |
| var docs = [{_id: 'a', _rev: '1-a'}, {_id: 'b', _rev: '1-b'}]; |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| db.bulkDocs({docs: docs}, {new_edits: false}, function (err, _) { |
| var bulkDocs = remote.bulkDocs; |
| remote.bulkDocs = function (docs, opts, callback) { |
| if (typeof callback !== 'function') { |
| return PouchDB.utils.Promise.reject(new Error()); |
| } |
| callback(new Error()); |
| }; |
| |
| db.replicate.to(remote, { batch_size: 1 }, function (err, result) { |
| should.not.exist(result); |
| should.exist(err); |
| err.result.docs_read.should.equal(1, 'docs_read'); |
| err.result.docs_written.should.equal(0, 'docs_written'); |
| err.result.doc_write_failures.should.equal(1, 'doc_write_failures'); |
| err.result.last_seq.should.equal(0, 'last_seq'); |
| remote.bulkDocs = bulkDocs; |
| db.replicate.to(remote, { batch_size: 1 }, function (err, result) { |
| result.doc_write_failures.should |
| .equal(0, 'second replication, doc_write_failures'); |
| result.docs_written.should |
| .equal(2, 'second replication, docs_written'); |
| result.last_seq.should.equal(2, 'second replication, last_seq'); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Test consecutive replications with different query_params', |
| function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var myDocs = [ |
| {_id: '0', integer: 0, string: '0'}, |
| {_id: '1', integer: 1, string: '1'}, |
| {_id: '2', integer: 2, string: '2'}, |
| {_id: '3', integer: 3, string: '3'}, |
| {_id: '4', integer: 5, string: '5'} |
| ]; |
| remote.bulkDocs({ docs: myDocs }, {}, function (err, results) { |
| var filterFun = function (doc, req) { |
| if (req.query.even) { |
| return doc.integer % 2 === 0; |
| } else { |
| return true; |
| } |
| }; |
| db.replicate.from(dbs.remote, { |
| filter: filterFun, |
| query_params: { 'even': true } |
| }, function (err, result) { |
| result.docs_written.should.equal(2); |
| db.replicate.from(dbs.remote, { |
| filter: filterFun, |
| query_params: { 'even': false } |
| }, function (err, result) { |
| result.docs_written.should.equal(3); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| |
| it('Test consecutive replications with different query_params and promises', |
| function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var myDocs = [ |
| {_id: '0', integer: 0, string: '0'}, |
| {_id: '1', integer: 1, string: '1'}, |
| {_id: '2', integer: 2, string: '2'}, |
| {_id: '3', integer: 3, string: '3'}, |
| {_id: '4', integer: 5, string: '5'} |
| ]; |
| var filterFun; |
| remote.bulkDocs({ docs: myDocs }).then(function (results) { |
| filterFun = function (doc, req) { |
| if (req.query.even) { |
| return doc.integer % 2 === 0; |
| } else { |
| return true; |
| } |
| }; |
| return db.replicate.from(dbs.remote, { |
| filter: filterFun, |
| query_params: { 'even': true } |
| }); |
| }).then(function (result) { |
| result.docs_written.should.equal(2); |
| return db.replicate.from(dbs.remote, { |
| filter: filterFun, |
| query_params: { 'even': false } |
| }); |
| }).then(function (result) { |
| result.docs_written.should.equal(3); |
| done(); |
| }).catch(done); |
| }); |
| |
| it('Test consecutive replications with different doc_ids', function (done) { |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| var myDocs = [ |
| {_id: '0', integer: 0, string: '0'}, |
| {_id: '1', integer: 1, string: '1'}, |
| {_id: '2', integer: 2, string: '2'}, |
| {_id: '3', integer: 3, string: '3'}, |
| {_id: '4', integer: 5, string: '5'} |
| ]; |
| remote.bulkDocs({ docs: myDocs }, {}, function (err, results) { |
| db.replicate.from(dbs.remote, { |
| doc_ids: ['0', '4'] |
| }, function (err, result) { |
| result.docs_written.should.equal(2); |
| db.replicate.from(dbs.remote, { |
| doc_ids: ['1', '2', '3'] |
| }, function (err, result) { |
| result.docs_written.should.equal(3); |
| db.replicate.from(dbs.remote, { |
| doc_ids: ['5'] |
| }, function (err, result) { |
| result.docs_written.should.equal(0); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(5); |
| info.doc_count.should.equal(5); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('doc count after multiple replications', function (done) { |
| |
| var runs = 2; |
| // helper. remove each document in db and bulk load docs into same |
| function rebuildDocuments(db, docs, callback) { |
| db.allDocs({ include_docs: true }, function (err, response) { |
| var count = 0; |
| var limit = response.rows.length; |
| if (limit === 0) { |
| bulkLoad(db, docs, callback); |
| } |
| response.rows.forEach(function (doc) { |
| db.remove(doc, function (err, response) { |
| ++count; |
| if (count === limit) { |
| bulkLoad(db, docs, callback); |
| } |
| }); |
| }); |
| }); |
| } |
| |
| // helper. |
| function bulkLoad(db, docs, callback) { |
| db.bulkDocs({ docs: docs }, function (err, results) { |
| if (err) { |
| console.error('Unable to bulk load docs. Err: ' + |
| JSON.stringify(err)); |
| return; |
| } |
| callback(results); |
| }); |
| } |
| |
| // a basic map function to mimic our testing situation |
| var map = 'function(doc) {' + |
| 'if (doc.common === true) {' + |
| 'emit(doc._id, doc.rev);' + |
| '}' + |
| '}'; |
| |
| // The number of workflow cycles to perform. 2+ was always failing |
| // reason for this test. |
| var workflow = function (name, remote, x) { |
| // some documents. note that the variable Date component, |
| //thisVaries, makes a difference. |
| // when the document is otherwise static, couch gets the same hash |
| // when calculating revision. |
| // and the revisions get messed up in pouch |
| var docs = [ |
| { |
| _id: '0', |
| integer: 0, |
| thisVaries: new Date(), |
| common: true |
| }, |
| { |
| _id: '1', |
| integer: 1, |
| thisVaries: new Date(), |
| common: true |
| }, |
| { |
| _id: '2', |
| integer: 2, |
| thisVaries: new Date(), |
| common: true |
| }, |
| { |
| _id: '3', |
| integer: 3, |
| thisVaries: new Date(), |
| common: true |
| } |
| ]; |
| var dbr = new PouchDB(remote); |
| rebuildDocuments(dbr, docs, function () { |
| var db = new PouchDB(name); |
| db.replicate.from(remote, function (err, result) { |
| db.query({ map: map }, { reduce: false }, function (err, result) { |
| result.rows.length.should.equal(docs.length); |
| if (--x) { |
| workflow(name, remote, x); |
| } else { |
| db.info(function (err, info) { |
| info.update_seq.should.equal(4); |
| info.doc_count.should.equal(4); |
| done(); |
| }); |
| } |
| }); |
| }); |
| }); |
| }; |
| |
| workflow(dbs.name, dbs.remote, runs); |
| }); |
| |
| it('issue #300 rev id unique per doc', function (done) { |
| var remote = new PouchDB(dbs.remote); |
| var db = new PouchDB(dbs.name); |
| var docs = [{ _id: 'a' }, { _id: 'b' }]; |
| remote.bulkDocs({ docs: docs }, {}, function (err, _) { |
| db.replicate.from(dbs.remote, function (err, _) { |
| db.allDocs(function (err, result) { |
| result.rows.length.should.equal(2); |
| result.rows[0].id.should.equal('a'); |
| result.rows[1].id.should.equal('b'); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(2); |
| info.doc_count.should.equal(2); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('issue #585 Store checkpoint on target db.', function (done) { |
| var db = new PouchDB(dbs.name); |
| var docs = [{ _id: 'a' }, { _id: 'b' }]; |
| db.bulkDocs({ docs: docs }, {}, function (err, _) { |
| db.replicate.to(dbs.remote, function (err, result) { |
| result.docs_written.should.equal(docs.length); |
| PouchDB.destroy(dbs.remote, function (err, result) { |
| db.replicate.to(dbs.remote, function (err, result) { |
| result.docs_written.should.equal(docs.length); |
| db.info(function (err, info) { |
| info.update_seq.should.equal(2); |
| info.doc_count.should.equal(2); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| it('should work with a read only source', function (done) { |
| var src = new PouchDB(dbs.name); |
| var target = new PouchDB(dbs.remote); |
| var err = { |
| "message": "_writer access is required for this request", |
| "name": "unauthorized", |
| "status": 401 |
| }; |
| src.bulkDocs({docs: [ |
| {_id: '0', integer: 0, string: '0'}, |
| {_id: '1', integer: 1, string: '1'}, |
| {_id: '2', integer: 2, string: '2'}, |
| ]}).then(function () { |
| src.put = function () { |
| if (typeof arguments[arguments.length - 1] === 'function') { |
| arguments[arguments.length - 1](err); |
| } else { |
| return PouchDB.utils.Promise.reject(err); |
| } |
| }; |
| return src.replicate.to(target); |
| }).then(function () { |
| target.info(function (err, info) { |
| info.update_seq.should.equal(3); |
| info.doc_count.should.equal(3); |
| done(); |
| }); |
| }, function (a) { |
| done(JSON.stringify(a, false, 4)); |
| }); |
| }); |
| |
| it('issue #2342 update_seq after replication', function (done) { |
| this.timeout(30000); |
| var docs = []; |
| for (var i = 0; i < 10; i++) { |
| docs.push({_id: i.toString()}); |
| } |
| |
| var remote = new PouchDB(dbs.remote); |
| var db = new PouchDB(dbs.name); |
| |
| remote.bulkDocs({ docs: docs }, {}, function (err, res) { |
| res.forEach(function (row, i) { |
| docs[i]._rev = row.rev; |
| if (i % 2 === 0) { |
| docs[i]._deleted = true; |
| } |
| }); |
| remote.bulkDocs({docs: docs}, {}, function (err, res) { |
| db.replicate.from(dbs.remote, function (err, _) { |
| db.info(function (err, info) { |
| db.changes({ |
| since: 'latest', |
| live: true, |
| onChange: function (change) { |
| change.changes.should.have.length(1); |
| change.seq.should.equal(info.update_seq); |
| done(); |
| } |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| it('issue #2393 update_seq after new_edits + replication', function (done) { |
| var docs = [{ |
| '_id': 'foo', |
| '_rev': '1-x', |
| '_revisions': { |
| 'start': 1, |
| 'ids': ['x'] |
| } |
| }]; |
| |
| var db = new PouchDB(dbs.name); |
| var remote = new PouchDB(dbs.remote); |
| |
| remote.bulkDocs({docs: docs, new_edits: false}, function (err, result) { |
| should.not.exist(err); |
| remote.bulkDocs({docs: docs, new_edits: false}, function (err, result) { |
| should.not.exist(err); |
| db.replicate.from(dbs.remote, function (err, _) { |
| db.info(function (err, info) { |
| db.changes({ |
| since: 'latest', |
| live: true, |
| onChange: function (change) { |
| change.changes.should.have.length(1); |
| change.seq.should.equal(info.update_seq); |
| remote.info(function (err, info) { |
| remote.changes({ |
| since: 'latest', |
| live: true, |
| onChange: function (change) { |
| change.changes.should.have.length(1); |
| change.seq.should.equal(info.update_seq); |
| done(); |
| } |
| }); |
| }); |
| } |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| // // This test only needs to run for one configuration, and it slows stuff |
| // // down |
| downAdapters.map(function (adapter) { |
| |
| describe('test.replication.js-down-test', function () { |
| |
| var dbs = {}; |
| |
| beforeEach(function (done) { |
| dbs.name = testUtils.adapterUrl(adapters[0], 'test_repl'); |
| testUtils.cleanup([dbs.name], done); |
| }); |
| |
| afterEach(function (done) { |
| testUtils.cleanup([dbs.name], done); |
| }); |
| |
| it('replicate from down server test', function (done) { |
| var db = new PouchDB(dbs.name); |
| db.replicate.to('http://infiniterequest.com', function (err, changes) { |
| should.exist(err); |
| done(); |
| }); |
| }); |
| |
| }); |
| }); |