mirror of
https://github.com/dolthub/dolt.git
synced 2026-04-22 02:50:04 -05:00
Merge pull request #5332 from dolthub/taylor/node-improvements
[no-release-notes] mysql-client-tests/node: Some test improvements
This commit is contained in:
@@ -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,
|
||||
};
|
||||
}
|
||||
@@ -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
@@ -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"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user