diff --git a/lib/connection.js b/lib/connection.js index c9ed9b8a..7201a980 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -9,14 +9,7 @@ var BufferList = require(__dirname + '/buffer-list'); var Connection = function(config) { EventEmitter.call(this); config = config || {}; - this.user = config.user; - this.database = config.database; - this.port = config.port || 5432; - this.host = config.host; - this.queryQueue = []; this.stream = config.stream || new net.Stream(); - this.queryQueue = []; - this.password = config.password || ''; this.lastBuffer = false; this.lastOffset = 0; this.buffer = null; @@ -28,23 +21,19 @@ sys.inherits(Connection, EventEmitter); var p = Connection.prototype; -p.connect = function() { +p.connect = function(port, host) { if(this.stream.readyState === 'closed'){ - this.stream.connect(this.port, this.host); + this.stream.connect(port, host); + }else if(this.stream.readyState == 'open') { + this.emit('connect'); } var self = this; + this.stream.on('connect', function() { - var data = ['user',self.user,'database', self.database, '\0'].join('\0'); - var byteLength = Buffer.byteLength(data); - var fullBuffer = new Buffer(byteLength + 4); - fullBuffer[0] = 0; - fullBuffer[1] = 3; - fullBuffer[2] = 0; - fullBuffer[3] = 0; - fullBuffer.write(data, 4); - self.send(null, fullBuffer); + self.emit('connect'); }); + this.stream.on('data', function(buffer) { self.setBuffer(buffer); var msg; @@ -53,18 +42,18 @@ p.connect = function() { self.emit(msg.name, msg); } }); +}; - this.on('authenticationCleartextPassword', function() { - self.send('p', new Buffer(self.password + '\0', self.encoding)); - }); - - this.on('authenticationMD5Password', function(msg) { - var enc = function(string) { - return crypto.createHash('md5').update(string).digest('hex'); - } - var md5password = "md5" + enc(enc(self.password + self.user) + msg.salt.toString('binary')) + "\0"; - self.send('p', new Buffer(md5password, self.encoding)); - }); +p.startupMessage = function(config) { + var buffer = new BufferList() + .addInt16(3) + .addInt16(0) + .addCString('user') + .addCString(config.user) + .addCString('database') + .addCString(config.database) + .addCString(''); + this.send(false, buffer.join()); }; p.send = function(code, bodyBuffer) { @@ -92,7 +81,7 @@ p.end = function() { }; p.query = function(text) { - this.send('Q', new Buffer(query.text + '\0', this.encoding)); + this.send('Q', new Buffer(text + '\0', this.encoding)); }; p.parse = function(query) { @@ -349,4 +338,4 @@ p.parseCString = function() { return this.buffer.toString(this.encoding, start, this.offset - 1); }; //end parsing methods -module.exports = Client; +module.exports = Connection; diff --git a/test/unit/communication-tests.js b/test/unit/communication-tests.js deleted file mode 100644 index d3b23b95..00000000 --- a/test/unit/communication-tests.js +++ /dev/null @@ -1,101 +0,0 @@ -require(__dirname+'/test-helper'); - -test('client can take existing stream', function() { - var stream = new MemoryStream(); - var client = new Client({ - stream: stream - }); - assert.equal(client.stream, stream); -}); - -test('using closed stream', function() { - var stream = new MemoryStream(); - stream.readyState = 'closed'; - stream.connect = function(port, host) { - this.connectCalled = true; - this.port = port; - this.host = host; - } - var client = new Client({ - stream: stream, - user: '!', - database: 'x', - host: 'bang', - port: 1234 - }); - client.connect(); - - test('makes stream connect', function() { - assert.equal(stream.connectCalled, true); - }); - - test('uses configured port', function() { - assert.equal(stream.port, 1234); - }); - - test('uses configured host', function() { - assert.equal(stream.host, 'bang'); - }); - - test('after stream connects', function() { - stream.emit('connect'); - - test('sends connection packet', function() { - assert.length(stream.packets, 1); - var expectedBuffer = new BufferList() - .add(Buffer([0,3,0, 0]))//version - .addCString('user') - .addCString('!') - .addCString('database') - .addCString('x') - .addCString("") //final terminator - .join(true); - assert.equalBuffers(stream.packets[0], expectedBuffer); - }); - - }); - - -}); - -test('using opened stream', function() { - var stream = new MemoryStream(); - stream.readyState = 'open'; - stream.connect = function() { - assert.ok(false, "Should not call open"); - }; - var client = new Client({stream: stream}); - test('does not call open', function() { - client.connect(); - }); -}); - -test('query queue', function() { - - var stream = new MemoryStream(); - - stream.readyState = 'open'; - - var client = new Client({ - stream: stream - }); - client.connect(); - - test('new client has empty queue', function() { - assert.empty(client.queryQueue); - }); - - test('calling query queues the query object', function() { - var query = client.query('!'); - assert.length(client.queryQueue, 1); - }); - - test('sends query after stream emits ready for query packet', function() { - assert.empty(stream.packets); - var handled = stream.emit('data', buffers.readyForQuery()); - assert.ok(handled, "Stream should have had data handled"); - assert.length(stream.packets, 1); - assert.equalBuffers(stream.packets[0], [0x51,0,0,0,6,33,0]) - }); - -}); diff --git a/test/unit/connection-message-sending-tests.js b/test/unit/connection-message-sending-tests.js new file mode 100644 index 00000000..7b142ef1 --- /dev/null +++ b/test/unit/connection-message-sending-tests.js @@ -0,0 +1,89 @@ +require(__dirname + "/test-helper"); +var stream = new MemoryStream(); +var con = new Connection({ + stream: stream +}); + +assert.recieved = function(stream, buffer) { + assert.length(stream.packets, 1); + var packet = stream.packets.pop(); + assert.equalBuffers(packet, buffer); +}; + +test("sends startup message", function() { + con.startupMessage({ + user: 'brian', + database: 'bang' + }); + assert.recieved(stream, new BufferList() + .addInt16(3) + .addInt16(0) + .addCString('user') + .addCString('brian') + .addCString('database') + .addCString('bang') + .addCString('').join(true)) +}); + +test('sends query message', function() { + var txt = 'select * from boom'; + con.query(txt); + assert.recieved(stream, new BufferList().addCString(txt).join(true,'Q')); +}); + +test('sends parse message', function() { + con.parse({text: '!'}); + var expected = new BufferList() + .addCString("") + .addCString("!") + .addInt16(0).join(true, 'P'); + assert.recieved(stream, expected); +}); + +test('sends parse message with named query', function() { + con.parse({ + name: 'boom', + text: 'select * from boom', + types: [] + }); + var expected = new BufferList() + .addCString("boom") + .addCString("select * from boom") + .addInt16(0).join(true,'P'); + assert.recieved(stream, expected); +}); + +test('sends bind to unamed statement with no values', function() { + con.bind(); + + var expectedBuffer = new BufferList() + .addCString("") + .addCString("") + .addInt16(0) + .addInt16(0) + .addInt16(0).join(true,"B"); + assert.recieved(stream, expectedBuffer); +}); + + +test("sends execute message for unamed portal with no row limit", function() { + con.execute(); + var expectedBuffer = new BufferList() + .addCString('') + .addInt32(0) + .join(true,'E'); + assert.recieved(stream, expectedBuffer); +}); + + +test('sends flush command', function() { + con.flush(); + var expected = new BufferList().join(true, 'H'); + assert.recieved(stream, expected); +}); + +test('sends sync command', function() { + con.sync(); + var expected = new BufferList().join(true,'S'); + assert.recieved(stream, expected); +}); diff --git a/test/unit/connection-startup-tests.js b/test/unit/connection-startup-tests.js new file mode 100644 index 00000000..d1603418 --- /dev/null +++ b/test/unit/connection-startup-tests.js @@ -0,0 +1,64 @@ +require(__dirname+'/test-helper'); + +test('connection can take existing stream', function() { + var stream = new MemoryStream(); + var con = new Connection({stream: stream}); + assert.equal(con.stream, stream); +}); + +test('using closed stream', function() { + var stream = new MemoryStream(); + stream.readyState = 'closed'; + stream.connect = function(port, host) { + this.connectCalled = true; + this.port = port; + this.host = host; + } + + var con = new Connection({stream: stream}); + + con.connect(1234, 'bang'); + + test('makes stream connect', function() { + assert.equal(stream.connectCalled, true); + }); + + test('uses configured port', function() { + assert.equal(stream.port, 1234); + }); + + test('uses configured host', function() { + assert.equal(stream.host, 'bang'); + }); + + test('after stream connects client emits connected event', function() { + + var hit = false; + + con.once('connect', function() { + hit = true; + }); + + assert.ok(stream.emit('connect')); + assert.ok(hit); + + }); +}); + +test('using opened stream', function() { + var stream = new MemoryStream(); + stream.readyState = 'open'; + stream.connect = function() { + assert.ok(false, "Should not call open"); + }; + var con = new Connection({stream: stream}); + test('does not call open', function() { + var hit = false; + con.once('connect', function() { + hit = true; + }); + con.connect(); + assert.ok(hit); + }); + +}); diff --git a/test/unit/prepared-query-tests.js b/test/unit/prepared-query-tests.js index bd4fc7a7..f4da768b 100644 --- a/test/unit/prepared-query-tests.js +++ b/test/unit/prepared-query-tests.js @@ -72,20 +72,4 @@ test('prepared queries', function() { }); - test('sends flush command', function() { - client.flush(); - assert.length(client.stream.packets, 1); - var packet = client.stream.packets.pop(); - var expected = new BufferList().join(true, 'H'); - assert.equalBuffers(packet, expected); - }); - - test('sends sync command', function() { - client.sync(); - assert.length(client.stream.packets, 1); - var packet = client.stream.packets.pop(); - var expected = new BufferList().join(true,'S'); - assert.equalBuffers(packet, expected); - }); - }); diff --git a/test/unit/test-helper.js b/test/unit/test-helper.js index 2ca5dd57..32dd10f4 100644 --- a/test/unit/test-helper.js +++ b/test/unit/test-helper.js @@ -4,7 +4,7 @@ Client = require(__dirname+'/../../lib/client'); EventEmitter = require('events').EventEmitter; BufferList = require(__dirname+'/../../lib/buffer-list'); buffers = require(__dirname+'/test-buffers'); -Connection = require(__dirname + '/../../lib/connection'); +Connection = require(__dirname + '/../../lib/connection') assert.same = function(actual, expected) { for(var key in expected) { assert.equal(actual[key], expected[key]); @@ -46,7 +46,7 @@ test = function(name, action) { } }catch(e) { process.stdout.write('E'); - test.errors.push(e); + test.errors.push({name: name, e: e}); } }; test.testCount = 0; @@ -62,8 +62,12 @@ process.on('exit', function() { console.log("Ignored: " + name); }); test.errors.forEach(function(error) { - throw error; + console.log("Error: " + error.name); }); + test.errors.forEach(function(error) { + throw error.e; + }); + }); MemoryStream = function() {