Merge pull request #5525 from dolthub/taylor/workbench-tests

[no-release-notes] mysql-client-tests: More workbench stability tests
This commit is contained in:
Taylor Bantle
2023-03-08 16:41:41 -08:00
committed by GitHub
12 changed files with 382 additions and 41 deletions

View File

@@ -0,0 +1,41 @@
setup_dolt_repo() {
REPO_NAME="dolt_repo_$$"
mkdir $REPO_NAME
cd $REPO_NAME
dolt init
dolt sql -q "CREATE TABLE mysqldump_table(pk int)"
dolt sql -q "INSERT INTO mysqldump_table VALUES (1);"
dolt sql -q "CREATE TABLE warehouse(warehouse_id int primary key, warehouse_name longtext)"
dolt sql -q "INSERT into warehouse VALUES (1, 'UPS'), (2, 'TV'), (3, 'Table');"
PORT=$( definePORT )
USER="dolt"
dolt sql-server --host 0.0.0.0 --port=$PORT --user=$USER --loglevel=trace &
SERVER_PID=$!
# Give the server a chance to start
sleep 1
export MYSQL_PWD=""
}
teardown_dolt_repo() {
kill $SERVER_PID
rm -rf $REPO_NAME
}
definePORT() {
getPORT=""
for i in {0..9}
do
let getPORT="($$ + $i) % (65536-1024) + 1024"
portinuse=$(lsof -i -P -n | grep LISTEN | grep $attemptedPORT | wc -l)
if [ $portinuse -eq 0 ]
then
echo "$getPORT"
break
fi
done
}

View File

@@ -1,3 +1,6 @@
#!/usr/bin/env bats
load $BATS_TEST_DIRNAME/helpers.bash
# MySQL client tests are set up to test Dolt as a MySQL server and
# standard MySQL Clients in a wide array of languages. I used BATS because
# it was easy to set up the Dolt piece using the command line.
@@ -8,31 +11,12 @@
# gotchas, we can add tests for that specific language.
setup() {
REPO_NAME="dolt_repo_$$"
mkdir $REPO_NAME
cd $REPO_NAME
dolt init
dolt sql -q "CREATE TABLE mysqldump_table(pk int)"
dolt sql -q "INSERT INTO mysqldump_table VALUES (1);"
dolt sql -q "CREATE TABLE warehouse(warehouse_id int primary key, warehouse_name longtext)"
dolt sql -q "INSERT into warehouse VALUES (1, 'UPS'), (2, 'TV'), (3, 'Table');"
PORT=$( definePORT )
USER="dolt"
dolt sql-server --host 0.0.0.0 --port=$PORT --user=$USER --loglevel=trace &
SERVER_PID=$!
# Give the server a chance to start
sleep 1
export MYSQL_PWD=""
setup_dolt_repo
}
teardown() {
cd ..
kill $SERVER_PID
rm -rf $REPO_NAME
teardown_dolt_repo
# Check if postgresql is still running. If so stop it
active=$(service postgresql status)
@@ -172,16 +156,4 @@ EOF" -m "postgres"
Rscript $BATS_TEST_DIRNAME/r/rmariadb-test.r $USER $PORT $REPO_NAME
}
definePORT() {
getPORT=""
for i in {0..9}
do
let getPORT="($$ + $i) % (65536-1024) + 1024"
portinuse=$(lsof -i -P -n | grep LISTEN | grep $attemptedPORT | wc -l)
if [ $portinuse -eq 0 ]
then
echo "$getPORT"
break
fi
done
}

View File

