Initial work on the server

This commit is contained in:
Abhishek Das
2013-03-25 05:57:47 +05:30
parent 93400554fd
commit 0485272d93
626 changed files with 121311 additions and 1 deletions
+147
View File
@@ -0,0 +1,147 @@
// An experimental fake MySQL server for tricky integration tests. Expanded
// as needed.
var Net = require('net');
var Packets = require('../lib/protocol/packets');
var PacketWriter = require('../lib/protocol/PacketWriter');
var Parser = require('../lib/protocol/Parser');
var Auth = require('../lib/protocol/Auth');
var EventEmitter = require('events').EventEmitter;
var Util = require('util');
module.exports = FakeServer;
Util.inherits(FakeServer, EventEmitter);
function FakeServer(options) {
EventEmitter.call(this);
this._server = null;
this._connections = [];
}
FakeServer.prototype.listen = function(port, cb) {
this._server = Net.createServer(this._handleConnection.bind(this));
this._server.listen(port, cb);
};
FakeServer.prototype._handleConnection = function(socket) {
var connection = new FakeConnection(socket);
this.emit('connection', connection);
this._connections.push(connection);
};
FakeServer.prototype.destroy = function() {
this._server.close();
this._connections.forEach(function(connection) {
connection.destroy();
});
};
Util.inherits(FakeConnection, EventEmitter);
function FakeConnection(socket) {
EventEmitter.call(this);
this._socket = socket;
this._parser = new Parser({onPacket: this._parsePacket.bind(this)});
this._handshakeInitializationPacket = null;
this._clientAuthenticationPacket = null;
this._oldPasswordPacket = null;
this._handshakeOptions = {};
socket.on('data', this._handleData.bind(this));
}
FakeConnection.prototype.handshake = function(options) {
this._handshakeOptions = options || {};
this._handshakeInitializationPacket = new Packets.HandshakeInitializationPacket({
scrambleBuff1: new Buffer(8),
scrambleBuff2: new Buffer(12),
});
this._sendPacket(this._handshakeInitializationPacket);
};
FakeConnection.prototype.deny = function(message, errno) {
this._sendPacket(new Packets.ErrorPacket({
message: message,
errno: errno,
}));
};
FakeConnection.prototype._sendPacket = function(packet) {
var writer = new PacketWriter();
packet.write(writer);
this._socket.write(writer.toBuffer(this._parser));
};
FakeConnection.prototype._handleData = function(buffer) {
this._parser.write(buffer);
};
FakeConnection.prototype._parsePacket = function(header) {
var Packet = this._determinePacket(header);
var packet = new Packet();
packet.parse(this._parser);
switch (Packet) {
case Packets.ClientAuthenticationPacket:
this._clientAuthenticationPacket = packet;
if (this._handshakeOptions.oldPassword) {
this._sendPacket(new Packets.UseOldPasswordPacket());
} else {
if (this._handshakeOptions.user || this._handshakeOptions.password) {
throw new Error('not implemented');
}
this._sendPacket(new Packets.OkPacket());
this._parser.resetPacketNumber();
}
break;
case Packets.OldPasswordPacket:
this._oldPasswordPacket = packet;
var expected = Auth.scramble323(this._handshakeInitializationPacket.scrambleBuff(), this._handshakeOptions.password);
var got = packet.scrambleBuff;
var toString = function(buffer) {
return Array.prototype.slice.call(buffer).join(',');
};
if (toString(expected) === toString(got)) {
this._sendPacket(new Packets.OkPacket());
} else {
this._sendPacket(new Packets.ErrorPacket());
}
this._parser.resetPacketNumber();
break;
case Packets.ComQueryPacket:
this.emit('query', packet);
break;
default:
throw new Error('Unexpected packet: ' + Packet.name)
}
};
FakeConnection.prototype._determinePacket = function() {
if (!this._clientAuthenticationPacket) {
return Packets.ClientAuthenticationPacket;
} else if (this._handshakeOptions.oldPassword && !this._oldPasswordPacket) {
return Packets.OldPasswordPacket;
}
var firstByte = this._parser.peak();
switch (firstByte) {
case 0x03: return Packets.ComQueryPacket;
default:
throw new Error('Unknown packet, first byte: ' + firstByte);
break;
}
};
FakeConnection.prototype.destroy = function() {
this._socket.destroy();
};
+65
View File
@@ -0,0 +1,65 @@
var common = exports;
var path = require('path');
var _ = require('underscore');
var FakeServer = require('./FakeServer');
common.lib = path.join(__dirname, '../lib');
common.fixtures = path.join(__dirname, 'fixtures');
// Useful for triggering ECONNREFUSED errors on connect()
common.bogusPort = 47378;
// Useful for triggering ER_ACCESS_DENIED_ERROR errors on connect()
common.bogusPassword = 'INVALID PASSWORD';
// Used for simulating a fake mysql server
common.fakeServerPort = 32893;
// Used for simulating a fake mysql server
common.fakeServerSocket = __dirname + '/fake_server.sock';
common.testDatabase = process.env.MYSQL_DATABASE;
var Mysql = require('../');
common.isTravis = function() {
return Boolean(process.env.CI);
};
common.createConnection = function(config) {
config = mergeTestConfig(config);
return Mysql.createConnection(config);
};
common.createPool = function(config) {
config = mergeTestConfig(config);
config.createConnection = common.createConnection;
return Mysql.createPool(config);
};
common.createFakeServer = function(options) {
return new FakeServer(_.extend({}, options));
};
common.useTestDb = function(connection) {
var query = connection.query('CREATE DATABASE ' + common.testDatabase, function(err) {
if (err && err.code !== 'ER_DB_CREATE_EXISTS') throw err;
});
connection.query('USE ' + common.testDatabase);
}
function mergeTestConfig(config) {
if (common.isTravis()) {
// see: http://about.travis-ci.org/docs/user/database-setup/
config = _.extend({
user: 'root'
}, config);
} else {
config = _.extend({
host : process.env.MYSQL_HOST,
port : process.env.MYSQL_PORT,
user : process.env.MYSQL_USER,
password : process.env.MYSQL_PASSWORD
}, config);
}
return config;
}
+3
View File
@@ -0,0 +1,3 @@
1,Hello World
2,This is a test
3,For loading data from a file
1 1 Hello World
2 2 This is a test
3 3 For loading data from a file
+27
View File
@@ -0,0 +1,27 @@
var common = require('../../common');
var connection = common.createConnection({password: 'INVALID PASSWORD'});
var assert = require('assert');
var endErr;
connection.on('end', function(err) {
assert.equal(endErr, undefined);
endErr = err;
});
var connectErr;
connection.connect(function(err) {
assert.equal(connectErr, undefined);
connectErr = err;
connection.end();
});
process.on('exit', function() {
if (process.env.NO_GRANT == '1' && typeof endErr == 'undefined') return;
assert.equal(endErr.code, 'ER_ACCESS_DENIED_ERROR');
assert.ok(/access denied/i.test(endErr.message));
assert.strictEqual(endErr, connectErr);
});
+37
View File
@@ -0,0 +1,37 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
var _ = require('underscore');
common.useTestDb(connection);
var table = 'insert_test';
connection.query([
'CREATE TEMPORARY TABLE `' + table + '` (',
'`id` int(11) unsigned NOT NULL AUTO_INCREMENT,',
'`title` varchar(255),',
'PRIMARY KEY (`id`)',
') ENGINE=InnoDB DEFAULT CHARSET=utf8'
].join('\n'));
var result;
var items = [];
var itemsFoundInTable = [];
for(var i = 0; i < 100; i++)
items[i] = ['test '+i];
connection.query('INSERT INTO ' + table + ' (title) VALUES ? ', [items], function(err, _result) {
if (err) throw err;
result = _result;
connection.query('SELECT title FROM '+table+';', [], function(err, _items) {
itemsFoundInTable = _.map(_items, function(row) { return [row.title]; });
connection.end();
});
});
process.on('exit', function() {
assert.deepEqual(items, itemsFoundInTable);
});
@@ -0,0 +1,20 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
var err = new Error('uncaught exception');
connection.connect(function() {
throw err;
});
var caughtErr;
process.on('uncaughtException', function(err) {
caughtErr = err;
process.exit(0);
});
process.on('exit', function() {
assert.strictEqual(caughtErr, err);
});
@@ -0,0 +1,24 @@
// This test verifies that changeUser errors are treated as fatal errors. The
// rationale for that is that a failure to execute a changeUser sequence may
// cause unexpected behavior for queries that were enqueued under the
// assumption of changeUser to succeed.
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
if (common.isTravis()) {
return console.log('skipping - travis mysql does not support this test');
}
var err;
connection.changeUser({user: 'does-not-exist'}, function(_err) {
err = _err;
connection.end();
});
process.on('exit', function() {
if (process.env.NO_GRANT == '1' && err === null) return;
assert.equal(err.code, 'ER_ACCESS_DENIED_ERROR');
assert.equal(err.fatal, true);
});
+36
View File
@@ -0,0 +1,36 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
if (common.isTravis()) {
return console.log('skipping - travis mysql does not support this test');
}
connection.query('CREATE DATABASE ' + common.testDatabase, function(err) {
if (err && err.code !== 'ER_DB_CREATE_EXISTS') throw err;
});
var initialDb;
connection.query('select database() as db', function(err, results) {
if (err) throw err;
initialDb = results[0].db;
assert.equal(connection.config.database, null);
});
connection.changeUser({database: common.testDatabase});
var finalDb;
connection.query('select database() as db', function(err, results){
if (err) throw err;
finalDb = results[0].db;
assert.equal(connection.config.database, finalDb);
});
connection.end();
process.on('exit', function() {
assert.equal(initialDb, null);
assert.equal(finalDb, common.testDatabase);
});
@@ -0,0 +1,39 @@
// Based on:
// https://github.com/ichernev/node-mysql/blob/on-duplicate-key-update/test/integration/connection/test-on-duplicate-key-update.js
// (but with CLIENT_FOUND_ROWS connection flag blacklisted)
var common = require('../../common');
var connection = common.createConnection({ flags: "-FOUND_ROWS" });
var assert = require('assert');
common.useTestDb(connection);
var table = 'on_duplicate_key_test';
connection.query('DROP TABLE IF EXISTS `' + table + '`');
connection.query([
'CREATE TABLE `' + table + '` (',
'`a` int(11) unsigned NOT NULL AUTO_INCREMENT,',
'`b` int(11),',
'`c` int(11),',
'PRIMARY KEY (`a`)',
') ENGINE=InnoDB DEFAULT CHARSET=utf8'
].join('\n'));
connection.query('INSERT INTO `' + table + '` SET ?', {a: 1, b: 1, c: 1});
connection.query('INSERT INTO `' + table + '` (a, b, c) VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = 1', function(err, info) {
assert.strictEqual(null, err);
assert.strictEqual(0, info.affectedRows, 'both primary key and updated key are the same so nothing is affected (expected 0, got ' + info.affectedRows + ' affectedRows)');
});
connection.query('INSERT INTO `' + table + '` (a, b, c) VALUES (2, 3, 4) ON DUPLICATE KEY UPDATE c = 1', function(err, info) {
assert.strictEqual(null, err);
assert.strictEqual(1, info.affectedRows, 'primary key differs, so new row is inserted (expected 1, got ' + info.affectedRows + ' affectedRows)');
});
connection.query('INSERT INTO `' + table + '` (a, b, c) VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = 2', function(err, info) {
assert.strictEqual(null, err);
assert.strictEqual(2, info.affectedRows, 'primary key is the same, row is updated (expected 2, got ' + info.affectedRows + ' affectedRows)');
});
connection.end();
@@ -0,0 +1,53 @@
var ConnectionConfig = require('../../../lib/ConnectionConfig');
var ClientConstants = require('../../../lib/protocol/constants/client');
var assert = require('assert');
var testFlags = [{
'default' : [ '' ],
'user' : 'LONG_PASSWORD',
'expected': ClientConstants.CLIENT_LONG_PASSWORD
}, {
'default' : [ '' ],
'user' : '-LONG_PASSWORD',
'expected': 0x0
}, {
'default' : [ 'LONG_PASSWORD', 'FOUND_ROWS' ],
'user' : '-LONG_PASSWORD',
'expected': ClientConstants.CLIENT_FOUND_ROWS
}, {
'default' : [ 'LONG_PASSWORD', 'FOUND_ROWS' ],
'user' : '-FOUND_ROWS',
'expected': ClientConstants.CLIENT_LONG_PASSWORD
}, {
'default' : [ 'LONG_PASSWORD', 'FOUND_ROWS' ],
'user' : '-LONG_FLAG',
'expected': ClientConstants.CLIENT_LONG_PASSWORD |
ClientConstants.CLIENT_FOUND_ROWS
}, {
'default' : [ 'LONG_PASSWORD', 'FOUND_ROWS' ],
'user' : 'LONG_FLAG',
'expected': ClientConstants.CLIENT_LONG_PASSWORD |
ClientConstants.CLIENT_FOUND_ROWS |
ClientConstants.CLIENT_LONG_FLAG
}, {
'default' : [ 'LONG_PASSWORD', 'FOUND_ROWS' ],
'user' : 'UNDEFINED_CONSTANT',
'expected': ClientConstants.CLIENT_LONG_PASSWORD |
ClientConstants.CLIENT_FOUND_ROWS
}, {
'default' : [ 'LONG_PASSWORD', 'FOUND_ROWS' ],
'user' : '-UNDEFINED_CONSTANT',
'expected': ClientConstants.CLIENT_LONG_PASSWORD |
ClientConstants.CLIENT_FOUND_ROWS
}, {
'default' : [ 'LONG_PASSWORD', 'FOUND_ROWS' ],
'user' : '-UNDEFINED_CONSTANT,, -found_ROWS',
'expected': ClientConstants.CLIENT_LONG_PASSWORD
}];
for (var i = 0; i < testFlags.length; i++) {
// console.log("expected: %s got: %s", testFlags[i]['expected'],
// ConnectionConfig.mergeFlags(testFlags[i]['default'], testFlags[i]['user']));
assert.strictEqual(testFlags[i]['expected'],
ConnectionConfig.mergeFlags(testFlags[i]['default'], testFlags[i]['user']));
}
@@ -0,0 +1,9 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
connection.connect(function(err) {
if (err) throw err;
connection.destroy();
});
@@ -0,0 +1,18 @@
var Mysql = require('../../../');
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
connection.config.queryFormat = function (query, values, tz) {
if (!values) return query;
return query.replace(/\:(\w+)/g, function (txt, key) {
if (values.hasOwnProperty(key)) {
return this.escape(values[key]);
}
return txt;
}.bind(this));
};
assert.equal(connection.format("SELECT :a1, :a2", { a1: 1, a2: 'two' }), "SELECT 1, 'two'");
assert.equal(connection.format("SELECT :a1", []), "SELECT :a1");
assert.equal(connection.format("SELECT :a1"), "SELECT :a1");
+46
View File
@@ -0,0 +1,46 @@
var Mysql = require('../../../');
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
common.useTestDb(connection);
var table = 'custom_typecast_test';
connection.query([
'CREATE TEMPORARY TABLE `' + table + '`(',
'`id` int(5),',
'`val` tinyint(1)',
') ENGINE=InnoDB DEFAULT CHARSET=utf8'
].join('\n'));
var results;
connection.query("INSERT INTO " + table + " VALUES (1, 0), (2, 1), (3, NULL)");
connection.query({
sql: "SELECT * FROM " + table,
typeCast: function (field, next) {
if (field.type != 'TINY') {
return next();
}
var val = field.string();
if (val === null) {
return null;
}
return (Number(val) > 0);
}
}, function (err, _results) {
if (err) throw err;
results = _results;
});
connection.end();
process.on('exit', function() {
assert.equal(results.length, 3);
assert.deepEqual(results[0], {id: 1, val: false});
assert.deepEqual(results[1], {id: 2, val: true});
assert.deepEqual(results[2], {id: 3, val: null});
});
@@ -0,0 +1,45 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
common.useTestDb(connection);
var table = 'stream_test';
connection.query([
'CREATE TEMPORARY TABLE `' + table + '` (',
'`id` int(11) unsigned NOT NULL AUTO_INCREMENT,',
'`title` varchar(255),',
'PRIMARY KEY (`id`)',
') ENGINE=InnoDB DEFAULT CHARSET=utf8'
].join('\n'));
var rowCount = 10;
for (var i = 1; i <= rowCount; i++) {
var row = {
id: i,
title: 'Row #' + i,
};
connection.query('INSERT INTO ' + table + ' SET ?', row);
}
var destroyed = false;
var hadEnd = false;
var query = connection.query('SELECT * FROM ' + table);
query
.on('result', function(row) {
assert.equal(destroyed, false);
destroyed = true;
connection.destroy();
})
.on('end', function() {
hadEnd = true;
});
connection.end();
process.on('exit', function() {
assert.strictEqual(hadEnd, false);
});
+24
View File
@@ -0,0 +1,24 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
var didConnect = false;
connection.connect(function(err) {
if (err) throw err;
assert.equal(didConnect, false);
didConnect = true;
});
var err;
connection.connect(function(_err) {
err = _err;
});
connection.end();
process.on('exit', function() {
assert.equal(didConnect, true);
assert.equal(err.fatal, false);
assert.equal(err.code, 'PROTOCOL_ENQUEUE_HANDSHAKE_TWICE');
});
+20
View File
@@ -0,0 +1,20 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
connection.connect();
var got_drain = false;
connection.on('drain', function() {
got_drain = true;
});
connection.query("SELECT 1", function(err) {
assert.equal(got_drain, false);
assert.ok(!err);
process.nextTick(function() {
assert.equal(got_drain, true);
connection.end();
});
});
+27
View File
@@ -0,0 +1,27 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
connection.connect();
var gotEnd = false;
connection.on('end', function(err) {
assert.equal(gotEnd, false);
assert.ok(!err);
gotEnd = true;
});
var gotCallback = false;
connection.end(function(err) {
if (err) throw err;
assert.equal(gotCallback, false);
gotCallback = true;
});
process.on('exit', function() {
assert.equal(gotCallback, true);
assert.equal(gotEnd, true);
});
+7
View File
@@ -0,0 +1,7 @@
var SqlString = require('../../../lib/protocol/SqlString');
var assert = require('assert');
assert.equal('`id`', SqlString.escapeId('id'));
assert.equal('`i``d`', SqlString.escapeId('i`d'));
assert.equal('`id1`.`id2`', SqlString.escapeId('id1.id2'));
assert.equal('`id``1`.`i``d2`', SqlString.escapeId('id`1.i`d2'));
@@ -0,0 +1,66 @@
// This test covers all event / callback interfaces offered by node-mysql and
// throws an exception in them. Exception safety means that each of those
// exceptions can be caught by an 'uncaughtException' / Domain handler without
// the connection instance ending up in a bad state where it doesn't work
// properly or doesn't execute the next sequence anymore.
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
var errors = [];
process.on('uncaughtException', function(err) {
console.log(err.stack);
errors.push(err);
});
// Normal callback
connection.connect(function(err) {
throw err || new Error('1');
});
// Normal callback (same code path as connect, but in here should that
// implementation detail change at some point).
connection.query('SELECT 1', function(err) {
throw err || new Error('2');
});
// Row streaming events
connection.query('SELECT 1')
.on('fields', function() {
throw new Error('3');
})
.on('result', function() {
throw new Error('4');
});
// Normal callback with error
connection.query('INVALID SQL', function(err) {
assert.equal(err.code, 'ER_PARSE_ERROR');
throw new Error('5');
});
// Row streaming 'result' event triggered by Ok Packet (special code path)
connection.query('USE ' + common.testDatabase)
.on('result', function() {
throw new Error('6');
});
// Normal callback (same code path as connect, but in here should that
// implementation detail change at some point).
connection.end(function(err) {
throw err || new Error('7');
});
process.on('exit', function() {
process.removeAllListeners();
var expectedErrors = 7;
for (var i = 0; i < expectedErrors - 1; i++) {
var error = errors[i];
assert.equal(error.message, String(i + 1));
assert.equal(error.code, undefined);
}
});
@@ -0,0 +1,25 @@
var common = require('../../common');
var connection = common.createConnection({password: common.bogusPassword});
var assert = require('assert');
var errors = {};
connection.connect(function(err) {
assert.equal(errors.a, undefined);
errors.a = err;
});
connection.query('SELECT 1', function(err) {
assert.equal(errors.b, undefined);
errors.b = err;
connection.end();
});
process.on('exit', function() {
if (process.env.NO_GRANT == '1' && errors.a === null) return;
assert.equal(errors.a.code, 'ER_ACCESS_DENIED_ERROR');
assert.equal(errors.a.fatal, true);
assert.strictEqual(errors.a, errors.b);
});
@@ -0,0 +1,20 @@
var common = require('../../common');
var connection = common.createConnection({password: common.bogusPassword});
var assert = require('assert');
connection.connect();
connection.query('SELECT 1');
var err;
connection.on('error', function(_err) {
assert.equal(err, undefined);
err = _err;
});
connection.end();
process.on('exit', function() {
if (process.env.NO_GRANT == '1' && typeof err == 'undefined') return;
assert.equal(err.code, 'ER_ACCESS_DENIED_ERROR');
assert.equal(err.fatal, true);
});
@@ -0,0 +1,21 @@
var common = require('../../common');
var connection = common.createConnection({port: common.bogusPort});
var assert = require('assert');
var errors = {};
connection.connect(function(err) {
assert.equal(errors.a, undefined);
errors.a = err;
});
connection.query('SELECT 1', function(err) {
assert.equal(errors.b, undefined);
errors.b = err;
});
process.on('exit', function() {
assert.equal(errors.a.code, 'ECONNREFUSED');
assert.equal(errors.a.fatal, true);
assert.strictEqual(errors.a, errors.b);
});
@@ -0,0 +1,17 @@
var common = require('../../common');
var connection = common.createConnection({port: common.bogusPort});
var assert = require('assert');
connection.connect();
connection.query('SELECT 1');
var err;
connection.on('error', function(_err) {
assert.equal(err, undefined);
err = _err;
});
process.on('exit', function() {
assert.equal(err.code, 'ECONNREFUSED');
assert.equal(err.fatal, true);
});
@@ -0,0 +1,19 @@
var common = require('../../common');
var connection = common.createConnection({port: common.bogusPort});
var assert = require('assert');
connection.connect();
var query = connection.query('SELECT 1');
var err;
query.on('error', function(_err) {
assert.equal(err, undefined);
err = _err;
});
connection.end();
process.on('exit', function() {
assert.equal(err.code, 'ECONNREFUSED');
assert.equal(err.fatal, true);
});
@@ -0,0 +1,26 @@
var common = require('../../common');
var connection = common.createConnection({port: common.fakeServerPort});
var assert = require('assert');
var server = common.createFakeServer();
var connectErr;
server.listen(common.fakeServerPort, function(err) {
if (err) throw err;
connection.connect(function(err) {
connectErr = err;
server.destroy();
});
});
server.on('connection', function(incomingConnection) {
var errno = 1130; // ER_HOST_NOT_PRIVILEGED
incomingConnection.deny('You suck.', errno);
});
process.on('exit', function() {
assert.equal(connectErr.code, 'ER_HOST_NOT_PRIVILEGED');
assert.ok(/You suck/.test(connectErr.message));
assert.equal(connectErr.fatal, true);
});
@@ -0,0 +1,16 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
var rows = undefined;
connection.query('SELECT 1', function(err, _rows) {
if (err) throw err;
rows = _rows;
});
connection.end();
process.on('exit', function() {
assert.deepEqual(rows, [{1: 1}]);
});
+26
View File
@@ -0,0 +1,26 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
common.useTestDb(connection);
var table = 'insert_test';
connection.query([
'CREATE TEMPORARY TABLE `' + table + '` (',
'`id` int(11) unsigned NOT NULL AUTO_INCREMENT,',
'`title` varchar(255),',
'PRIMARY KEY (`id`)',
') ENGINE=InnoDB DEFAULT CHARSET=utf8'
].join('\n'));
var result;
connection.query('INSERT INTO ' + table + ' SET ?', {title: 'test'}, function(err, _result) {
if (err) throw err;
result = _result;
});
connection.end();
process.on('exit', function() {
assert.strictEqual(result.insertId, 1);
});
@@ -0,0 +1,55 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
common.useTestDb(connection);
var table = 'load_data_test';
connection.query([
'CREATE TEMPORARY TABLE `' + table + '` (',
'`id` int(11) unsigned NOT NULL AUTO_INCREMENT,',
'`title` varchar(255),',
'PRIMARY KEY (`id`)',
') ENGINE=InnoDB DEFAULT CHARSET=utf8'
].join('\n'));
var path = common.fixtures + '/data.csv';
var sql =
'LOAD DATA LOCAL INFILE ? INTO TABLE ' + table + ' ' +
'FIELDS TERMINATED BY ? (id, title)';
var ok;
connection.query(sql, [path, ','], function(err, _ok) {
if (err) throw err;
ok = _ok;
});
var rows;
connection.query('SELECT * FROM ' + table, function(err, _rows) {
if (err) throw err;
rows = _rows;
});
// Try to load a file that does not exist to see if we handle this properly
var loadErr;
var loadResult;
var badPath = common.fixtures + '/does_not_exist.csv';
connection.query(sql, [badPath, ','], function(err, result) {
loadErr = err;
loadResult = result;
});
connection.end();
process.on('exit', function() {
assert.equal(ok.affectedRows, 3);
assert.equal(rows.length, 3);
assert.equal(rows[0].id, 1);
assert.equal(rows[0].title, 'Hello World');
assert.equal(loadErr.code, 'ENOENT');
assert.equal(loadResult.affectedRows, 0);
});
@@ -0,0 +1,12 @@
var common = require('../../common');
var connection = common.createConnection({port: common.bogusPort});
var assert = require('assert');
var err;
connection.connect(function(_err) {
err = _err;
});
process.on('exit', function() {
assert.ok(err.stack.indexOf(__filename) > 0);
});
@@ -0,0 +1,16 @@
// Experimental: https://github.com/felixge/node-mysql/issues/198
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
var err;
connection.query('invalid sql', function(_err) {
err = _err;
});
connection.end();
process.on('exit', function() {
assert.ok(err.stack.indexOf(__filename) > 0);
});
@@ -0,0 +1,55 @@
var common = require('../../common');
var connection = common.createConnection({multipleStatements: true});
var assert = require('assert');
var sql = [
'SELECT 1',
'USE ' + common.testDatabase,
'SELECT 2',
'invalid sql',
'SELECT 3',
].join('; ');
var results = [];
var fields = [];
var hadErr = false;
var query = connection.query(sql);
query
.on('error', function(err) {
assert.equal(hadErr, false);
hadErr = true;
assert.equal(err.code, 'ER_PARSE_ERROR');
assert.equal(err.index, 3);
})
.on('fields', function(_fields, index) {
fields.push({fields: _fields, index: index});
})
.on('result', function(result, index) {
results.push({result: result, index: index});
});
connection.end();
process.on('exit', function() {
assert.ok(hadErr);
assert.equal(results.length, 3);
assert.deepEqual(results[0].result, {1: 1});
assert.equal(results[0].index, 0);
assert.equal(results[1].result.constructor.name, 'OkPacket');
assert.equal(results[1].index, 1);
assert.deepEqual(results[2].result, {2: 2});
assert.equal(results[2].index, 2);
assert.equal(fields.length, 2);
assert.equal(fields[0].fields[0].name, '1');
assert.equal(fields[1].fields[0].name, '2');
assert.equal(fields[0].index, 0);
assert.equal(fields[1].index, 2);
});
@@ -0,0 +1,36 @@
var common = require('../../common');
var connection = common.createConnection({multipleStatements: true});
var assert = require('assert');
var sql = [
'SELECT 1',
'invalid sql',
'SELECT 2',
].join('; ');
var finishedQueryOne = false;
connection.query(sql, function(err, results, fields) {
assert.equal(finishedQueryOne, false);
finishedQueryOne = true;
assert.equal(err.code, 'ER_PARSE_ERROR');
assert.deepEqual(results, [[{1: 1}]]);
assert.equal(fields.length, 1);
assert.equal(fields[0][0].name, '1');
});
var finishedQueryTwo = false;
connection.query('SELECT 3', function(err, results) {
assert.equal(finishedQueryTwo, false);
finishedQueryTwo = true;
assert.deepEqual(results, [{3: 3}]);
});
connection.end();
process.on('exit', function() {
assert.equal(finishedQueryOne, true);
assert.equal(finishedQueryTwo, true);
});
@@ -0,0 +1,31 @@
var common = require('../../common');
var connection = common.createConnection({multipleStatements: true});
var assert = require('assert');
var sql = [
'SELECT 1',
'USE ' + common.testDatabase,
'SELECT 2',
].join('; ');
var results;
var fields;
connection.query(sql, function(err, _results, _fields) {
if (err) throw err;
results = _results;
fields = _fields;
});
connection.end();
process.on('exit', function() {
assert.equal(results.length, 3);
assert.deepEqual(results[0], [{1: 1}]);
assert.strictEqual(results[1].constructor.name, 'OkPacket');
assert.deepEqual(results[2], [{2: 2}]);
assert.equal(fields[0][0].name, '1');
assert.equal(fields[1], undefined);
assert.equal(fields[2][0].name, '2');
});
@@ -0,0 +1,48 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
common.useTestDb(connection);
var table = 'nested_test';
connection.query([
'CREATE TEMPORARY TABLE `' + table + '` (',
'`id` int(11) unsigned NOT NULL AUTO_INCREMENT,',
'`title` varchar(255),',
'PRIMARY KEY (`id`)',
') ENGINE=InnoDB DEFAULT CHARSET=utf8'
].join('\n'));
connection.query('INSERT INTO ' + table + ' SET ?', {title: 'test'});
var options1 = {
nestTables: true,
sql: 'SELECT * FROM ' + table
};
var options2 = {
nestTables: '_',
sql: 'SELECT * FROM ' + table
};
var rows1, rows2;
connection.query(options1, function(err, _rows) {
if (err) throw err;
rows1 = _rows;
});
connection.query(options2, function(err, _rows) {
if (err) throw err;
rows2 = _rows;
});
connection.end();
process.on('exit', function() {
assert.equal(rows1.length, 1);
assert.equal(rows1[0].nested_test.id, 1);
assert.equal(rows1[0].nested_test.title, 'test');
assert.equal(rows2.length, 1);
assert.equal(rows2[0].nested_test_id, 1);
assert.equal(rows2[0].nested_test_title, 'test');
});
@@ -0,0 +1,19 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
connection.connect();
connection.query('INVALID SQL');
var err;
connection.on('error', function(_err) {
assert.equal(err, undefined);
err = _err;
});
connection.end();
process.on('exit', function() {
assert.equal(err.code, 'ER_PARSE_ERROR');
assert.equal(Boolean(err.fatal), false);
});
@@ -0,0 +1,19 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
connection.connect();
var query = connection.query('INVALID SQL');
var err;
query.on('error', function(_err) {
assert.equal(err, undefined);
err = _err;
});
connection.end();
process.on('exit', function() {
assert.equal(err.code, 'ER_PARSE_ERROR');
assert.equal(Boolean(err.fatal), false);
});
+35
View File
@@ -0,0 +1,35 @@
var common = require('../../common');
var connection = common.createConnection({
port : common.fakeServerPort,
password : 'oldpw',
insecureAuth : true,
});
var assert = require('assert');
var server = common.createFakeServer();
var connected;
server.listen(common.fakeServerPort, function(err) {
if (err) throw err;
connection.connect(function(err, result) {
if (err) throw err;
connected = result;
connection.destroy();
server.destroy();
});
});
server.on('connection', function(incomingConnection) {
incomingConnection.handshake({
user : connection.config.user,
password : connection.config.password,
oldPassword : true,
});
});
process.on('exit', function() {
assert.equal(connected.fieldCount, 0);
});
+15
View File
@@ -0,0 +1,15 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
var pingErr;
connection.ping(function(err) {
pingErr = err;
});
connection.end();
process.on('exit', function() {
assert.equal(pingErr, null);
});
@@ -0,0 +1,40 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
common.useTestDb(connection);
var procedureName = 'multipleSelectProcedure';
var input0 = 1;
var input1 = 1000;
var fieldName0 = 'param0';
var fieldName1 = 'param1';
var result = undefined;
connection.query([
'CREATE DEFINER=root@localhost PROCEDURE '+procedureName+'(IN '+fieldName0+' INT, IN '+fieldName1+' INT)',
'BEGIN',
'SELECT '+fieldName0+';',
'SELECT '+fieldName1+';',
'END'
].join('\n'));
connection.query('CALL '+procedureName+'(?,?)', [input0,input1], function(err, _result) {
if (err) throw err;
_result.pop(); // drop metadata
result = _result;
});
connection.query('DROP PROCEDURE '+procedureName);
connection.end();
process.on('exit', function() {
var result0Expected = {};
result0Expected[fieldName0] = input0;
var result1Expected = {};
result1Expected[fieldName1] = input1;
assert.deepEqual(result, [[result0Expected], [result1Expected]]);
});
@@ -0,0 +1,33 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
common.useTestDb(connection);
var procedureName = 'singleSelectProcedure';
var input = 1;
var fieldName = 'param';
var result = undefined;
connection.query([
'CREATE DEFINER=root@localhost PROCEDURE '+procedureName+'(IN '+fieldName+' INT)',
'BEGIN',
'SELECT '+fieldName+';',
'END'
].join('\n'));
connection.query('CALL '+procedureName+'(?)', [input], function(err, _result) {
if (err) throw err;
_result.pop(); // drop metadata
result = _result;
});
connection.query('DROP PROCEDURE '+procedureName);
connection.end();
process.on('exit', function() {
var expected = {};
expected[fieldName] = input;
assert.deepEqual(result, [[expected]]);
});
@@ -0,0 +1,17 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
var err;
connection.connect(function() {
connection.destroy();
connection.query('SELECT 1', function(_err) {
err = _err;
});
});
process.on('exit', function() {
assert.equal(err.fatal, false);
assert.equal(err.code, 'PROTOCOL_ENQUEUE_AFTER_DESTROY');
});
@@ -0,0 +1,23 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
var didEnd = false;
connection.connect();
connection.end(function(err) {
if (err) throw err;
didEnd = true;
});
var err;
connection.on('error', function(_err) {
err = _err;
});
connection.query('SELECT 1');
process.on('exit', function() {
assert.equal(didEnd, true);
assert.equal(err.code, 'PROTOCOL_ENQUEUE_AFTER_QUIT');
assert.equal(err.fatal, false);
});
+23
View File
@@ -0,0 +1,23 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
var didEnd = false;
connection.connect();
connection.end(function(err) {
if (err) throw err;
didEnd = true;
});
var err;
connection.query('SELECT 1', function(_err) {
assert.equal(didEnd, false);
err = _err;
});
process.on('exit', function() {
assert.equal(didEnd, true);
assert.equal(err.code, 'PROTOCOL_ENQUEUE_AFTER_QUIT');
assert.equal(err.fatal, false);
});
+36
View File
@@ -0,0 +1,36 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
common.useTestDb(connection);
var table = 'escape_test';
connection.query([
'CREATE TEMPORARY TABLE `' + table + '` (',
'`id` int(11) unsigned NOT NULL AUTO_INCREMENT,',
'`example` varchar(255),',
'PRIMARY KEY (`id`)',
') ENGINE=InnoDB DEFAULT CHARSET=utf8'
].join('\n'));
connection.query('INSERT INTO ' + table + ' SET id = ?, example = ?', [1, 'array escape']);
connection.query('INSERT INTO ' + table + ' SET ?', {
id: 2,
example: 'object escape'
});
var rows;
connection.query('SELECT * FROM escape_test', function(err, _rows) {
if (err) throw err;
rows = _rows;
});
connection.end();
process.on('exit', function() {
assert.equal(rows.length, 2);
assert.deepEqual(rows[0], {id: 1, example: 'array escape'});
assert.deepEqual(rows[1], {id: 2, example: 'object escape'});
});
+21
View File
@@ -0,0 +1,21 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
connection.connect();
var rows = undefined;
var fields = undefined;
connection.query('SELECT 1', function(err, _rows, _fields) {
if (err) throw err;
rows = _rows;
fields = _fields;
});
connection.end();
process.on('exit', function() {
assert.deepEqual(rows, [{1: 1}]);
assert.equal(fields[0].name, '1');
});
@@ -0,0 +1,16 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
var rows;
connection.query('SELECT ""', function(err, _rows) {
if (err) throw err;
rows = _rows;
});
connection.end();
process.on('exit', function() {
assert.deepEqual(rows, [{'': ''}]);
});
@@ -0,0 +1,81 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
connection.connect(function(err) {
if (err) throw err;
getMaxAllowedPacket();
});
var oldMaxAllowedPacket;
function getMaxAllowedPacket() {
connection.query('SHOW VARIABLES WHERE Variable_name = ?', ['max_allowed_packet'], function(err, rows) {
if (err) throw err;
oldMaxAllowedPacket = Number(rows[0].Value);
increaseMaxAllowedPacketIfNeeded();
});
}
function increaseMaxAllowedPacketIfNeeded() {
// Our test generates a SQL query a few bytes larger than 16 MB, but lets
// leave a little margin:
var minMaxAllowedPacket = 20 * 1024 * 1024;
var newMaxAllowedPacket = (oldMaxAllowedPacket < minMaxAllowedPacket)
? minMaxAllowedPacket
: oldMaxAllowedPacket;
connection.query('SET GLOBAL max_allowed_packet = ?', [newMaxAllowedPacket], function(err, rows) {
if (err) throw err;
// We need to re-connect for this change to take effect, bah
connection.end();
connection = common.createConnection();
// We need to wait for the re-connect to happen before starting the actual
// test. That's because our buffer to hex shim in 0.4.x takes ~12 sec on
// TravisCI, causing a MySQL connection timeout otherwise.
connection.connect(function(err) {
if (err) throw err;
triggerLargeQueryAndResponsePackets();
});
});
}
var rows = [];
var length = Math.pow(256, 3) / 2; // Half, because of hex encoding
var buffer = new Buffer(length);
var sql = 'SELECT ? as bigField';
function triggerLargeQueryAndResponsePackets() {
connection.query(sql, [buffer], function(err, _rows) {
if (err) throw err;
rows = _rows;
resetMaxAllowedPacket();
});
}
function resetMaxAllowedPacket() {
connection.query('SET GLOBAL max_allowed_packet = ?', [oldMaxAllowedPacket], function(err, rows) {
if (err) {
err.message = 'Could not reset max_allowed_packet size, please check your server settings: ' + err.message;
throw err;
}
});
connection.end();
}
process.on('exit', function() {
assert.equal(rows.length, 1);
assert.equal(rows[0].bigField.length, length);
});
@@ -0,0 +1,24 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
connection.query('SET wait_timeout = 1');
var errorErr;
var endErr;
connection
.on('end', function(err) {
assert.ok(!endErr);
endErr = err;
})
.on('error', function(err) {
assert.ok(!errorErr);
errorErr = err;
});
process.on('exit', function() {
assert.strictEqual(errorErr.code, 'PROTOCOL_CONNECTION_LOST');
assert.strictEqual(errorErr.fatal, true);
assert.strictEqual(endErr, errorErr);
});
@@ -0,0 +1,36 @@
var common = require('../../common');
var connection = common.createConnection({port: common.fakeServerPort});
var assert = require('assert');
var endErr;
connection.on('end', function(err) {
assert.ok(!endErr);
endErr = err;
});
var queryErr;
var server = common.createFakeServer();
server.listen(common.fakeServerPort, function(err) {
if (err) throw err;
connection.query('SELECT 1', function(err) {
assert.ok(!queryErr);
queryErr = err;
});
});
server.on('connection', function(connection) {
connection.handshake();
connection.on('query', function(packet) {
server.destroy();
});
});
process.on('exit', function() {
assert.strictEqual(queryErr.code, 'PROTOCOL_CONNECTION_LOST');
assert.strictEqual(queryErr.fatal, true);
assert.strictEqual(endErr, queryErr);
});
+26
View File
@@ -0,0 +1,26 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
var statsErr, statsData;
connection.statistics(function(err, data) {
statsErr = err;
statsData = data;
});
connection.end();
process.on('exit', function() {
assert.equal(statsErr, null);
assert.strictEqual(typeof statsData, "object");
assert.strictEqual(statsData.hasOwnProperty("message"), true);
assert.strictEqual(statsData.hasOwnProperty("uptime"), true);
assert.strictEqual(statsData.hasOwnProperty("threads"), true);
assert.strictEqual(statsData.hasOwnProperty("questions"), true);
assert.strictEqual(statsData.hasOwnProperty("slow_queries"), true);
assert.strictEqual(statsData.hasOwnProperty("opens"), true);
assert.strictEqual(statsData.hasOwnProperty("flush_tables"), true);
assert.strictEqual(statsData.hasOwnProperty("open_tables"), true);
assert.strictEqual(statsData.hasOwnProperty("queries_per_second_avg"), true);
});
@@ -0,0 +1,46 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
common.useTestDb(connection);
var table = 'stream_test';
connection.query([
'CREATE TEMPORARY TABLE `' + table + '` (',
'`id` int(11) unsigned NOT NULL AUTO_INCREMENT,',
'`title` varchar(255),',
'PRIMARY KEY (`id`)',
') ENGINE=InnoDB DEFAULT CHARSET=utf8'
].join('\n'));
var rowCount = 10;
for (var i = 1; i <= rowCount; i++) {
var row = {
id: i,
title: 'Row #' + i,
};
connection.query('INSERT INTO ' + table + ' SET ?', row);
}
var query = connection.query('SELECT * FROM ' + table);
var hadEnd = false;
var rows = [];
var fields = undefined;
query.on('result', function(row) {
connection.pause();
connection.resume();
rows.push(row);
})
.on('end', function() {
hadEnd = true;
});
connection.end();
process.on('exit', function() {
assert.equal(rows.length, rowCount);
assert.equal(hadEnd, true);
});
+65
View File
@@ -0,0 +1,65 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
common.useTestDb(connection);
var table = 'stream_test';
connection.query([
'CREATE TEMPORARY TABLE `' + table + '` (',
'`id` int(11) unsigned NOT NULL AUTO_INCREMENT,',
'`title` varchar(255),',
'PRIMARY KEY (`id`)',
') ENGINE=InnoDB DEFAULT CHARSET=utf8'
].join('\n'));
var rowCount = 10;
for (var i = 1; i <= rowCount; i++) {
var row = {
id: i,
title: 'Row #' + i,
};
connection.query('INSERT INTO ' + table + ' SET ?', row);
}
var paused = false;
var query = connection.query('SELECT * FROM ' + table);
var hadEnd = 0;
var rows = [];
var fields = undefined;
query
.on('fields', function(_fields, index) {
assert.equal(index, 0);
assert.ok(!fields);
fields = _fields;
})
.on('result', function(row) {
// Make sure we never receive a row while being paused
assert.equal(paused, false);
paused = true;
connection.pause();
setTimeout(function() {
paused = false;
connection.resume();
rows.push(row);
}, 10);
})
.on('end', function() {
hadEnd = true;
});
connection.end();
process.on('exit', function() {
assert.equal(rows.length, 10);
assert.equal(hadEnd, true);
assert.equal(fields[0].name, 'id');
assert.equal(fields[1].name, 'title');
});
+67
View File
@@ -0,0 +1,67 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
common.useTestDb(connection);
var table = 'timezone_test';
connection.query([
'CREATE TEMPORARY TABLE `' + table + '`(',
'`offset` varchar(10),',
'`dt` datetime',
') ENGINE=InnoDB DEFAULT CHARSET=utf8'
].join('\n'));
var tests = [ 0, 1, 5, 12, 26, -1, -5, -20, 'Z', 'local' ];
connection.query('DELETE FROM ' + table);
testNextDate();
function testNextDate() {
if (tests.length === 0) {
return connection.end();
}
var test = tests.pop();
testDate(test, function () {
testNextDate();
});
}
function testDate(offset, cb) {
var dt = new Date();
if (offset == 'Z' || offset == 'local') {
connection.config.timezone = offset;
} else {
connection.config.timezone = (offset < 0 ? "-" : "+") + pad2(Math.abs(offset)) + ":00";
}
connection.query('INSERT INTO ' + table + ' SET ?', { offset: offset, dt: dt });
if (offset == 'Z') {
dt.setTime(dt.getTime() + (dt.getTimezoneOffset() * 60000));
} else if (offset != 'local') {
dt.setTime(dt.getTime() + (dt.getTimezoneOffset() * 60000) + (offset * 3600000));
}
connection.query({
sql: 'SELECT * FROM ' + table + ' WHERE offset = \'' + offset + '\'',
typeCast: function (field, next) {
if (field.type != 'DATETIME') return next();
return new Date(field.string());
}
}, function (err, result) {
if (err) throw err;
assert.strictEqual(dt.toString(), result[0].dt.toString());
return cb();
});
}
function pad2(v) {
return (v < 10 ? "0" : "") + v;
}
@@ -0,0 +1,41 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
common.useTestDb(connection);
var table = 'transaction_test';
connection.query([
'CREATE TEMPORARY TABLE `' + table + '` (',
'`id` int(11) unsigned NOT NULL AUTO_INCREMENT,',
'`title` varchar(255),',
'PRIMARY KEY (`id`)',
') ENGINE=InnoDB DEFAULT CHARSET=utf8'
].join('\n'));
connection.query('START TRANSACTION');
var rowCount = 10;
for (var i = 1; i <= rowCount; i++) {
var row = {
id: i,
title: 'Row #' + i,
};
connection.query('INSERT INTO ' + table + ' SET ?', row);
}
connection.query('COMMIT');
var rows = [];
var query = connection.query('SELECT * FROM ' + table, function(err, _rows) {
if (err) throw err;
rows = _rows;
});
connection.end();
process.on('exit', function() {
assert.equal(rows.length, rowCount);
});
@@ -0,0 +1,41 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
common.useTestDb(connection);
var table = 'transaction_test';
connection.query([
'CREATE TEMPORARY TABLE `' + table + '` (',
'`id` int(11) unsigned NOT NULL AUTO_INCREMENT,',
'`title` varchar(255),',
'PRIMARY KEY (`id`)',
') ENGINE=InnoDB DEFAULT CHARSET=utf8'
].join('\n'));
connection.query('START TRANSACTION');
var rowCount = 10;
for (var i = 1; i <= rowCount; i++) {
var row = {
id: i,
title: 'Row #' + i,
};
connection.query('INSERT INTO ' + table + ' SET ?', row);
}
connection.query('ROLLBACK');
var rows;
var query = connection.query('SELECT * FROM ' + table, function(err, _rows) {
if (err) throw err;
rows = _rows;
});
connection.end();
process.on('exit', function() {
assert.equal(rows.length, 0);
});
@@ -0,0 +1,34 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
common.useTestDb(connection);
var table = 'insert_test';
connection.query([
'CREATE TEMPORARY TABLE `' + table + '` (',
'`id` int(11) unsigned NOT NULL AUTO_INCREMENT,',
'`date` DATETIME NULL,',
'`number` INT NULL,',
'PRIMARY KEY (`id`)',
') ENGINE=InnoDB DEFAULT CHARSET=utf8'
].join('\n'));
connection.query('INSERT INTO ' + table + ' SET ?', {
date : null,
number : null,
});
var results;
connection.query('SELECT * FROM ' + table, function(err, _results) {
if (err) throw err;
results = _results;
});
connection.end();
process.on('exit', function() {
assert.strictEqual(results[0].date, null);
assert.strictEqual(results[0].number, null);
});
+37
View File
@@ -0,0 +1,37 @@
var common = require('../../common');
var connection = common.createConnection({typeCast: true});
var assert = require('assert');
var util = require('util');
connection.connect();
var options = {
sql : "SELECT NOW() as date, POINT(1.2,-3.4) as point",
typeCast : false
};
var rows;
var query = connection.query(options, function(err, _rows) {
if (err) throw err;
rows = _rows;
});
connection.end();
process.on('exit', function() {
var point = rows[0].point;
var byteOrder = point.readUInt8(4);
var wkbType = byteOrder? point.readUInt32LE(5) : point.readUInt32BE(5);
var x = byteOrder? point.readDoubleLE(9) : point.readDoubleBE(9);
var y = byteOrder? point.readDoubleLE(17) : point.readDoubleBE(17);
assert.strictEqual(typeof rows[0].date, 'object');
assert.equal(Buffer.isBuffer(rows[0].date), true);
assert.strictEqual(typeof point, 'object');
assert.equal(Buffer.isBuffer(point), true);
assert.equal(point.readUInt32LE(0), 0); // unknown
assert.equal(wkbType, 1); // WKBPoint
assert.equal(x, 1.2);
assert.equal(y, -3.4);
});
+118
View File
@@ -0,0 +1,118 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
common.useTestDb(connection);
var tests = [
{type: 'decimal(3,3)', insert: '0.330', expect: 0.33 },
{type: 'decimal(3,3)', insert: 0.33},
{type: 'tinyint', insert: 1},
{type: 'smallint', insert: 2},
{type: 'int', insert: 3},
{type: 'float', insert: 4.5},
{type: 'double', insert: 5.5},
{type: 'bigint', insert: '6', expect: 6},
{type: 'bigint', insert: 6},
{type: 'mediumint', insert: 7},
{type: 'year', insert: 2012},
{type: 'timestamp', insert: new Date('2012-05-12 11:00:23')},
{type: 'datetime', insert: new Date('2012-05-12 12:00:23')},
{type: 'date', insert: new Date('2012-05-12 00:00:00 Z')},
{type: 'time', insert: '13:13:23'},
{type: 'binary(4)', insert: new Buffer([0, 1, 254, 255])},
{type: 'varbinary(4)', insert: new Buffer([0, 1, 254, 255])},
{type: 'tinyblob', insert: new Buffer([0, 1, 254, 255])},
{type: 'mediumblob', insert: new Buffer([0, 1, 254, 255])},
{type: 'longblob', insert: new Buffer([0, 1, 254, 255])},
{type: 'blob', insert: new Buffer([0, 1, 254, 255])},
{type: 'bit(32)', insert: new Buffer([0, 1, 254, 255])},
{type: 'char(5)', insert: 'Hello'},
{type: 'varchar(5)', insert: 'Hello'},
{type: 'varchar(3) character set utf8 collate utf8_bin', insert: 'bin'},
{type: 'tinytext', insert: 'Hello World'},
{type: 'mediumtext', insert: 'Hello World'},
{type: 'longtext', insert: 'Hello World'},
{type: 'text', insert: 'Hello World'},
{type: 'point', insertRaw: 'POINT(1.2,-3.4)', expect: {x:1.2, y:-3.4}, deep: true},
{type: 'point', insertRaw: (function() {
var buffer = new Buffer(21);
buffer.writeUInt8(1, 0);
buffer.writeUInt32LE(1, 1);
buffer.writeDoubleLE(-5.6, 5);
buffer.writeDoubleLE(10.23, 13);
return 'GeomFromWKB(' + connection.escape(buffer) + ')';
})(), expect: {x:-5.6, y:10.23}, deep: true},
{type: 'linestring', insertRaw: 'LINESTRING(POINT(1.2,-3.4),POINT(-5.6,10.23),POINT(0.2,0.7))', expect: [{x:1.2, y:-3.4}, {x:-5.6, y:10.23}, {x:0.2, y:0.7}], deep: true},
{type: 'polygon', insertRaw: "GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7, 5 5))')", expect: [[{x:0,y:0},{x:10,y:0},{x:10,y:10},{x:0,y:10},{x:0,y:0}],[{x:5,y:5},{x:7,y:5},{x:7,y:7},{x:5,y:7},{x:5,y:5}]], deep: true},
{type: 'geometry', insertRaw: 'POINT(1.2,-3.4)', expect: {x:1.2, y:-3.4}, deep: true},
{type: 'multipoint', insertRaw: "GeomFromText('MULTIPOINT(0 0, 20 20, 60 60)')", expect: [{x:0, y:0}, {x:20, y:20}, {x:60, y:60}], deep: true},
{type: 'multilinestring', insertRaw: "GeomFromText('MULTILINESTRING((10 10, 20 20), (15 15, 30 15))')", expect: [[{x:10,y:10},{x:20,y:20}],[{x:15,y:15},{x:30,y:15}]], deep: true},
{type: 'multipolygon', insertRaw: "GeomFromText('MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0)),((5 5,7 5,7 7,5 7, 5 5)))')", expect: [[[{x:0,y:0},{x:10,y:0},{x:10,y:10},{x:0,y:10},{x:0,y:0}]],[[{x:5,y:5},{x:7,y:5},{x:7,y:7},{x:5,y:7},{x:5,y:5}]]], deep: true},
{type: 'geometrycollection', insertRaw: "GeomFromText('GEOMETRYCOLLECTION(POINT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))')", expect: [{x:10,y:10},{x:30,y:30},[{x:15,y:15},{x:20,y:20}]], deep: true}
];
var table = 'type_casting';
var schema = [];
var inserts = [];
tests.forEach(function(test, index) {
var escaped = test.insertRaw || connection.escape(test.insert);
test.columnName = test.type + '_' + index;
schema.push('`' + test.columnName + '` ' + test.type + ',');
inserts.push('`' + test.columnName + '` = ' + escaped);
});
var createTable = [
'CREATE TEMPORARY TABLE `' + table + '` (',
'`id` int(11) unsigned NOT NULL AUTO_INCREMENT,'
].concat(schema).concat([
'PRIMARY KEY (`id`)',
') ENGINE=InnoDB DEFAULT CHARSET=utf8'
]).join('\n');
connection.query(createTable);
connection.query('INSERT INTO ' + table + ' SET' + inserts.join(',\n'));
var row;
connection.query('SELECT * FROM type_casting', function(err, rows) {
if (err) throw err;
row = rows[0];
});
connection.end();
process.on('exit', function() {
tests.forEach(function(test) {
var expected = test.expect || test.insert;
var got = row[test.columnName];
var message;
if (expected instanceof Date) {
assert.equal(got instanceof Date, true, test.type);
expected = String(expected);
got = String(got);
} else if (Buffer.isBuffer(expected)) {
assert.equal(Buffer.isBuffer(got), true, test.type);
expected = String(Array.prototype.slice.call(expected));
got = String(Array.prototype.slice.call(got));
}
if (test.deep) {
message = 'got: "' + JSON.stringify(got) + '" expected: "' + JSON.stringify(expected) +
'" test: ' + test.type + '';
assert.deepEqual(expected, got, message);
} else {
message = 'got: "' + got + '" (' + (typeof got) + ') expected: "' + expected +
'" (' + (typeof expected) + ') test: ' + test.type + '';
assert.strictEqual(expected, got, message);
}
});
});
@@ -0,0 +1,32 @@
var common = require('../../common');
var connection = common.createConnection({socketPath: common.fakeServerSocket});
var assert = require('assert');
var server = common.createFakeServer();
var didConnect = false;
server.listen(common.fakeServerSocket, function(err) {
if (err) throw err;
connection.connect(function(err) {
if (err) throw err;
assert.equal(didConnect, false);
didConnect = true;
connection.destroy();
server.destroy();
});
});
var hadConnection = false;
server.on('connection', function(connection) {
connection.handshake();
assert.equal(hadConnection, false);
hadConnection = true;
});
process.on('exit', function() {
assert.equal(didConnect, true);
assert.equal(hadConnection, true);
});
@@ -0,0 +1,39 @@
var common = require('../../common');
var connection = common.createConnection();
var assert = require('assert');
common.useTestDb(connection);
var table = 'zerofill_results_test';
connection.query([
'CREATE TEMPORARY TABLE `' + table + '` (',
'`id` int(11) unsigned NOT NULL AUTO_INCREMENT,',
'`num` int(5) UNSIGNED ZEROFILL,',
'PRIMARY KEY (`id`)',
') ENGINE=InnoDB DEFAULT CHARSET=utf8'
].join('\n'));
var test_numbers = [ "00000", "00001", "00012", "00123", "01234", "12345", null ];
var results = {};
for (var i = 0; i < test_numbers.length; i++) {
connection.query('INSERT INTO ' + table + ' SET ?', {
id: (i + 1),
num: (test_numbers[i] !== null ? parseInt(test_numbers[i], 10) : null)
}, function (err, _result) {
if (err) throw err;
});
}
connection.query('SELECT * FROM ' + table, function (err, _results) {
if (err) throw err;
results = _results;
});
connection.end();
process.on('exit', function() {
assert.strictEqual(results.length, test_numbers.length);
for (var i = 0; i < results.length; i++) {
assert.strictEqual(test_numbers[results[i].id - 1], (results[i].num !== null ? "" + results[i].num : null));
}
});
+26
View File
@@ -0,0 +1,26 @@
var common = require('../../common');
var assert = require('assert');
var pool = common.createPool({
connectionLimit : 1,
waitForConnections : false
});
pool.getConnection(function(err, connection) {
if (err) throw err;
pool.getConnection(function(err) {
assert.ok(err);
var shouldGetConnection = false;
pool.config.waitForConnections = true;
pool.getConnection(function(err, connection2) {
if (err) throw err;
assert.ok(shouldGetConnection);
assert.strictEqual(connection, connection2);
pool.end();
});
shouldGetConnection = true;
connection.end();
});
});
+17
View File
@@ -0,0 +1,17 @@
var common = require('../../common');
var assert = require('assert');
var Connection = require(common.lib + '/Connection');
var pool = common.createPool();
pool.getConnection(function(err, connection) {
if (err) throw err;
assert.strictEqual(connection, pool._allConnections[0]);
connection.destroy();
assert.ok(pool._allConnections.length == 0);
assert.ok(connection._poolRemoved);
assert.strictEqual(connection.end, Connection.prototype.end);
assert.strictEqual(connection.destroy, Connection.prototype.destroy);
pool.end();
});
+13
View File
@@ -0,0 +1,13 @@
var common = require('../../common');
var assert = require('assert');
var pool = common.createPool();
var poolEnded = false;
pool.end(function(err) {
poolEnded = true;
if (err) throw err;
});
process.on('exit', function() {
assert(poolEnded);
});
+10
View File
@@ -0,0 +1,10 @@
var common = require('../../common');
var assert = require('assert');
var Connection = require(common.lib + '/Connection');
var pool = common.createPool();
pool.getConnection(function(err, connection) {
if (err) throw err;
assert.ok(connection instanceof Connection);
pool.end();
});
+7
View File
@@ -0,0 +1,7 @@
var options = {};
if (process.env.FILTER) {
options.include = new RegExp(process.env.FILTER + '.*\\.js$');
}
require('urun')(__dirname, options);
+125
View File
@@ -0,0 +1,125 @@
var common = require('../../common');
var test = require('utest');
var assert = require('assert');
var Parser = require(common.lib + '/protocol/Parser');
function packet(bytes) {
var buffer = new Buffer(bytes);
var parser = new Parser();
parser.append(buffer);
return parser;
}
test('Parser', {
"parseBuffer: buffer won\'t change after appending another one": function() {
var startBuffer = new Buffer(5);
startBuffer.fill('a');
var parser = new Parser();
parser.append(startBuffer);
var value = parser.parseBuffer(4);
assert.equal(value.toString(), 'aaaa');
parser.append(new Buffer('b'));
assert.equal(value.toString(), 'aaaa');
},
'parseUnsignedNumber: 1 byte': function() {
var value = packet([5]).parseUnsignedNumber(1);
assert.equal(value, 5);
},
'parseUnsignedNumber: 2 bytes': function() {
var value = packet([1, 1]).parseUnsignedNumber(2);
assert.equal(value, 256 + 1);
},
'parseUnsignedNumber: honors offsets': function() {
var parser = packet([1, 2]);
assert.equal(parser.parseUnsignedNumber(1), 1);
assert.equal(parser.parseUnsignedNumber(1), 2);
},
'parseLengthCodedNumber: 1 byte': function() {
var parser = packet([250]);
assert.strictEqual(parser.parseLengthCodedNumber(), 250);
},
'parseLengthCodedNumber: 251 = null': function() {
var parser = packet([251]);
assert.strictEqual(parser.parseLengthCodedNumber(), null);
},
'parseLengthCodedNumber: 252 = 16 bit': function() {
var parser = packet([252, 2, 1]);
var expected =
2 * Math.pow(256, 0) +
1 * Math.pow(256, 1);
assert.strictEqual(parser.parseLengthCodedNumber(), expected);
},
'parseLengthCodedNumber: 253 = 24 bit': function() {
var parser = packet([253, 3, 2, 1]);
var expected =
3 * Math.pow(256, 0) +
2 * Math.pow(256, 1) +
1 * Math.pow(256, 2);
assert.strictEqual(parser.parseLengthCodedNumber(), expected);
},
'parseLengthCodedNumber: 254 = 64 bit': function() {
var parser = packet([254, 8, 7, 6, 5, 4, 3, 2, 0]);
var expected =
8 * Math.pow(256, 0) +
7 * Math.pow(256, 1) +
6 * Math.pow(256, 2) +
5 * Math.pow(256, 3) +
4 * Math.pow(256, 4) +
3 * Math.pow(256, 5) +
2 * Math.pow(256, 6) +
0 * Math.pow(256, 7);
assert.strictEqual(parser.parseLengthCodedNumber(), expected);
},
'parseLengthCodedNumber: < 53 bit = no problemo': function() {
var parser = packet([254, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00]);
assert.strictEqual(parser.parseLengthCodedNumber(), Math.pow(2, 53) - 1);
},
'parseLengthCodedNumber: 53 bit = Error': function() {
var parser = packet([254, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00]);
assert.throws(function() {
parser.parseLengthCodedNumber();
}, /precision/i);
},
'parseLengthCodedNumber: 255 = Error': function() {
var parser = packet([255]);
assert.throws(function() {
parser.parseLengthCodedNumber();
}, /unexpected/i);
},
'parsePacketTerminatedString: regular case': function() {
var parser = packet([0x48, 0x69]);
parser._packetEnd = 2;
var str = parser.parsePacketTerminatedString();
assert.equal(str, 'Hi');
},
'parsePacketTerminatedString: 0x00 terminated': function() {
var parser = packet([0x48, 0x69, 0x00]);
parser._packetEnd = 2;
var str = parser.parsePacketTerminatedString();
assert.equal(str, 'Hi');
},
});
+132
View File
@@ -0,0 +1,132 @@
var common = require('../../common');
var test = require('utest');
var assert = require('assert');
var SqlString = require(common.lib + '/protocol/SqlString');
test('SqlString.escape', {
'undefined -> NULL': function() {
assert.equal(SqlString.escape(undefined), 'NULL');
},
'null -> NULL': function() {
assert.equal(SqlString.escape(null), 'NULL');
},
'booleans convert to strings': function() {
assert.equal(SqlString.escape(false), 'false');
assert.equal(SqlString.escape(true), 'true');
},
'numbers convert to strings': function() {
assert.equal(SqlString.escape(5), '5');
},
'objects are turned into key value pairs': function() {
assert.equal(SqlString.escape({a: 'b', c: 'd'}), "`a` = 'b', `c` = 'd'");
},
'objects function properties are ignored': function() {
assert.equal(SqlString.escape({a: 'b', c: function() {}}), "`a` = 'b'");
},
'nested objects are cast to strings': function() {
assert.equal(SqlString.escape({a: {nested: true}}), "`a` = '[object Object]'");
},
'arrays are turned into lists': function() {
assert.equal(SqlString.escape([1, 2, 'c']), "1, 2, 'c'");
},
'nested arrays are turned into grouped lists': function() {
assert.equal(SqlString.escape([[1,2,3], [4,5,6], ['a', 'b', {nested: true}]]), "(1, 2, 3), (4, 5, 6), ('a', 'b', '[object Object]')");
},
'nested objects inside arrays are cast to strings': function() {
assert.equal(SqlString.escape([1, {nested: true}, 2]), "1, '[object Object]', 2");
},
'strings are quoted': function() {
assert.equal(SqlString.escape('Super'), "'Super'");
},
'\0 gets escaped': function() {
assert.equal(SqlString.escape('Sup\0er'), "'Sup\\0er'");
},
'\b gets escaped': function() {
assert.equal(SqlString.escape('Sup\ber'), "'Sup\\ber'");
},
'\n gets escaped': function() {
assert.equal(SqlString.escape('Sup\ner'), "'Sup\\ner'");
},
'\r gets escaped': function() {
assert.equal(SqlString.escape('Sup\rer'), "'Sup\\rer'");
},
'\t gets escaped': function() {
assert.equal(SqlString.escape('Sup\ter'), "'Sup\\ter'");
},
'\\ gets escaped': function() {
assert.equal(SqlString.escape('Sup\\er'), "'Sup\\\\er'");
},
'\u001a (ascii 26) gets replaced with \\Z': function() {
assert.equal(SqlString.escape('Sup\u001aer'), "'Sup\\Zer'");
},
'single quotes get escaped': function() {
assert.equal(SqlString.escape('Sup\'er'), "'Sup\\'er'");
},
'double quotes get escaped': function() {
assert.equal(SqlString.escape('Sup"er'), "'Sup\\\"er'");
},
'dates are converted to YYYY-MM-DD HH:II:SS': function() {
var expected = '2012-05-07 11:42:03';
var date = new Date(Date.UTC(2012, 4, 7, 11, 42, 3));
var string = SqlString.escape(date);
assert.strictEqual(string, "'" + expected + "'");
},
'buffers are converted to hex': function() {
var buffer = new Buffer([0, 1, 254, 255]);
var string = SqlString.escape(buffer);
assert.strictEqual(string, "X'0001feff'");
},
'NaN -> NaN': function() {
assert.equal(SqlString.escape(NaN), 'NaN');
},
'Infinity -> Infinity': function() {
assert.equal(SqlString.escape(Infinity), 'Infinity');
}
});
test('SqlString.format', {
'question marks are replaced with escaped array values': function() {
var sql = SqlString.format('? and ?', ['a', 'b']);
assert.equal(sql, "'a' and 'b'");
},
'extra question marks are left untouched': function() {
var sql = SqlString.format('? and ?', ['a']);
assert.equal(sql, "'a' and ?");
},
'extra arguments are not used': function() {
var sql = SqlString.format('? and ?', ['a', 'b', 'c']);
assert.equal(sql, "'a' and 'b'");
},
'question marks within values do not cause issues': function() {
var sql = SqlString.format('? and ?', ['hello?', 'b']);
assert.equal(sql, "'hello?' and 'b'");
},
});
+29
View File
@@ -0,0 +1,29 @@
var common = require('../common');
var test = require('utest');
var assert = require('assert');
var Charsets = require(common.lib + '/protocol/constants/charsets');
var ConnectionConfig = require(common.lib + '/ConnectionConfig');
test('ConnectionConfig#Constructor', {
'takes user,pw,host,port,db from url string': function() {
var url = 'mysql://myuser:mypass@myhost:3333/mydb';
var config = new ConnectionConfig(url);
assert.equal(config.host, 'myhost');
assert.equal(config.port, 3333);
assert.equal(config.user, 'myuser');
assert.equal(config.password, 'mypass');
assert.equal(config.database, 'mydb');
},
'allows additional options via url query': function() {
var url = 'mysql://myhost/mydb?debug=true&charset=BIG5_CHINESE_CI';
var config = new ConnectionConfig(url);
assert.equal(config.host, 'myhost');
assert.equal(config.port, 3306);
assert.equal(config.database, 'mydb');
assert.equal(config.debug, true);
assert.equal(config.charsetNumber, Charsets.BIG5_CHINESE_CI);
},
});