Merge pull request #5332 from dolthub/taylor/node-improvements

[no-release-notes] mysql-client-tests/node: Some test improvements
This commit is contained in:
Taylor Bantle
2023-02-08 14:39:43 -08:00
committed by GitHub
7 changed files with 317 additions and 270 deletions
@@ -1,98 +1,121 @@
const mysql = require('mysql2/promise');
const args = process.argv.slice(2);
const user = args[0];
const port = args[1];
const dbName = args[2];
import mysql from "mysql2/promise";
import { getConfig } from "./helpers";
async function createTable() {
const conn = await getConnection();
try {
await conn.execute("create table users (name varchar(20))");
} catch (err) {
console.error(`Error creating table:`, err);
process.exit(1);
} finally {
conn.end();
}
const conn = await getConnection();
try {
await conn.execute("create table users (name varchar(20))");
} catch (err) {
console.error(`Error creating table:`, err);
process.exit(1);
} finally {
conn.end();
}
}
async function commitTable() {
const conn = await getConnection();
try {
await conn.execute(`call dolt_add('.')`);
await conn.execute(`call dolt_commit('-am', 'new table')`);
} catch (err) {
console.error(`Error committing table:`, err);
} finally {
conn.end();
}
const conn = await getConnection();
try {
await conn.execute(`call dolt_add('.')`);
await conn.execute(`call dolt_commit('-am', 'new table')`);
} catch (err) {
console.error(`Error committing table:`, err);
} finally {
conn.end();
}
}
const authors = [
'bob', 'john', 'mary', 'alice',
'bob2', 'john2', 'mary2', 'alice2',
'bob3', 'john3', 'mary3', 'alice3',
'bob4', 'john4', 'mary4', 'alice4',
'bob5', 'john5', 'mary5', 'alice5',
'bob6', 'john6', 'mary6', 'alice6',
'bob7', 'john7', 'mary7', 'alice7',
'bob8', 'john8', 'mary8', 'alice8',
'bob9', 'john9', 'mary9', 'alice9'
"bob",
"john",
"mary",
"alice",
"bob2",
"john2",
"mary2",
"alice2",
"bob3",
"john3",
"mary3",
"alice3",
"bob4",
"john4",
"mary4",
"alice4",
"bob5",
"john5",
"mary5",
"alice5",
"bob6",
"john6",
"mary6",
"alice6",
"bob7",
"john7",
"mary7",
"alice7",
"bob8",
"john8",
"mary8",
"alice8",
"bob9",
"john9",
"mary9",
"alice9",
];
async function insertAuthor(name) {
const conn = await getConnection();
try {
await conn.execute('start transaction');
await conn.execute('INSERT INTO users (name) VALUES(?);', [name]);
await conn.execute(`call dolt_commit('-am', concat('created author', ?))`, [name]);
} catch (err) {
console.error(`Error committing ${name}:`, err);
process.exit(1)
} finally {
conn.end();
}
const conn = await getConnection();
try {
await conn.execute("start transaction");
await conn.execute("INSERT INTO users (name) VALUES(?);", [name]);
await conn.execute(`call dolt_commit('-am', concat('created author', ?))`, [
name,
]);
} catch (err) {
console.error(`Error committing ${name}:`, err);
process.exit(1);
} finally {
conn.end();
}
}
async function validateCommits(name) {
const conn = await getConnection();
var results;
try {
results = await conn.query(`select count(*) as c from dolt_log where message like 'created author%'`);
} catch (err) {
console.error(`Error:`, err);
process.exit(1)
} finally {
conn.end();
}
const count = results[0][0].c;
const expectedCount = authors.length;
if (count != expectedCount) {
console.error(`Unexpected number of commits: expected ${expectedCount}, was ${count}`);
process.exit(1)
}
const conn = await getConnection();
let results;
try {
results = await conn.query(
`select count(*) as c from dolt_log where message like 'created author%'`
);
} catch (err) {
console.error(`Error:`, err);
process.exit(1);
} finally {
conn.end();
}
const count = results[0][0].c;
const expectedCount = authors.length;
if (count != expectedCount) {
console.error(
`Unexpected number of commits: expected ${expectedCount}, was ${count}`
);
process.exit(1);
}
}
async function getConnection() {
const connection = await mysql.createConnection({
host: '127.0.0.1',
port: port,
user: user,
database: dbName,
});
return connection;
const connection = await mysql.createConnection(getConfig());
return connection;
}
// Regression test concurrent dolt_commit with node clients
// https://github.com/dolthub/dolt/issues/4361
async function main() {
await createTable();
await commitTable();
await Promise.all(authors.map(insertAuthor));
await validateCommits();
await createTable();
await commitTable();
await Promise.all(authors.map(insertAuthor));
await validateCommits();
}
main();
@@ -0,0 +1,26 @@
import mysql from "mysql";
export class Database {
constructor(config) {
this.connection = mysql.createConnection(config);
this.connection.connect();
}
query(sql, args) {
return new Promise((resolve, reject) => {
this.connection.query(sql, args, (err, rows) => {
if (err) return reject(err);
return resolve(rows);
});
});
}
close() {
this.connection.end((err) => {
if (err) {
console.error(err);
} else {
console.log("db connection closed");
}
});
}
}
@@ -0,0 +1,18 @@
const args = process.argv.slice(2);
const user = args[0];
const port = args[1];
const dbName = args[2];
export function getArgs() {
return { user, port, dbName };
}
export function getConfig() {
const { user, port, dbName } = getArgs();
return {
host: "127.0.0.1",
port: port,
user: user,
database: dbName,
};
}
+107 -137
View File
@@ -1,145 +1,115 @@
const mysql = require('mysql');
import { Database } from "./database.js";
import { getConfig } from "./helpers.js";
const args = process.argv.slice(2);
const user = args[0];
const port = args[1];
const db = args[2];
const config = {
host: '127.0.0.1',
user: user,
port: port,
database: db
};
class Database {
constructor( config ) {
this.connection = mysql.createConnection( config );
this.connection.connect();
}
query( sql, args ) {
return new Promise( ( resolve, reject ) => {
this.connection.query( sql, args, ( err, rows ) => {
if ( err )
return reject( err );
return resolve( rows );
} );
} );
}
close() {
this.connection.end(err => {
if (err) {
console.error(err)
} else {
console.log("db connection closed")
}
})
}
}
const tests = [
{
q: "create table test (pk int, `value` int, primary key(pk))",
res: {
fieldCount: 0,
affectedRows: 0,
insertId: 0,
serverStatus: 2,
warningCount: 0,
message: "",
protocol41: true,
changedRows: 0,
},
},
{
q: "describe test",
res: [
{
Field: "pk",
Type: "int",
Null: "NO",
Key: "PRI",
Default: "NULL",
Extra: "",
},
{
Field: "value",
Type: "int",
Null: "YES",
Key: "",
Default: "NULL",
Extra: "",
},
],
},
{ q: "select * from test", res: [] },
{
q: "insert into test (pk, `value`) values (0,0)",
res: {
fieldCount: 0,
affectedRows: 1,
insertId: 0,
serverStatus: 2,
warningCount: 0,
message: "",
protocol41: true,
changedRows: 0,
},
},
{ q: "select * from test", res: [{ pk: 0, value: 0 }] },
{ q: "call dolt_add('-A');", res: [{ status: 0 }] },
{ q: "call dolt_commit('-m', 'my commit')", res: [] },
{ q: "select COUNT(*) FROM dolt_log", res: [{ "COUNT(*)": 2 }] },
{ q: "call dolt_checkout('-b', 'mybranch')", res: [{ status: 0 }] },
{
q: "insert into test (pk, `value`) values (1,1)",
res: {
fieldCount: 0,
affectedRows: 1,
insertId: 0,
serverStatus: 2,
warningCount: 0,
message: "",
protocol41: true,
changedRows: 0,
},
},
{ q: "call dolt_commit('-a', '-m', 'my commit2')", res: [] },
{ q: "call dolt_checkout('main')", res: [{ status: 0 }] },
{
q: "call dolt_merge('mybranch')",
res: [{ fast_forward: 1, conflicts: 0 }],
},
{ q: "select COUNT(*) FROM dolt_log", res: [{ "COUNT(*)": 3 }] },
];
async function main() {
const queries = [
"create table test (pk int, `value` int, primary key(pk))",
"describe test",
"select * from test",
"insert into test (pk, `value`) values (0,0)",
"select * from test",
"call dolt_add('-A');",
"call dolt_commit('-m', 'my commit')",
"select COUNT(*) FROM dolt_log",
"call dolt_checkout('-b', 'mybranch')",
"insert into test (pk, `value`) values (1,1)",
"call dolt_commit('-a', '-m', 'my commit2')",
"call dolt_checkout('main')",
"call dolt_merge('mybranch')",
"select COUNT(*) FROM dolt_log",
];
const database = new Database(getConfig());
const results = [
{
fieldCount: 0,
affectedRows: 0,
insertId: 0,
serverStatus: 2,
warningCount: 0,
message: '',
protocol41: true,
changedRows: 0
},
[ { Field: 'pk',
Type: 'int',
Null: 'NO',
Key: 'PRI',
Default: 'NULL',
Extra: '' },
{ Field: 'value',
Type: 'int',
Null: 'YES',
Key: '',
Default: 'NULL',
Extra: '' }
],
[],
{
fieldCount: 0,
affectedRows: 1,
insertId: 0,
serverStatus: 2,
warningCount: 0,
message: '',
protocol41: true,
changedRows: 0
},
[ { pk: 0, value: 0 } ],
[ { status: 0 } ],
[],
[ { "COUNT(*)": 2 } ],
[ { status: 0 } ],
{
fieldCount: 0,
affectedRows: 1,
insertId: 0,
serverStatus: 2,
warningCount: 0,
message: '',
protocol41: true,
changedRows: 0
},
[],
[ { status: 0 } ],
[ { fast_forward: 1, conflicts: 0 } ],
[ { "COUNT(*)": 3 } ],
];
await Promise.all(
tests.map((test) => {
const expected = test.res;
return database
.query(test.q)
.then((rows) => {
const resultStr = JSON.stringify(rows);
const result = JSON.parse(resultStr);
if (
resultStr !== JSON.stringify(expected) &&
test.q.includes("dolt_commit") &&
!(rows.length === 1 && rows[0].hash.length > 0)
) {
console.log("Query:", test.q);
console.log("Results:", result);
console.log("Expected:", expected);
throw new Error("Query failed");
} else {
console.log("Query succeeded:", test.q);
}
})
.catch((err) => {
console.error(err);
process.exit(1);
});
})
);
const database = new Database(config);
await Promise.all(queries.map((query, idx) => {
const expected = results[idx];
return database.query(query).then(rows => {
const resultStr = JSON.stringify(rows);
const result = JSON.parse(resultStr);
if (resultStr !== JSON.stringify(expected) && !(query.includes("dolt_commit"))) {
console.log("Query:", query);
console.log("Results:", result);
console.log("Expected:", expected);
throw new Error("Query failed")
} else {
console.log("Query succeeded:", query)
}
}).catch(err => {
console.error(err)
process.exit(1);
});
}));
database.close()
process.exit(0)
database.close();
process.exit(0);
}
main();
@@ -1,84 +1,79 @@
const knex = require("knex");
const wtfnode = require("wtfnode")
Socket = require('net').Socket;
const args = process.argv.slice(2);
const user = args[0];
const port = args[1];
const dbName = args[2];
import knex from "knex";
import wtfnode from "wtfnode";
import { Socket } from "net";
import { getConfig } from "./helpers.js";
const db = knex({
client: "mysql2",
connection: {
host: "127.0.0.1",
port: port,
user: user,
database: dbName,
},
client: "mysql2",
connection: getConfig(),
});
async function createTable() {
let val = await db.schema.createTable('test2', (table) => {
table.integer('id').primary()
table.integer('foo')
});
return val
const val = await db.schema.createTable("test2", (table) => {
table.integer("id").primary();
table.integer("foo");
});
return val;
}
async function upsert(table, data) {
let val = await db(table).insert(data).onConflict().merge();
return val
const val = await db(table).insert(data).onConflict().merge();
return val;
}
async function select() {
let val = await db.select('id', 'foo').from('test2');
return val
const val = await db.select("id", "foo").from("test2");
return val;
}
async function main() {
await createTable();
await Promise.all([
upsert("test2", { id: 1, foo: 1 }),
upsert("test2", { id: 2, foo: 2 }),
])
await createTable();
await Promise.all([
upsert("test2", { id: 1, foo: 1 }),
upsert("test2", { id: 2, foo: 2 }),
]);
let expectedResult = JSON.stringify([ { id: 1, foo: 1 }, { id: 2, foo: 2 } ])
let result = await select();
if (JSON.stringify(result) !== expectedResult) {
console.log("Results:", result);
console.log("Expected:", expectedResult);
process.exit(1)
throw new Error("Query failed")
const expectedResult = JSON.stringify([
{ id: 1, foo: 1 },
{ id: 2, foo: 2 },
]);
const result = await select();
if (JSON.stringify(result) !== expectedResult) {
console.log("Results:", result);
console.log("Expected:", expectedResult);
process.exit(1);
}
await db.destroy();
// cc: https://github.com/dolthub/dolt/issues/3752
setTimeout(async () => {
const sockets = await getOpenSockets();
if (sockets.length > 0) {
wtfnode.dump();
process.exit(1);
}
await db.destroy();
// cc: https://github.com/dolthub/dolt/issues/3752
setTimeout(async () => {
let sockets = await getOpenSockets();
if (sockets.length > 0) {
wtfnode.dump();
process.exit(1);
throw new Error("Database not properly destroyed. Hanging server connections");
}
}, 3000);
}, 3000);
}
// cc: https://github.com/myndzi/wtfnode/blob/master/index.js#L457
async function getOpenSockets() {
let sockets = []
process._getActiveHandles().forEach(function (h) {
// handles can be null now? early exit to guard against this
if (!h) { return; }
const sockets = [];
process._getActiveHandles().forEach(function (h) {
// handles can be null now? early exit to guard against this
if (!h) {
return;
}
if (h instanceof Socket) {
if ((h.fd == null) && (h.localAddress) && !(h.destroyed)) { sockets.push(h); }
}
});
if (h instanceof Socket) {
if (h.fd == null && h.localAddress && !h.destroyed) {
sockets.push(h);
}
}
});
return sockets
return sockets;
}
main();
+15 -1
View File
@@ -11,7 +11,8 @@
"dependencies": {
"knex": "^1.0.7",
"mysql": "^2.18.1",
"mysql2": "^2.3.3"
"mysql2": "^2.3.3",
"wtfnode": "^0.9.1"
}
},
"node_modules/bignumber.js": {
@@ -435,6 +436,14 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"node_modules/wtfnode": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/wtfnode/-/wtfnode-0.9.1.tgz",
"integrity": "sha512-Ip6C2KeQPl/F3aP1EfOnPoQk14Udd9lffpoqWDNH3Xt78svxPbv53ngtmtfI0q2Te3oTq79XKTnRNXVIn/GsPA==",
"bin": {
"wtfnode": "proxy.js"
}
},
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
@@ -758,6 +767,11 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"wtfnode": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/wtfnode/-/wtfnode-0.9.1.tgz",
"integrity": "sha512-Ip6C2KeQPl/F3aP1EfOnPoQk14Udd9lffpoqWDNH3Xt78svxPbv53ngtmtfI0q2Te3oTq79XKTnRNXVIn/GsPA=="
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
@@ -3,6 +3,7 @@
"version": "1.0.0",
"description": "A simple node command line utility to show how to connect a node application to a Dolt database using the MySQL connector.",
"main": "index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},