@@ -0,0 +1,32 @@
# Node Client Integration Tests
## Install
```
$ npm install
```
## Run node tests
To run the node tests, you must make sure you have Dolt installed on your computer and
have run `npm install`. Then update your Dolt config by running:
```shell
sh ../mysql-client-tests-entrypoint.sh
```
And then you can run the tests using the `run-tests.sh` script, which sets up the database, runs the SQL server, runs the provided `.js` test file against the running server, and then tears down the database.
For example, you can run the `workbench.js` tests by running:
```shell
sh run-tests.sh workbench.js
```
## Workbench stability tests
The tests in `workbenchTests` were written to enforce the stability of the SQL workbench
on [Hosted](https://hosted.doltdb.com/). The workbench uses many Dolt system tables,
functions, and procedures, and any changes to these interfaces can break the workbench.
@tbantle22 will be tagged in any GitHub PR that updates those files to ensure appropriate
workbench updates are made for Dolt changes that break these queries.

View File

@@ -0,0 +1,8 @@
#!/bin/sh
source ../helpers.bash
echo "Running $1 tests"
setup_dolt_repo
cd ..
node $1 $USER $PORT $REPO_NAME
teardown_dolt_repo

View File

@@ -45,7 +45,7 @@ export const branchTests = [
res: [{ hash: "" }],
},
{
q: `SELECT * FROM dolt_branches WHERE name NOT LIKE "workspaces/%" LIMIT 200`,
q: `SELECT * FROM dolt_branches LIMIT 200`,
res: [
{
name: "main",
@@ -66,7 +66,7 @@ export const branchTests = [
res: [{ status: 0 }],
},
{
q: `SELECT COUNT(*) FROM dolt_branches WHERE name NOT LIKE "workspaces/%" LIMIT 200`,
q: `SELECT COUNT(*) FROM dolt_branches LIMIT 200`,
res: [{ ["COUNT(*)"]: 3 }],
},
{
@@ -87,7 +87,7 @@ export const branchTests = [
res: [{ status: 0 }],
},
{
q: `SELECT COUNT(*) FROM dolt_branches WHERE name NOT LIKE "workspaces/%" LIMIT 200`,
q: `SELECT COUNT(*) FROM dolt_branches LIMIT 200`,
res: [{ ["COUNT(*)"]: 2 }],
},
];

View File

@@ -46,4 +46,11 @@ export const databaseTests = [
{ Database: "new_db" },
],
},
{
q: `SELECT dolt_version()`,
res: [{ "dolt_version()": "0.0.0" }],
matcher: (_, exp) => {
return exp[0]["dolt_version()"].length > 0;
},
},
];

View File

@@ -0,0 +1,89 @@
const readmeText = `# README
## My List
- Item 1
- Item 2
`;
export const docsTests = [
{
q: "select * from dolt_docs",
expectedErr: "table not found: dolt_docs",
},
{
q: `CREATE TABLE IF NOT EXISTS \`dolt_docs\` (
\`doc_name\` varchar(16383) NOT NULL,
\`doc_text\` varchar(16383),
PRIMARY KEY (\`doc_name\`)
)`,
res: {
fieldCount: 0,
affectedRows: 0,
insertId: 0,
info: "",
serverStatus: 2,
warningStatus: 0,
},
},
{
q: "select * from dolt_docs",
res: [],
},
{
q: `CREATE TABLE IF NOT EXISTS \`dolt_docs\` (
\`doc_name\` varchar(16383) NOT NULL,
\`doc_text\` varchar(16383),
PRIMARY KEY (\`doc_name\`)
)`,
res: {
fieldCount: 0,
affectedRows: 0,
insertId: 0,
info: "",
serverStatus: 2,
warningStatus: 0,
},
},
{
q: "INSERT INTO dolt_docs VALUES (:docName, :docText) ON DUPLICATE KEY UPDATE doc_text=:docText",
p: {
docName: "README.md",
docText: readmeText,
},
res: {
fieldCount: 0,
affectedRows: 1,
insertId: 0,
info: "",
serverStatus: 2,
warningStatus: 0,
},
},
{
q: `select * from dolt_docs where doc_name=:docName`,
p: { docName: "README.md" },
res: [{ doc_name: "README.md", doc_text: readmeText }],
},
{
q: "DELETE FROM dolt_docs WHERE doc_name=:docName",
p: { docName: "README.md" },
res: {
fieldCount: 0,
affectedRows: 1,
insertId: 0,
info: "",
serverStatus: 2,
warningStatus: 0,
},
},
{
q: `select * from dolt_docs where doc_name=:docName`,
p: { docName: "README.md" },
res: [],
},
{
q: `CALL DOLT_COMMIT("-A", "-m", :commitMsg)`,
p: { commitMsg: "Add dolt_docs table" },
res: [{ hash: "" }],
},
];

View File

@@ -7,6 +7,9 @@ import {
assertQueryResult,
getQueryWithEscapedParameters,
} from "../helpers.js";
import { docsTests } from "./docs.js";
import { tagsTests } from "./tags.js";
import { viewsTests } from "./views.js";
export default async function runWorkbenchTests(database) {
await runTests(database, databaseTests);
@@ -14,12 +17,11 @@ export default async function runWorkbenchTests(database) {
await runTests(database, logTests);
await runTests(database, mergeTests);
await runTests(database, tableTests);
await runTests(database, docsTests);
await runTests(database, tagsTests);
await runTests(database, viewsTests);
// TODO:
// Workspaces
// Diffs
// Docs
// Views
// Tags
}
async function runTests(database, tests) {
@@ -44,6 +46,13 @@ async function runTests(database, tests) {
}
})
.catch((err) => {
if (test.expectedErr) {
if (err.message.includes(test.expectedErr)) {
return;
} else {
console.log("Query error did not match expected:", test.q);
}
}
console.error(err);
process.exit(1);
});

View File

@@ -65,3 +65,30 @@ export function mergeBaseMatcher(rows, exp) {
});
return true;
}
export function tagsMatcher(rows, exp) {
if (rows.length !== exp.length) {
return false;
}
for (let i = 0; i < rows.length; i++) {
if (rows[i].tag_name !== exp[i].tag_name) {
return false;
}
if (rows[i].message !== exp[i].message) {
return false;
}
if (rows[i].email !== exp[i].email) {
return false;
}
if (rows[i].tagger !== exp[i].tagger) {
return false;
}
if (rows[i].tag_hash.length !== 32) {
return false;
}
if (rows[i].date.length === 0) {
return false;
}
}
return true;
}

