Skip to content

Commit

Permalink
WIP: tests
Browse files Browse the repository at this point in the history
  • Loading branch information
boennemann committed Dec 15, 2015
1 parent 6a34beb commit cc22af4
Show file tree
Hide file tree
Showing 7 changed files with 279 additions and 83 deletions.
163 changes: 84 additions & 79 deletions lib/couchdb.js
Expand Up @@ -8,92 +8,97 @@ 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,
json: true
})

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']))
})
}
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -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"
}
}
3 changes: 0 additions & 3 deletions test/unit/config.js
Expand Up @@ -45,9 +45,6 @@ test('config', function (t) {
}
},
'@noCallThru': true
},
touch: {
sync: function () {}
}
})

Expand Down
46 changes: 46 additions & 0 deletions 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()
})
54 changes: 54 additions & 0 deletions 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()
})
58 changes: 58 additions & 0 deletions 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()
})
36 changes: 36 additions & 0 deletions 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()
})

0 comments on commit cc22af4

Please sign in to comment.