From cc22af47cd914b3ea3393676caba2563220864ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20B=C3=B6nnemann?= Date: Tue, 15 Dec 2015 14:37:57 +0100 Subject: [PATCH] WIP: tests --- lib/couchdb.js | 163 ++++++++++++++------------- package.json | 2 +- test/unit/config.js | 3 - test/unit/couchdb/check-vendor.js | 46 ++++++++ test/unit/couchdb/generate-config.js | 54 +++++++++ test/unit/couchdb/get-config.js | 58 ++++++++++ test/unit/couchdb/set-config.js | 36 ++++++ 7 files changed, 279 insertions(+), 83 deletions(-) create mode 100644 test/unit/couchdb/check-vendor.js create mode 100644 test/unit/couchdb/generate-config.js create mode 100644 test/unit/couchdb/get-config.js create mode 100644 test/unit/couchdb/set-config.js diff --git a/lib/couchdb.js b/lib/couchdb.js index 87bb1d8..21793cd 100644 --- a/lib/couchdb.js +++ b/lib/couchdb.js @@ -8,29 +8,8 @@ var log = require('npmlog') var randomstring = require('randomstring') var request = require('request') -module.exports = function (config, callback) { - if (!config.db.url) { - var storePath = join(config.paths.data, 'config.json') - var storeExists = existsSync(storePath) - var store = storeExists && jsonfile.readFileSync(storePath, { - throws: false - }) || {} - var secret = store.couch_httpd_auth_secret - - if (!secret) { - secret = randomstring.generate({ - charset: 'hex' - }) - jsonfile.writeFileSync(storePath, Object.assign(store, { - couch_httpd_auth_secret: secret - }), {spaces: 2}) - } - - return callback(null, { - secret: secret, - authentication_db: '_users' - }) - } +var exports = module.exports = function (config, callback) { + if (!config.db.url) return async.asyncify(exports.generatedConfig)(config, callback) var couch = request.defaults({ baseUrl: config.db.url, @@ -38,62 +17,88 @@ module.exports = function (config, callback) { }) async.waterfall([ - function (callback) { - couch({url: '/'}, function (err, res, data) { - if (err || (res && res.statusCode !== 200)) { - return callback(new Error('Could not find CouchDB at ' + config.db.url)) - } - - var vendor = _.findKey(data, function (prop) { - return /^welcome/i.test(prop) - }) - - if (vendor !== 'couchdb') { - log.warn( - 'database', - 'You are not running an official CouchDB distribution, ' + - 'but "' + vendor + '". ' + - 'This might not be fully supported. Proceed at your own risk.' - ) - } - - callback(null) - }) - }, - function (callback) { - couch({ - url: '/_config/httpd/authentication_handlers', - method: 'PUT', - body: '{couch_httpd_oauth, oauth_authentication_handler},{couch_httpd_auth, default_authentication_handler},{couch_httpd_auth, cookie_authentication_handler}' - }, function (err, res, data) { - if (err || (res && res.statusCode !== 200)) { - return callback(new Error('Could not set necessary CouchDB config')) - } - - callback(null) - }) - }, - function (callback) { - couch({ - url: '/_config/couch_httpd_auth' - }, function (err, res, data) { - if (err || (res && res.statusCode !== 200)) { - return callback(new Error('Could not retrieve necessary CouchDB config values')) - } - - if (!data.secret) { - return callback(new Error('Could not retrieve CouchDB secret')) - } - - if (!data.authentication_db) { - return callback(new Error('Could not retrieve CouchDB authentication database')) - } - - callback(null, _.pick(data, ['secret', 'authentication_db'])) - }) + async.apply(exports.checkVendor, config, couch), + async.apply(exports.getConfig, couch), + async.apply(exports.setConfig, couch) + ], callback) +} + +exports.generatedConfig = function generatedConfig (config) { + var storePath = join(config.paths.data, 'config.json') + var storeExists = existsSync(storePath) + var store = storeExists && jsonfile.readFileSync(storePath, { + throws: false + }) || {} + var secret = store.couch_httpd_auth_secret + + if (!secret) { + secret = randomstring.generate({ + charset: 'hex' + }) + jsonfile.writeFileSync(storePath, Object.assign(store, { + couch_httpd_auth_secret: secret + }), {spaces: 2}) + } + + return { + secret: secret, + authentication_db: '_users' + } +} + +exports.checkVendor = function checkVendor (config, couch, callback) { + couch({url: '/'}, function (err, res, data) { + if (err || (res && res.statusCode !== 200)) { + return callback(new Error('Could not find CouchDB at ' + config.db.url)) + } + + var vendor = _.findKey(data, function (prop) { + return /^welcome/i.test(prop) + }) + + if (vendor !== 'couchdb') { + log.warn( + 'database', + 'You are not running an official CouchDB distribution, ' + + 'but "' + vendor + '". ' + + 'This might not be fully supported. Proceed at your own risk.' + ) + } + + callback(null) + }) +} + +exports.setConfig = function setConfig (couch, callback) { + couch({ + url: '/_config/httpd/authentication_handlers', + method: 'PUT', + body: '{couch_httpd_oauth, oauth_authentication_handler},{couch_httpd_auth, default_authentication_handler},{couch_httpd_auth, cookie_authentication_handler}' + }, function (err, res, data) { + if (err || (res && res.statusCode !== 200)) { + return callback(new Error('Could not set necessary CouchDB config')) + } + + callback(null) + }) +} + +exports.getConfig = function getConfig (couch, callback) { + couch({ + url: '/_config/couch_httpd_auth' + }, function (err, res, data) { + if (err || (res && res.statusCode !== 200)) { + return callback(new Error('Could not retrieve necessary CouchDB config values')) + } + + if (!data.secret) { + return callback(new Error('Could not retrieve CouchDB secret')) + } + + if (!data.authentication_db) { + return callback(new Error('Could not retrieve CouchDB authentication database')) } - ], function (err, result) { - if (err) return callback(err) - callback(null, result) + + callback(null, _.pick(data, ['secret', 'authentication_db'])) }) } diff --git a/package.json b/package.json index e19b9c1..615d045 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,6 @@ "pretest": "standard", "semantic-release": "semantic-release pre && npm publish && semantic-release post", "start": "bin/start", - "test": "nyc tap --no-cov ./test/{unit,integration}/*.js" + "test": "nyc tap --no-cov ./test/{unit,integration}/**/**.js" } } diff --git a/test/unit/config.js b/test/unit/config.js index fe157cc..01c8ea3 100644 --- a/test/unit/config.js +++ b/test/unit/config.js @@ -45,9 +45,6 @@ test('config', function (t) { } }, '@noCallThru': true - }, - touch: { - sync: function () {} } }) diff --git a/test/unit/couchdb/check-vendor.js b/test/unit/couchdb/check-vendor.js new file mode 100644 index 0000000..860c6df --- /dev/null +++ b/test/unit/couchdb/check-vendor.js @@ -0,0 +1,46 @@ +var log = require('npmlog') +var test = require('tap').test + +test('check couch vendor', function (t) { + t.test('request fails', function (tt) { + var checkVendor = require('../../../lib/couchdb.js').checkVendor + + tt.plan(2) + + checkVendor({db: {url: '<% COUCH URL %>'}}, function (input, callback) { + callback(new Error()) + }, function (err) { + tt.match(err.message, '<% COUCH URL %>') + }) + + checkVendor({db: {url: '<% COUCH URL %>'}}, function (input, callback) { + callback(null, {statusCode: 500}) + }, function (err) { + tt.match(err.message, '<% COUCH URL %>') + }) + }) + + t.test('verify vendor', function (tt) { + var checkVendor = require('../../../lib/couchdb.js').checkVendor + tt.plan(3) + + checkVendor({}, function (input, callback) { + callback(null, null, { + couchdb: 'Welcome!' + }) + }, tt.error) + + var tmp = log.warn + log.warn = function (scope, message) { + log.warn = tmp + tt.match(message, '<% VENDOR %>') + } + checkVendor({}, function (input, callback) { + callback(null, null, { + '<% VENDOR %>': 'Welcome!' + }) + }, tt.error) + }) + + t.end() +}) diff --git a/test/unit/couchdb/generate-config.js b/test/unit/couchdb/generate-config.js new file mode 100644 index 0000000..6d1f808 --- /dev/null +++ b/test/unit/couchdb/generate-config.js @@ -0,0 +1,54 @@ +var test = require('tap').test +var proxyquire = require('proxyquire') + +test('generate couch config', function (t) { + t.test('read from file', function (tt) { + var generatedConfig = proxyquire('../../../lib/couchdb.js', { + fs: { + existsSync: function () { + return true + }, + '@noCallThru': true + }, + jsonfile: { + readFileSync: function () { + return { + couch_httpd_auth_secret: 'a' + } + }, + '@noCallThru': true + } + }).generatedConfig + + var result = generatedConfig({paths: {data: ''}}) + + tt.is(result.secret, 'a') + tt.is(result.authentication_db, '_users') + + tt.end() + }) + + t.test('generate and write to file', function (tt) { + var generatedConfig = proxyquire('../../../lib/couchdb.js', { + fs: { + existsSync: function () { + return false + }, + '@noCallThru': true + }, + jsonfile: { + writeFileSync: function () {}, + '@noCallThru': true + } + }).generatedConfig + + var result = generatedConfig({paths: {data: ''}}) + + tt.is(result.secret.length, 32) + tt.is(result.authentication_db, '_users') + + tt.end() + }) + + t.end() +}) diff --git a/test/unit/couchdb/get-config.js b/test/unit/couchdb/get-config.js new file mode 100644 index 0000000..1d322e1 --- /dev/null +++ b/test/unit/couchdb/get-config.js @@ -0,0 +1,58 @@ +var test = require('tap').test + +test('get couch config', function (t) { + t.test('request fails', function (tt) { + var getConfig = require('../../../lib/couchdb.js').getConfig + + tt.plan(2) + + getConfig(function (input, callback) { + callback(new Error()) + }, function (err) { + tt.ok(err instanceof Error) + }) + + getConfig(function (input, callback) { + callback(null, {statusCode: 500}) + }, function (err) { + tt.ok(err instanceof Error) + }) + }) + + t.test('request succeds', function (tt) { + var getConfig = require('../../../lib/couchdb.js').getConfig + + tt.plan(9) + + getConfig(function (input, callback) { + tt.is(input.url, '/_config/couch_httpd_auth') + callback(null, null, {}) + }, function (err) { + tt.ok(err instanceof Error) + }) + + getConfig(function (input, callback) { + tt.is(input.url, '/_config/couch_httpd_auth') + callback(null, null, {secret: 'foo'}) + }, function (err) { + tt.ok(err instanceof Error) + }) + + getConfig(function (input, callback) { + tt.is(input.url, '/_config/couch_httpd_auth') + callback(null, null, { + secret: 'foo', + authentication_db: 'bar', + ignore: 'baz' + }) + }, function (err, result) { + tt.error(err) + + tt.is(result.secret, 'foo') + tt.is(result.authentication_db, 'bar') + tt.notOk(result.ignore) + }) + }) + + t.end() +}) diff --git a/test/unit/couchdb/set-config.js b/test/unit/couchdb/set-config.js new file mode 100644 index 0000000..cbcb448 --- /dev/null +++ b/test/unit/couchdb/set-config.js @@ -0,0 +1,36 @@ +var test = require('tap').test + +test('set couch config', function (t) { + t.test('request fails', function (tt) { + var setConfig = require('../../../lib/couchdb.js').setConfig + + tt.plan(2) + + setConfig(function (input, callback) { + callback(new Error()) + }, function (err) { + tt.ok(err instanceof Error) + }) + + setConfig(function (input, callback) { + callback(null, {statusCode: 500}) + }, function (err) { + tt.ok(err instanceof Error) + }) + }) + + t.test('request succeds', function (tt) { + var setConfig = require('../../../lib/couchdb.js').setConfig + + tt.plan(4) + + setConfig(function (input, callback) { + tt.is(input.url, '/_config/httpd/authentication_handlers') + tt.is(input.method, 'PUT') + tt.is(input.body, '{couch_httpd_oauth, oauth_authentication_handler},{couch_httpd_auth, default_authentication_handler},{couch_httpd_auth, cookie_authentication_handler}') + callback(null) + }, tt.error) + }) + + t.end() +})