(#4071) - remove http dead code and better tests
diff --git a/lib/adapters/http/index.js b/lib/adapters/http/index.js
index eda4bbd..de58de6 100644
--- a/lib/adapters/http/index.js
+++ b/lib/adapters/http/index.js
@@ -23,6 +23,7 @@
var log = require('debug')('pouchdb:http');
var createMultipart = require('../../deps/ajax/multipart');
var blufferToBase64 = require('../../deps/binary/blobOrBufferToBase64');
+var parseDoc = require('../../deps/docs/parseDoc');
function readAttachmentsAsBlobOrBuffer(row) {
var atts = row.doc && row.doc._attachments;
@@ -63,51 +64,40 @@
// Get all the information you possibly can about the URI given by name and
// return it as a suitable object.
function getHost(name, opts) {
- // If the given name contains "http:"
- if (/http(s?):/.test(name)) {
- // Prase the URI into all its little bits
- var uri = utils.parseUri(name);
+ // Prase the URI into all its little bits
+ var uri = utils.parseUri(name);
- // Store the fact that it is a remote URI
- uri.remote = true;
-
- // Store the user and password as a separate auth object
- if (uri.user || uri.password) {
- uri.auth = {username: uri.user, password: uri.password};
- }
-
- // Split the path part of the URI into parts using '/' as the delimiter
- // after removing any leading '/' and any trailing '/'
- var parts = uri.path.replace(/(^\/|\/$)/g, '').split('/');
-
- // Store the first part as the database name and remove it from the parts
- // array
- uri.db = parts.pop();
-
- // Restore the path by joining all the remaining parts (all the parts
- // except for the database name) with '/'s
- uri.path = parts.join('/');
- opts = opts || {};
- opts = clone(opts);
- uri.headers = opts.headers || (opts.ajax && opts.ajax.headers) || {};
-
- if (opts.auth || uri.auth) {
- var nAuth = opts.auth || uri.auth;
- var token = btoa(nAuth.username + ':' + nAuth.password);
- uri.headers.Authorization = 'Basic ' + token;
- }
-
- if (opts.headers) {
- uri.headers = opts.headers;
- }
-
- return uri;
+ // Store the user and password as a separate auth object
+ if (uri.user || uri.password) {
+ uri.auth = {username: uri.user, password: uri.password};
}
- // If the given name does not contain 'http:' then return a very basic object
- // with no host, the current path, the given name as the database name and no
- // username/password
- return {host: '', path: '/', db: name, auth: false};
+ // Split the path part of the URI into parts using '/' as the delimiter
+ // after removing any leading '/' and any trailing '/'
+ var parts = uri.path.replace(/(^\/|\/$)/g, '').split('/');
+
+ // Store the first part as the database name and remove it from the parts
+ // array
+ uri.db = parts.pop();
+
+ // Restore the path by joining all the remaining parts (all the parts
+ // except for the database name) with '/'s
+ uri.path = parts.join('/');
+ opts = opts || {};
+ opts = clone(opts);
+ uri.headers = opts.headers || (opts.ajax && opts.ajax.headers) || {};
+
+ if (opts.auth || uri.auth) {
+ var nAuth = opts.auth || uri.auth;
+ var token = btoa(nAuth.username + ':' + nAuth.password);
+ uri.headers.Authorization = 'Basic ' + token;
+ }
+
+ if (opts.headers) {
+ uri.headers = opts.headers;
+ }
+
+ return uri;
}
// Generate a URL with the host data given by opts and the given path
@@ -117,28 +107,31 @@
// Generate a URL with the host data given by opts and the given path
function genUrl(opts, path) {
- if (opts.remote) {
- // If the host already has a path, then we need to have a path delimiter
- // Otherwise, the path delimiter is the empty string
- var pathDel = !opts.path ? '' : '/';
+ // If the host already has a path, then we need to have a path delimiter
+ // Otherwise, the path delimiter is the empty string
+ var pathDel = !opts.path ? '' : '/';
- // If the host already has a path, then we need to have a path delimiter
- // Otherwise, the path delimiter is the empty string
- return opts.protocol + '://' + opts.host + ':' + opts.port + '/' +
- opts.path + pathDel + path;
- }
-
- return '/' + path;
+ // If the host already has a path, then we need to have a path delimiter
+ // Otherwise, the path delimiter is the empty string
+ return opts.protocol + '://' + opts.host + ':' + opts.port + '/' +
+ opts.path + pathDel + path;
}
// Implements the PouchDB API for dealing with CouchDB instances over HTTP
function HttpPouch(opts, callback) {
// The functions that will be publicly available for HttpPouch
var api = this;
- api.getHost = opts.getHost ? opts.getHost : getHost;
// Parse the URI given by opts.name into an easy-to-use object
- var host = api.getHost(opts.name, opts);
+ var getHostFun = getHost;
+
+ // TODO: this seems to only be used by yarong for the Thali project.
+ // Verify whether or not it's still needed.
+ /* istanbul ignore:next */
+ if (opts.getHost) {
+ getHostFun = opts.getHost;
+ }
+ var host = getHostFun(opts.name, opts);
// Generate the database URL based on the host
var dbUrl = genDBUrl(host, '');
@@ -173,6 +166,7 @@
url: dbUrl
}, function (err) {
// If we get an "Unauthorized" error
+ /* istanbul ignore else */
if (err && err.status === 401) {
// Test if the database already exists
ajax({headers: clone(host.headers), method: 'HEAD', url: dbUrl},
@@ -231,11 +225,11 @@
method: 'GET',
url: genUrl(host, '')
}, function (err, result) {
+ /* istanbul ignore next */
if (err) {
return callback(err);
}
- var uuid = (result && result.uuid) ?
- result.uuid + host.db : genDBUrl(host, '');
+ var uuid = result.uuid + host.db;
callback(null, uuid);
});
});
@@ -269,9 +263,7 @@
});
}
// Ping the http if it's finished compaction
- if (typeof callback === "function") {
- ping();
- }
+ ping();
});
});
@@ -284,12 +276,12 @@
method: 'GET',
url: genDBUrl(host, '')
}, function (err, res) {
+ /* istanbul ignore next */
if (err) {
- callback(err);
- } else {
- res.host = genDBUrl(host, '');
- callback(null, res);
+ return callback(err);
}
+ res.host = genDBUrl(host, '');
+ callback(null, res);
});
};
@@ -501,11 +493,6 @@
blob = rev;
rev = null;
}
- if (typeof type === 'undefined') {
- type = blob;
- blob = rev;
- rev = null;
- }
var id = encodeDocId(docId) + '/' + encodeAttachmentId(attachmentId);
var url = genDBUrl(host, id);
if (rev) {
@@ -567,10 +554,10 @@
}
}
opts = opts || {};
- var error = utils.invalidIdError(doc._id);
- if (error) {
- throw error;
- }
+
+ // check for any errors
+ // TODO: rename this function
+ parseDoc.invalidIdError(doc._id);
// List of parameter to add to the PUT request
var params = [];
@@ -646,14 +633,10 @@
// Update/create multiple documents given by req in the database
// given by host.
api._bulkDocs = function (req, opts, callback) {
- // If opts.new_edits exists add it to the document data to be
- // send to the database.
// If new_edits=false then it prevents the database from creating
// new revision numbers for the documents. Instead it just uses
// the old ones. This is used in database replication.
- if (typeof opts.new_edits !== 'undefined') {
- req.new_edits = opts.new_edits;
- }
+ req.new_edits = opts.new_edits;
Promise.all(req.docs.map(preprocessAttachments)).then(function () {
// Update/create the documents
@@ -796,9 +779,6 @@
// an ok timeout
var params = { timeout: opts.timeout - (5 * 1000) };
var limit = (typeof opts.limit !== 'undefined') ? opts.limit : false;
- if (limit === 0) {
- limit = 1;
- }
var returnDocs;
if ('returnDocs' in opts) {
returnDocs = opts.returnDocs;
@@ -845,6 +825,7 @@
// These parameters may be used by the filter on the source database.
if (opts.query_params && typeof opts.query_params === 'object') {
for (var param_name in opts.query_params) {
+ /* istanbul ignore else */
if (opts.query_params.hasOwnProperty(param_name)) {
params[param_name] = opts.query_params[param_name];
}
@@ -884,6 +865,8 @@
return;
}
params.since = since;
+ // "since" can be any kind of json object in Coudant/CouchDB 2.x
+ /* istanbul ignore next */
if (typeof params.since === "object") {
params.since = JSON.stringify(params.since);
}
@@ -1095,14 +1078,14 @@
method: 'DELETE',
headers: clone(host.headers)
}, function (err, resp) {
+ /* istanbul ignore next */
if (err) {
api.emit('error', err);
- callback(err);
- } else {
- api.emit('destroyed');
- api.constructor.emit('destroyed', opts.name);
- callback(null, resp);
+ return callback(err);
}
+ api.emit('destroyed');
+ api.constructor.emit('destroyed', opts.name);
+ callback(null, resp);
});
};
}
diff --git a/lib/deps/docs/updateDoc.js b/lib/deps/docs/updateDoc.js
index 06dfe0c..c3c50a6 100644
--- a/lib/deps/docs/updateDoc.js
+++ b/lib/deps/docs/updateDoc.js
@@ -50,8 +50,9 @@
var newRev = docInfo.metadata.rev;
docInfo.metadata.rev_tree = merged.tree;
+ /* istanbul ignore else */
if (prev.rev_map) {
- docInfo.metadata.rev_map = prev.rev_map; // used by leveldb
+ docInfo.metadata.rev_map = prev.rev_map; // used only by leveldb
}
// recalculate
diff --git a/tests/integration/test.attachments.js b/tests/integration/test.attachments.js
index c2cd4ca..fa6296a 100644
--- a/tests/integration/test.attachments.js
+++ b/tests/integration/test.attachments.js
@@ -85,6 +85,43 @@
}
};
+ it('fetch atts with open_revs and missing', function () {
+ var db = new PouchDB(dbs.name);
+ var doc = {
+ _id: 'frog',
+ _rev: '1-x',
+ _revisions: {
+ start: 1,
+ ids: ['x']
+ },
+ _attachments: {
+ 'foo.txt': {
+ content_type: 'text/plain',
+ data: ''
+ }
+ }
+ };
+ return db.bulkDocs({
+ docs: [doc],
+ new_edits: false
+ }).then(function () {
+ return db.get('frog', {
+ revs: true,
+ open_revs: ['1-x', '2-fake'],
+ attachments: true
+ });
+ }).then(function (res) {
+ // there should be exactly one "ok" result
+ // and one result with attachments
+ res.filter(function (x) {
+ return x.ok;
+ }).should.have.length(1);
+ res.filter(function (x) {
+ return x.ok && x.ok._attachments;
+ }).should.have.length(1);
+ });
+ });
+
it('issue 2803 should throw 412', function () {
var db = new PouchDB(dbs.name);
return db.put(binAttDoc).then(function () {
diff --git a/tests/integration/test.basics.js b/tests/integration/test.basics.js
index 2236e02..cfcfac0 100644
--- a/tests/integration/test.basics.js
+++ b/tests/integration/test.basics.js
@@ -77,6 +77,14 @@
}, done);
});
+ it('Add a doc with opts object', function (done) {
+ var db = new PouchDB(dbs.name);
+ db.post({test: 'somestuff'}, {}, function (err, info) {
+ should.not.exist(err);
+ done();
+ });
+ });
+
it('Modify a doc', function (done) {
var db = new PouchDB(dbs.name);
db.post({test: 'somestuff'}, function (err, info) {
diff --git a/tests/integration/test.compaction.js b/tests/integration/test.compaction.js
index 21c7070..2cd037c 100644
--- a/tests/integration/test.compaction.js
+++ b/tests/integration/test.compaction.js
@@ -30,6 +30,13 @@
});
});
+ it('compact with options object', function () {
+ var db = new PouchDB(dbs.name);
+ return db.compact({}).then(function (result) {
+ result.should.eql({ok: true});
+ });
+ });
+
it('#2913 massively parallel compaction', function () {
var db = new PouchDB(dbs.name);
var tasks = [];
diff --git a/tests/integration/test.http.js b/tests/integration/test.http.js
index 56b0e2f..d69333c 100644
--- a/tests/integration/test.http.js
+++ b/tests/integration/test.http.js
@@ -122,4 +122,72 @@
PouchDB.utils.ajax = ajax;
});
+
+ it('Test unauthorized user', function () {
+ var db = new PouchDB(dbs.name, {
+ auth: {
+ user: 'foo',
+ password: 'bar'
+ }
+ });
+ return db.info().then(function () {
+ if (testUtils.isExpressRouter()) {
+ return; // express-router doesn't do auth
+ }
+ throw new Error('expected an error');
+ }, function (err) {
+ should.exist(err); // 401 error
+ });
+ });
+
+ it('Test unauthorized user, user/pass in url itself', function () {
+ var dbname = dbs.name.replace(/\/\//, '//foo:bar@');
+ var db = new PouchDB(dbname);
+ return db.info().then(function () {
+ if (testUtils.isExpressRouter()) {
+ return; // express-router doesn't do auth
+ }
+ throw new Error('expected an error');
+ }, function (err) {
+ should.exist(err); // 401 error
+ });
+ });
+
+ it('Test custom header', function () {
+ var db = new PouchDB(dbs.name, {
+ headers: {
+ 'X-Custom': 'some-custom-header'
+ }
+ });
+ return db.info();
+ });
+
+ it('getUrl() works (used by plugins)', function () {
+ var db = new PouchDB(dbs.name);
+ db.getUrl().should.match(/^http/);
+ });
+
+ it('getHeaders() works (used by plugins)', function () {
+ var db = new PouchDB(dbs.name);
+ db.getHeaders().should.deep.equal({});
+ });
+
+ it('test url too long error for allDocs()', function () {
+ var docs = [];
+ var numDocs = 75;
+ for (var i = 0; i < numDocs; i++) {
+ docs.push({
+ _id: 'fairly_long_doc_name_' + i
+ });
+ }
+ var db = new PouchDB(dbs.name);
+ return db.bulkDocs(docs).then(function () {
+ return db.allDocs({
+ keys: docs.map(function (x) { return x._id; })
+ });
+ }).then(function (res) {
+ res.rows.should.have.length(numDocs);
+ });
+ });
+
});
diff --git a/tests/integration/test.revs_diff.js b/tests/integration/test.revs_diff.js
index deda990..13ff98d 100644
--- a/tests/integration/test.revs_diff.js
+++ b/tests/integration/test.revs_diff.js
@@ -44,6 +44,33 @@
});
});
+ it('Test revs diff with opts object', function (done) {
+ var db = new PouchDB(dbs.name, {auto_compaction: false});
+ var revs = [];
+ db.post({
+ test: 'somestuff',
+ _id: 'somestuff'
+ }, function (err, info) {
+ revs.push(info.rev);
+ db.put({
+ _id: info.id,
+ _rev: info.rev,
+ another: 'test'
+ }, function (err, info2) {
+ revs.push(info2.rev);
+ db.revsDiff({ 'somestuff': revs }, {}, function (err, results) {
+ results.should.not.include.keys('somestuff');
+ revs.push('2-randomid');
+ db.revsDiff({ 'somestuff': revs }, function (err, results) {
+ results.should.include.keys('somestuff');
+ results.somestuff.missing.should.have.length(1);
+ done();
+ });
+ });
+ });
+ });
+ });
+
it('Missing docs should be returned with all revisions', function (done) {
new PouchDB(dbs.name, function (err, db) {
var revs = ['1-a', '2-a', '2-b'];
diff --git a/tests/integration/utils.js b/tests/integration/utils.js
index 9662778..38bd7a2 100644
--- a/tests/integration/utils.js
+++ b/tests/integration/utils.js
@@ -22,6 +22,11 @@
testUtils.params().SERVER === 'sync-gateway';
};
+testUtils.isExpressRouter = function () {
+ return 'SERVER' in testUtils.params() &&
+ testUtils.params().SERVER === 'pouchdb-express-router';
+};
+
testUtils.params = function () {
if (typeof module !== 'undefined' && module.exports) {
return process.env;