From 66df9d120dbb8d6c1c82039fc09039bdb9080ede Mon Sep 17 00:00:00 2001 From: rusher Date: Fri, 4 Dec 2020 12:42:41 +0100 Subject: [PATCH] Adding current GA version to test suite change statistics test (mariadb doesn't have flush_tables) change load data infile disable (MariaDB return a specific error 4166 : ER_LOAD_INFILE_CAPABILITY_DISABLED) ensure load data is enable server side (mysql 8/mariadb 10.5) --- .travis.yml | 4 + test/common.js | 87 +++++++++++++++++++ .../test-load-data-infile-disable.js | 56 +++++++----- .../connection/test-load-data-infile.js | 78 +++++++++-------- ...st-multiple-statements-load-data-infile.js | 79 +++++++++-------- .../integration/connection/test-statistics.js | 4 +- 6 files changed, 212 insertions(+), 96 deletions(-) diff --git a/.travis.yml b/.travis.yml index 377f6da09..e7e8d002c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,6 +41,10 @@ matrix: env: "DOCKER_MYSQL_TYPE=mariadb DOCKER_MYSQL_VERSION=10.2" - node_js: *lts env: "DOCKER_MYSQL_TYPE=mariadb DOCKER_MYSQL_VERSION=10.3" + - node_js: *lts + env: "DOCKER_MYSQL_TYPE=mariadb DOCKER_MYSQL_VERSION=10.4" + - node_js: *lts + env: "DOCKER_MYSQL_TYPE=mariadb DOCKER_MYSQL_VERSION=10.5" dist: trusty addons: diff --git a/test/common.js b/test/common.js index f0eccbe08..13f4d0c25 100644 --- a/test/common.js +++ b/test/common.js @@ -158,3 +158,90 @@ function mergeTestConfig(config) { return config; } + +/** + * Indicate if connection use a MariaDB or MySQL server + * @param {String=} connection current connection + * @returns {boolean} true if MariaDB server + */ +common.isMariaDB = function(connection) { + var serverVersion = ''; + if (connection && connection._protocol && connection._protocol._handshakeInitializationPacket) { + serverVersion = connection._protocol._handshakeInitializationPacket.serverVersion + ''; + } + // MariaDB prefix server string with '5.5.5-' + // Since https://jira.mariadb.org/browse/MDEV-7780 server version can skipped '5.5.5-' prefix + // so adding test containing 'MariaDB' + return (serverVersion.indexOf('5.5.5-') === 0 || serverVersion.indexOf('MariaDB') !== -1); +}; + +/** + * Return true if connection has minimum version + * + * @param {Object=} connection current connection + * @param {Number=} major major server version + * @param {Number=} minor minor server version + * @param {Number=} patch patch server version + * @returns {boolean} true is server version is >= to major.minor.patch version. + */ +common.minVersion = function(connection, major, minor, patch) { + var versionString = ''; + if (connection && connection._protocol && connection._protocol._handshakeInitializationPacket) { + versionString = connection._protocol._handshakeInitializationPacket.serverVersion; + } + if (!versionString) throw new Error('unknown server version'); + if (!major) throw new Error('a major version must be set'); + if (!minor) minor = 0; + if (!patch) patch = 0; + var ver = parseVersionString(versionString); + + return ( + ver.major > major || + (ver.major === major && ver.minor > minor) || + (ver.major === major && ver.minor === minor && ver.patch >= patch) + ); +}; + +/** + * Utility function to return JSON object from versionString. + * Example: + * '5.5.5-10.4.13-MariaDB' => { "major": 10, "minor": 4, "patch": 13 } + * @param {String=} versionString Server verion string + * @returns {{major: number, minor: number, patch: number}} JSON server version + */ +var parseVersionString = function(versionString) { + var ver = versionString.indexOf('5.5.5-') === 0 ? versionString.substring(6) : versionString; + var char; + var offset = 0; + var type = 0; + var val = 0; + + var result = { + major : 0, + minor : 0, + patch : 0 + }; + for (; offset < ver.length; offset++) { + char = ver.charCodeAt(offset); + if (char < 48 || char > 57) { + switch (type) { + case 0: + result.major = val; + break; + case 1: + result.minor = val; + break; + case 2: + result.patch = val; + return result; + } + type++; + val = 0; + } else { + val = val * 10 + char - 48; + } + } + //serverVersion finished by number like "5.5.57", assign patchVersion + if (type === 2) result.patch = val; + return result; +}; diff --git a/test/integration/connection/test-load-data-infile-disable.js b/test/integration/connection/test-load-data-infile-disable.js index 89cdf4aaf..93c452c07 100644 --- a/test/integration/connection/test-load-data-infile-disable.js +++ b/test/integration/connection/test-load-data-infile-disable.js @@ -10,29 +10,39 @@ common.getTestConnection({localInfile: false}, function (err, connection) { common.useTestDb(connection); - connection.query([ - 'CREATE TEMPORARY TABLE ?? (', - '`id` int(11) unsigned NOT NULL AUTO_INCREMENT,', - '`title` varchar(400),', - 'PRIMARY KEY (`id`)', - ') ENGINE=InnoDB DEFAULT CHARSET=utf8' - ].join('\n'), [table], assert.ifError); - - var sql = - 'LOAD DATA LOCAL INFILE ? INTO TABLE ?? CHARACTER SET utf8 ' + - 'FIELDS TERMINATED BY ? ' + - 'LINES TERMINATED BY ? ' + - '(id, title)'; - - connection.query(sql, [path, table, ',', newline], function (err) { - assert.ok(err); - assert.equal(err.code, 'ER_NOT_ALLOWED_COMMAND'); - }); - - connection.query('SELECT * FROM ??', [table], function (err, rows) { + // only test result if server permits local infile + connection.query('SELECT @@local_infile', function (err, rows) { assert.ifError(err); - assert.equal(rows.length, 0); + if (rows[0]['@@local_infile'] === 1) { + connection.query([ + 'CREATE TEMPORARY TABLE ?? (', + '`id` int(11) unsigned NOT NULL AUTO_INCREMENT,', + '`title` varchar(400),', + 'PRIMARY KEY (`id`)', + ') ENGINE=InnoDB DEFAULT CHARSET=utf8' + ].join('\n'), [table], assert.ifError); + + var sql = + 'LOAD DATA LOCAL INFILE ? INTO TABLE ?? CHARACTER SET utf8 ' + + 'FIELDS TERMINATED BY ? ' + + 'LINES TERMINATED BY ? ' + + '(id, title)'; + + connection.query(sql, [path, table, ',', newline], function (err) { + assert.ok(err); + if (common.isMariaDB(connection) && common.minVersion(connection, 10, 5, 0)) { + // mariadb specific error ER_LOAD_INFILE_CAPABILITY_DISABLED + assert.equal(err.errno, 4166); + } else { + assert.equal(err.code, 'ER_NOT_ALLOWED_COMMAND'); + } + }); + + connection.query('SELECT * FROM ??', [table], function (err, rows) { + assert.ifError(err); + assert.equal(rows.length, 0); + }); + } + connection.end(assert.ifError); }); - - connection.end(assert.ifError); }); diff --git a/test/integration/connection/test-load-data-infile.js b/test/integration/connection/test-load-data-infile.js index ef5a72a3f..486445238 100644 --- a/test/integration/connection/test-load-data-infile.js +++ b/test/integration/connection/test-load-data-infile.js @@ -11,42 +11,48 @@ common.getTestConnection(function (err, connection) { common.useTestDb(connection); - connection.query([ - 'CREATE TEMPORARY TABLE ?? (', - '`id` int(11) unsigned NOT NULL AUTO_INCREMENT,', - '`title` varchar(400),', - 'PRIMARY KEY (`id`)', - ') ENGINE=InnoDB DEFAULT CHARSET=utf8' - ].join('\n'), [table], assert.ifError); - - var sql = - 'LOAD DATA LOCAL INFILE ? INTO TABLE ?? CHARACTER SET utf8 ' + - 'FIELDS TERMINATED BY ? ' + - 'LINES TERMINATED BY ? ' + - '(id, title)'; - - connection.query(sql, [path, table, ',', newline], function (err, result) { + // only test result if server permits local infile + connection.query('SELECT @@local_infile', function (err, rows) { assert.ifError(err); - assert.equal(result.affectedRows, 5); + if (rows[0]['@@local_infile'] === 1) { + + connection.query([ + 'CREATE TEMPORARY TABLE ?? (', + '`id` int(11) unsigned NOT NULL AUTO_INCREMENT,', + '`title` varchar(400),', + 'PRIMARY KEY (`id`)', + ') ENGINE=InnoDB DEFAULT CHARSET=utf8' + ].join('\n'), [table], assert.ifError); + + var sql = + 'LOAD DATA LOCAL INFILE ? INTO TABLE ?? CHARACTER SET utf8 ' + + 'FIELDS TERMINATED BY ? ' + + 'LINES TERMINATED BY ? ' + + '(id, title)'; + + connection.query(sql, [path, table, ',', newline], function (err, result) { + assert.ifError(err); + assert.equal(result.affectedRows, 5); + }); + + connection.query('SELECT * FROM ??', [table], function (err, rows) { + assert.ifError(err); + assert.equal(rows.length, 5); + assert.equal(rows[0].id, 1); + assert.equal(rows[0].title, 'Hello World'); + assert.equal(rows[3].id, 4); + assert.equal(rows[3].title, '中文内容'); + assert.equal(rows[4].id, 5); + assert.equal(rows[4].title.length, 321); + assert.equal(rows[4].title, 'this is a long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long string'); + }); + + connection.query(sql, [badPath, table, ',', newline], function (err, result) { + assert.ok(err); + assert.equal(err.code, 'ENOENT'); + assert.equal(result.affectedRows, 0); + }); + } + connection.end(assert.ifError); }); - - connection.query('SELECT * FROM ??', [table], function (err, rows) { - assert.ifError(err); - assert.equal(rows.length, 5); - assert.equal(rows[0].id, 1); - assert.equal(rows[0].title, 'Hello World'); - assert.equal(rows[3].id, 4); - assert.equal(rows[3].title, '中文内容'); - assert.equal(rows[4].id, 5); - assert.equal(rows[4].title.length, 321); - assert.equal(rows[4].title, 'this is a long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long string'); - }); - - connection.query(sql, [badPath, table, ',', newline], function (err, result) { - assert.ok(err); - assert.equal(err.code, 'ENOENT'); - assert.equal(result.affectedRows, 0); - }); - - connection.end(assert.ifError); }); diff --git a/test/integration/connection/test-multiple-statements-load-data-infile.js b/test/integration/connection/test-multiple-statements-load-data-infile.js index cc115863b..8a4e84453 100644 --- a/test/integration/connection/test-multiple-statements-load-data-infile.js +++ b/test/integration/connection/test-multiple-statements-load-data-infile.js @@ -10,42 +10,49 @@ common.getTestConnection({multipleStatements: true}, function (err, connection) common.useTestDb(connection); - connection.query([ - 'CREATE TEMPORARY TABLE ?? (', - '`id` int(11) unsigned NOT NULL AUTO_INCREMENT,', - '`title` varchar(400),', - 'PRIMARY KEY (`id`)', - ') ENGINE=InnoDB DEFAULT CHARSET=utf8' - ].join('\n'), [table], assert.ifError); - - var stmt = - 'LOAD DATA LOCAL INFILE ? INTO TABLE ?? CHARACTER SET utf8 ' + - 'FIELDS TERMINATED BY ? ' + - 'LINES TERMINATED BY ? ' + - '(id, title)'; - - var sql = - connection.format(stmt, [path, table, ',', newline]) + ';' + - connection.format(stmt, [path, table, ',', newline]) + ';'; - - connection.query(sql, function (err, results) { + // only test result if server permits local infile + connection.query('SELECT @@local_infile', function (err, rows) { assert.ifError(err); - assert.equal(results.length, 2); - assert.equal(results[0].affectedRows, 5); - assert.equal(results[1].affectedRows, 0); + if (rows[0]['@@local_infile'] === 1) { + + connection.query([ + 'CREATE TEMPORARY TABLE ?? (', + '`id` int(11) unsigned NOT NULL AUTO_INCREMENT,', + '`title` varchar(400),', + 'PRIMARY KEY (`id`)', + ') ENGINE=InnoDB DEFAULT CHARSET=utf8' + ].join('\n'), [table], assert.ifError); + + var stmt = + 'LOAD DATA LOCAL INFILE ? INTO TABLE ?? CHARACTER SET utf8 ' + + 'FIELDS TERMINATED BY ? ' + + 'LINES TERMINATED BY ? ' + + '(id, title)'; + + var sql = + connection.format(stmt, [path, table, ',', newline]) + ';' + + connection.format(stmt, [path, table, ',', newline]) + ';'; + + connection.query(sql, function (err, results) { + assert.ifError(err); + assert.equal(results.length, 2); + assert.equal(results[0].affectedRows, 5); + assert.equal(results[1].affectedRows, 0); + }); + + connection.query('SELECT * FROM ??', [table], function (err, rows) { + assert.ifError(err); + assert.equal(rows.length, 5); + assert.equal(rows[0].id, 1); + assert.equal(rows[0].title, 'Hello World'); + assert.equal(rows[3].id, 4); + assert.equal(rows[3].title, '中文内容'); + assert.equal(rows[4].id, 5); + assert.equal(rows[4].title.length, 321); + assert.equal(rows[4].title, 'this is a long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long string'); + }); + } + + connection.end(assert.ifError); }); - - connection.query('SELECT * FROM ??', [table], function (err, rows) { - assert.ifError(err); - assert.equal(rows.length, 5); - assert.equal(rows[0].id, 1); - assert.equal(rows[0].title, 'Hello World'); - assert.equal(rows[3].id, 4); - assert.equal(rows[3].title, '中文内容'); - assert.equal(rows[4].id, 5); - assert.equal(rows[4].title.length, 321); - assert.equal(rows[4].title, 'this is a long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long string'); - }); - - connection.end(assert.ifError); }); diff --git a/test/integration/connection/test-statistics.js b/test/integration/connection/test-statistics.js index a31ccb60c..c620eecdb 100644 --- a/test/integration/connection/test-statistics.js +++ b/test/integration/connection/test-statistics.js @@ -13,7 +13,9 @@ common.getTestConnection(function (err, connection) { assert.ok(data.hasOwnProperty('questions')); assert.ok(data.hasOwnProperty('slow_queries')); assert.ok(data.hasOwnProperty('opens')); - assert.ok(data.hasOwnProperty('flush_tables')); + if (!common.isMariaDB(connection)) { + assert.ok(data.hasOwnProperty('flush_tables')); + } assert.ok(data.hasOwnProperty('open_tables')); assert.ok(data.hasOwnProperty('queries_per_second_avg')); connection.end(assert.ifError);