-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
feat: Add dynamic retrieval for client password #1926
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
83e8fa5
1d331b4
2d7f9fd
bafdad5
afc7388
14e4fb5
fe5a246
3b1c2e4
e1d71f8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -114,7 +114,28 @@ Client.prototype._connect = function (callback) { | |
|
||
function checkPgPass (cb) { | ||
return function (msg) { | ||
if (self.password !== null) { | ||
if (typeof(self.password) === 'function') { | ||
try { | ||
self._Promise.resolve(self.password()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ohhh nice use on supporting BYOP - not sure how popular BYOP is now that promises have shipped natively in node for years, but still nice for backwards compatibility 👌 |
||
.then(pass => { | ||
if (undefined !== pass) { | ||
charmander marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (typeof(pass) !== 'string') { | ||
charmander marked this conversation as resolved.
Show resolved
Hide resolved
|
||
con.emit('error', new TypeError('Password must be a string')) | ||
return | ||
} | ||
self.connectionParameters.password = self.password = pass | ||
} else { | ||
self.connectionParameters.password = self.password = null | ||
} | ||
cb(msg) | ||
}) | ||
.catch(err => { | ||
con.emit('error', err) | ||
}) | ||
} catch (err) { | ||
con.emit('error', err) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wow - impressive error handling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Apparently not as impressive as @charmander ;-) |
||
} else if (self.password !== null) { | ||
cb(msg) | ||
} else { | ||
pgPass(self.connectionParameters, function (pass) { | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,113 @@ | ||||||
'use strict' | ||||||
const assert = require('assert') | ||||||
const helper = require('./../test-helper') | ||||||
const suite = new helper.Suite() | ||||||
const pg = require('../../../lib/index'); | ||||||
charmander marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
const Client = pg.Client; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (This one still exists) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah i need to turn on linting on the test folder There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would also help if we turned back on the semi rule. This PR passed "make lint" as the semi rule got removed when the eslint config was last cleaned up (by me...). |
||||||
|
||||||
const password = process.env.PGPASSWORD || null; | ||||||
charmander marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
const sleep = millis => new Promise(resolve => setTimeout(resolve, millis)) | ||||||
|
||||||
suite.testAsync('Get password from a sync function', function () { | ||||||
let wasCalled = false | ||||||
function getPassword() { | ||||||
wasCalled = true | ||||||
return password; | ||||||
charmander marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
} | ||||||
const client = new Client({ | ||||||
password: getPassword, | ||||||
}) | ||||||
return client.connect() | ||||||
.then(() => { | ||||||
assert.ok(wasCalled, 'Our password function should have been called') | ||||||
return client.end() | ||||||
}) | ||||||
}) | ||||||
|
||||||
suite.testAsync('Throw error from a sync function', function () { | ||||||
let wasCalled = false | ||||||
const myError = new Error('Oops!') | ||||||
function getPassword() { | ||||||
wasCalled = true | ||||||
throw myError | ||||||
} | ||||||
const client = new Client({ | ||||||
password: getPassword, | ||||||
}) | ||||||
let wasThrown = false | ||||||
return client.connect() | ||||||
.catch(err => { | ||||||
assert.equal(err, myError, 'Our sync error should have been thrown') | ||||||
wasThrown = true | ||||||
}) | ||||||
.then(() => { | ||||||
assert.ok(wasCalled, 'Our password function should have been called') | ||||||
assert.ok(wasThrown, 'Our error should have been thrown') | ||||||
return client.end() | ||||||
}) | ||||||
}) | ||||||
|
||||||
suite.testAsync('Get password from a function asynchronously', function () { | ||||||
let wasCalled = false | ||||||
function getPassword() { | ||||||
wasCalled = true | ||||||
return sleep(100).then(() => password) | ||||||
} | ||||||
const client = new Client({ | ||||||
password: getPassword, | ||||||
}) | ||||||
return client.connect() | ||||||
.then(() => { | ||||||
assert.ok(wasCalled, 'Our password function should have been called') | ||||||
return client.end() | ||||||
}) | ||||||
}) | ||||||
|
||||||
suite.testAsync('Throw error from an async function', function () { | ||||||
let wasCalled = false | ||||||
const myError = new Error('Oops!') | ||||||
function getPassword() { | ||||||
wasCalled = true | ||||||
return sleep(100).then(() => { | ||||||
throw myError | ||||||
}) | ||||||
} | ||||||
const client = new Client({ | ||||||
password: getPassword, | ||||||
}) | ||||||
let wasThrown = false | ||||||
return client.connect() | ||||||
.catch(err => { | ||||||
assert.equal(err, myError, 'Our async error should have been thrown') | ||||||
wasThrown = true | ||||||
}) | ||||||
.then(() => { | ||||||
assert.ok(wasCalled, 'Our password function should have been called') | ||||||
assert.ok(wasThrown, 'Our error should have been thrown') | ||||||
return client.end() | ||||||
}) | ||||||
}) | ||||||
|
||||||
suite.testAsync('Password function must return a string', function () { | ||||||
let wasCalled = false | ||||||
function getPassword() { | ||||||
wasCalled = true | ||||||
// Return a password that is not a string | ||||||
return 12345 | ||||||
} | ||||||
const client = new Client({ | ||||||
password: getPassword, | ||||||
}) | ||||||
let wasThrown = false | ||||||
return client.connect() | ||||||
.catch(err => { | ||||||
assert.ok(err instanceof TypeError, 'A TypeError should have been thrown') | ||||||
assert.equal(err.message, 'Password must be a string') | ||||||
wasThrown = true | ||||||
}) | ||||||
.then(() => { | ||||||
assert.ok(wasCalled, 'Our password function should have been called') | ||||||
assert.ok(wasThrown, 'Our error should have been thrown') | ||||||
return client.end() | ||||||
}) | ||||||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -72,6 +72,19 @@ class Suite { | |
const test = new Test(name, cb) | ||
this._queue.push(test) | ||
} | ||
|
||
testAsync (name, action) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i apologize the tests here aren't written w/ a modern node testing framework. There's this cost-benefit thing I keep running into where it's like "Should I re-write all these tests into jest/mocha/etc? They already work and I know they work...but maybe rewriting will introduce some breakage." The original tests in the repo were written before mocha or jest existed so it's kinda like...well....if it ain't broke...otoh I feel like it's probably more confusing to contribute to. I also at the time, coming from ruby, thought i'd be 'clever' and attach a bunch of stuff to the global namespace like assert and other things. That was a mistake. :( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No worries. I've thought about cleaning up some of them more than once and it's always the same conclusion. Maybe having a separate harness for things going forward as it's definitely easier to write async tests with an async harness. Doesn't even have to be be full on mocha/jest/whatever ... just having something to call out to with async actions should be enough. I like how you can easily run any one of the tests in this project via "node path/to/test.js". |
||
const test = new Test(name, cb => { | ||
try { | ||
Promise.resolve(action()) | ||
.then(() => cb(null)) | ||
.catch((err) => cb(err)) | ||
charmander marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} catch (err) { | ||
cb(err) | ||
} | ||
}) | ||
this._queue.push(test) | ||
} | ||
} | ||
|
||
process.on('unhandledRejection', (e) => { | ||
|
Uh oh!
There was an error while loading. Please reload this page.