View File

@@ -140,4 +140,9 @@ export const tableTests = [
},
],
},
{
q: `SELECT * FROM ::tableName ORDER BY ::col0 LIMIT :limit OFFSET :offset`,
p: { tableName: "test_info", col0: "id", limit: 10, offset: 0 },
res: [{ id: 1, info: "info about test pk 0", test_pk: 0 }],
},
];

View File

@@ -0,0 +1,70 @@
import { tagsMatcher } from "./matchers.js";
export const tagsTests = [
{
q: "SELECT * FROM dolt_tags ORDER BY date DESC",
res: [],
},
{
q: `CALL DOLT_TAG(:tagName, :fromRefName)`,
p: { tagName: "mytag", fromRefName: "main" },
res: [{ status: 0 }],
},
{
q: "SELECT * FROM dolt_tags ORDER BY date DESC",
res: [
{
tag_name: "mytag",
message: "",
email: "mysql-test-runner@liquidata.co",
tagger: "mysql-test-runner",
},
],
matcher: tagsMatcher,
},
{
q: `CALL DOLT_TAG("-m", :message, :tagName, :fromRefName)`,
p: { message: "latest release", tagName: "mytagnew", fromRefName: "main" },
res: [{ status: 0 }],
},
{
q: "SELECT * FROM dolt_tags ORDER BY date DESC",
res: [
{
tag_name: "mytagnew",
message: "latest release",
email: "mysql-test-runner@liquidata.co",
tagger: "mysql-test-runner",
},
{
tag_name: "mytag",
message: "",
email: "mysql-test-runner@liquidata.co",
tagger: "mysql-test-runner",
},
],
matcher: tagsMatcher,
},
{
q: `CALL DOLT_TAG("-d", :tagName)`,
p: { tagName: "mytagnew" },
res: [{ status: 0 }],
},
{
q: "SELECT * FROM dolt_tags ORDER BY date DESC",
res: [
{
tag_name: "mytag",
message: "",
email: "mysql-test-runner@liquidata.co",
tagger: "mysql-test-runner",
},
],
matcher: tagsMatcher,
},
{
q: `CALL DOLT_COMMIT("-A", "-m", :commitMsg)`,
p: { commitMsg: "Add a tag" },
expectedErr: "nothing to commit",
},
];

View File

@@ -0,0 +1,81 @@
import { getArgs } from "../helpers.js";
const args = getArgs();
export const viewsTests = [
{
q: "SELECT * FROM ::tableName ::col0 LIMIT :limit OFFSET :offset",
p: { tableName: "dolt_schemas", col0: "id", limit: 10, offset: 0 },
expectedErr: "table not found: dolt_schemas",
},
{
q: "CREATE VIEW ::name AS SELECT * FROM test",
p: { name: "myview" },
res: {
fieldCount: 0,
affectedRows: 0,
insertId: 0,
info: "",
serverStatus: 2,
warningStatus: 0,
},
},
{
q: "SELECT * FROM ::tableName ::col0 LIMIT :limit OFFSET :offset",
p: { tableName: "dolt_schemas", col0: "id", limit: 10, offset: 0 },
res: [
{
type: "view",
name: "myview",
fragment: "CREATE VIEW `myview` AS SELECT * FROM test",
extra: { CreatedAt: 0 },
},
],
},
{
// Excludes views
q: "SHOW FULL TABLES WHERE table_type = 'BASE TABLE'",
res: [
{
[`Tables_in_${args.dbName}/main`]: "test",
Table_type: "BASE TABLE",
},
{
[`Tables_in_${args.dbName}/main`]: "test_info",
Table_type: "BASE TABLE",
},
],
},
{
// Includes views
q: "SHOW FULL TABLES",
res: [
{ [`Tables_in_${args.dbName}/main`]: "myview", Table_type: "VIEW" },
{
[`Tables_in_${args.dbName}/main`]: "test",
Table_type: "BASE TABLE",
},
{
[`Tables_in_${args.dbName}/main`]: "test_info",
Table_type: "BASE TABLE",
},
],
},
{
q: "SHOW CREATE VIEW ::viewName",
p: { viewName: "myview" },
res: [
{
View: "myview",
"Create View": "CREATE VIEW `myview` AS SELECT * FROM test",
character_set_client: "utf8mb4",
collation_connection: "utf8mb4_0900_bin",
},
],
},
{
q: `CALL DOLT_COMMIT("-A", "-m", :commitMsg)`,
p: { commitMsg: "Add view" },
res: [{ hash: "" }],
},
];