#!/usr/bin/env bats load $BATS_TEST_DIRNAME/helper/common.bash load $BATS_TEST_DIRNAME/helper/query-server-common.bash make_repo() { mkdir "$1" cd "$1" dolt init cd .. } setup() { skiponwindows "tests are flaky on Windows" setup_no_dolt_init mkdir $BATS_TMPDIR/sql-server-test$$ nativevar DOLT_ROOT_PATH $BATS_TMPDIR/sql-server-test$$ /p dolt config --global --add user.email "test@test.com" dolt config --global --add user.name "test" make_repo repo1 make_repo repo2 } teardown() { stop_sql_server teardown_common } @test "sql-server: Database specific system variables should be loaded" { cd repo1 dolt branch dev dolt branch other start_sql_server server_query repo1 1 "SET PERSIST repo1_default_branch = 'dev';" "" stop_sql_server start_sql_server server_query repo1 1 "SELECT @@repo1_default_branch;" "@@SESSION.repo1_default_branch\ndev" stop_sql_server # system variable is lost when starting sql-server outside of the folder # because global config is used. cd .. start_sql_server server_query repo1 1 "SELECT LENGTH(@@repo1_default_branch);" "LENGTH(@@repo1_default_branch)\n0" server_query repo1 1 "SET PERSIST repo1_default_branch = 'other';" "" stop_sql_server start_sql_server server_query repo1 1 "SELECT @@repo1_default_branch;" "@@SESSION.repo1_default_branch\nother" stop_sql_server # ensure we didn't blow away local setting cd repo1 start_sql_server_with_args --user dolt --doltcfg-dir './' server_query repo1 1 "SELECT @@repo1_default_branch;" "@@SESSION.repo1_default_branch\ndev" } @test "sql-server: user session variables from config" { cd repo1 echo " privilege_file: privs.json user_session_vars: - name: user0 vars: aws_credentials_file: /Users/user0/.aws/config aws_credentials_profile: default - name: user1 vars: aws_credentials_file: /Users/user1/.aws/config aws_credentials_profile: lddev" > server.yaml dolt sql --privilege-file=privs.json -q "CREATE USER dolt@'127.0.0.1'" dolt sql --privilege-file=privs.json -q "CREATE USER user0@'127.0.0.1' IDENTIFIED BY 'pass0'" dolt sql --privilege-file=privs.json -q "CREATE USER user1@'127.0.0.1' IDENTIFIED BY 'pass1'" dolt sql --privilege-file=privs.json -q "CREATE USER user2@'127.0.0.1' IDENTIFIED BY 'pass2'" start_sql_server_with_config "" server.yaml run dolt sql-client --host=127.0.0.1 --port=$PORT --user=user0 --password=pass0< server.yaml start_sql_server_with_config repo1 server.yaml # No tables at the start run dolt ls [ "$status" -eq 0 ] [[ "$output" =~ "No tables in working set" ]] || false # attempt to create table (autocommit on), expect either some exception server_query repo1 1 "CREATE TABLE i_should_not_exist ( c0 INT )" "" "database server is set to read only mode" # Expect that there are still no tables run dolt ls [ "$status" -eq 0 ] [[ "$output" =~ "No tables in working set" ]] || false } @test "sql-server: read-only flag still allows select" { skiponwindows "Missing dependencies" cd repo1 dolt sql -q "create table t(c0 int)" dolt sql -q "insert into t values (1)" DEFAULT_DB="$1" let PORT="$$ % (65536-1024) + 1024" echo " read_only: true" > server.yaml start_sql_server_with_config repo1 server.yaml # make a select query server_query repo1 1 "select * from t" "c0\n1" } @test "sql-server: read-only flag prevents dolt_commit" { skiponwindows "Missing dependencies" cd repo1 DEFAULT_DB="$1" let PORT="$$ % (65536-1024) + 1024" echo " read_only: true" > server.yaml start_sql_server_with_config repo1 server.yaml # make a dolt_commit query skip "read-only flag does not prevent dolt_commit" server_query repo1 1 "select dolt_commit('--allow-empty', '-m', 'msg')" "" "database server is set to read only mode: user does not have permission: write" } @test "sql-server: test command line modification" { skiponwindows "Missing dependencies" cd repo1 start_sql_server repo1 # No tables at the start run dolt ls [ "$status" -eq 0 ] [[ "$output" =~ "No tables in working set" ]] || false server_query repo1 1 "CREATE TABLE one_pk ( pk BIGINT NOT NULL, c1 BIGINT, c2 BIGINT, PRIMARY KEY (pk) )" "" run dolt ls [ "$status" -eq 0 ] [[ "$output" =~ "one_pk" ]] || false # Add rows on the command line run dolt sql -q "insert into one_pk values (1,1,1)" [ "$status" -eq 1 ] server_query repo1 1 "SELECT * FROM one_pk ORDER by pk" "" # Test import as well (used by doltpy) echo 'pk,c1,c2' > import.csv echo '2,2,2' >> import.csv run dolt table import -u one_pk import.csv [ "$status" -eq 1 ] server_query repo1 1 "SELECT * FROM one_pk ORDER by pk" "" } @test "sql-server: test dolt sql interface works properly with autocommit" { skiponwindows "Missing dependencies" cd repo1 start_sql_server repo1 # No tables at the start run dolt ls [ "$status" -eq 0 ] [[ "$output" =~ "No tables in working set" ]] || false # create table with autocommit off and verify there are still no tables server_query repo1 0 "CREATE TABLE one_pk ( pk BIGINT NOT NULL COMMENT 'tag:0', c1 BIGINT COMMENT 'tag:1', c2 BIGINT COMMENT 'tag:2', PRIMARY KEY (pk) )" "" run dolt ls [ "$status" -eq 0 ] [[ "$output" =~ "No tables in working set" ]] || false # check that dolt_commit throws an error when there are no changes to commit run server_query repo1 0 "SELECT DOLT_COMMIT('-a', '-m', 'Commit1')" [ "$status" -eq 1 ] run dolt ls [ "$status" -eq 0 ] [[ "$output" =~ "No tables in working set" ]] || false # create table with autocommit on and verify table creation server_query repo1 1 "CREATE TABLE one_pk ( pk BIGINT NOT NULL COMMENT 'tag:0', c1 BIGINT COMMENT 'tag:1', c2 BIGINT COMMENT 'tag:2', PRIMARY KEY (pk) )" "" run dolt ls [ "$status" -eq 0 ] [[ "$output" =~ "one_pk" ]] || false # check that dolt_commit works properly when autocommit is on run dolt sql -q "SELECT DOLT_COMMIT('-a', '-m', 'Commit1')" [ "$status" -eq 0 ] # check that dolt_commit throws error now that there are no working set changes. run dolt sql -q "SELECT DOLT_COMMIT('-a', '-m', 'Commit1')" [ "$status" -eq 1 ] # Make a change to the working set but not the staged set. run dolt sql -q "INSERT INTO one_pk (pk,c1,c2) VALUES (2,2,2),(3,3,3)" # check that dolt_commit throws error now that there are no staged changes. run dolt sql -q "SELECT DOLT_COMMIT('-m', 'Commit1')" [ "$status" -eq 1 ] run dolt log [ $status -eq 0 ] [[ "$output" =~ "Commit1" ]] || false } @test "sql-server: test basic querying via dolt sql-server" { skiponwindows "Missing dependencies" cd repo1 start_sql_server repo1 server_query repo1 1 "SHOW tables" "" server_query repo1 1 "CREATE TABLE one_pk ( pk BIGINT NOT NULL COMMENT 'tag:0', c1 BIGINT COMMENT 'tag:1', c2 BIGINT COMMENT 'tag:2', PRIMARY KEY (pk) )" "" server_query repo1 1 "SHOW tables" "Tables_in_repo1\none_pk" insert_query repo1 1 "INSERT INTO one_pk (pk) VALUES (0)" server_query repo1 1 "SELECT * FROM one_pk ORDER BY pk" "pk,c1,c2\n0,None,None" insert_query repo1 1 "INSERT INTO one_pk (pk,c1) VALUES (1,1)" insert_query repo1 1 "INSERT INTO one_pk (pk,c1,c2) VALUES (2,2,2),(3,3,3)" server_query repo1 1 "SELECT * FROM one_pk ORDER by pk" "pk,c1,c2\n0,None,None\n1,1,None\n2,2,2\n3,3,3" update_query repo1 1 "UPDATE one_pk SET c2=c1 WHERE c2 is NULL and c1 IS NOT NULL" } @test "sql-server: test multiple queries on the same connection" { skiponwindows "Missing dependencies" cd repo1 start_sql_server repo1 multi_query repo1 1 "CREATE TABLE one_pk ( pk BIGINT NOT NULL COMMENT 'tag:0', c1 BIGINT COMMENT 'tag:1', c2 BIGINT COMMENT 'tag:2', PRIMARY KEY (pk) ); INSERT INTO one_pk (pk) VALUES (0); INSERT INTO one_pk (pk,c1) VALUES (1,1); INSERT INTO one_pk (pk,c1,c2) VALUES (2,2,2),(3,3,3);" server_query repo1 1 "SELECT * FROM one_pk ORDER by pk" "pk,c1,c2\n0,None,None\n1,1,None\n2,2,2\n3,3,3" } @test "sql-server: test reset_hard" { skiponwindows "Missing dependencies" cd repo1 dolt sql <'); INSERT INTO dolt_branches (name,hash) VALUES ('main', @@repo1_head);" server_query repo1 1 "call dolt_add('.')" "status\n0" run dolt ls [ "$status" -eq 0 ] [[ "$output" =~ "one_pk" ]] || false run dolt sql -q "drop table one_pk" [ "$status" -eq 1 ] server_query repo1 1 "drop table one_pk" "" multi_query repo1 1 "call dolt_commit('-am', 'Dropped table one_pk')" run dolt ls [ "$status" -eq 0 ] ! [[ "$output" =~ "one_pk" ]] || false } # TODO: Need to update testing logic allow queries for a multiple session. @test "sql-server: Create a temporary table and validate that it doesn't persist after a session closes" { skiponwindows "Missing dependencies" cd repo1 start_sql_server repo1 # check no tables on main server_query repo1 1 "SHOW Tables" "" # Create a temporary table with some indexes server_query repo1 1 "CREATE TEMPORARY TABLE one_pk ( pk int, c1 int, c2 int, PRIMARY KEY (pk), INDEX idx_v1 (c1, c2) COMMENT 'hello there' )" "" server_query repo1 1 "SHOW tables" "" # validate that it does have show tables } @test "sql-server: connect to another branch with connection string" { skiponwindows "Missing dependencies" cd repo1 dolt checkout -b "feature-branch" dolt checkout main start_sql_server repo1 server_query "repo1/feature-branch" 1 "CREATE TABLE test ( pk int, c1 int, PRIMARY KEY (pk) )" "" server_query repo1 1 "SHOW tables" "" # no tables on main server_query "repo1/feature-branch" 1 "SHOW Tables" "Tables_in_repo1/feature-branch\ntest" } @test "sql-server: connect to a commit with connection string" { skiponwindows "Missing dependencies" cd repo1 dolt sql -q "create table test (pk int primary key)" dolt commit -a -m "Created new table" dolt sql -q "insert into test values (1), (2), (3)" dolt commit -a -m "Inserted 3 values" dolt sql -q "insert into test values (4), (5), (6)" dolt commit -a -m "Inserted 3 more values" start_sql_server repo1 # get the second-to-last commit hash hash=`dolt log | grep commit | cut -d" " -f2 | tail -n+2 | head -n1` server_query "repo1/$hash" 1 "select count(*) from test" "count(*)\n3" # fails server_query "repo1/$hash" 1 "insert into test values (7)" "" "read-only" # server should still be alive after an error server_query "repo1/$hash" 1 "select count(*) from test" "count(*)\n3" } @test "sql-server: select a branch with the USE syntax" { skiponwindows "Missing dependencies" cd repo1 dolt checkout -b "feature-branch" dolt checkout main start_sql_server repo1 multi_query repo1 1 ' USE `repo1/feature-branch`; CREATE TABLE test ( pk int, c1 int, PRIMARY KEY (pk) )' "" server_query repo1 1 "SHOW tables" "" # no tables on main server_query "repo1/feature-branch" 1 "SHOW Tables" "Tables_in_repo1/feature-branch\ntest" } @test "sql-server: SET GLOBAL default branch as ref" { skiponwindows "Missing dependencies" cd repo1 dolt checkout -b "new" dolt checkout main start_sql_server repo1 multi_query repo1 1 ' select dolt_checkout("new"); CREATE TABLE t (a int primary key, b int); INSERT INTO t VALUES (2,2),(3,3);' "" server_query repo1 1 "SHOW tables" "" # no tables on main server_query repo1 1 "set GLOBAL repo1_default_branch = 'refs/heads/new';" "" server_query repo1 1 "select @@GLOBAL.repo1_default_branch;" "@@GLOBAL.repo1_default_branch\nrefs/heads/new" server_query repo1 1 "select active_branch()" "active_branch()\nnew" server_query repo1 1 "SHOW tables" "Tables_in_repo1\nt" } @test "sql-server: SET GLOBAL default branch as branch name" { skiponwindows "Missing dependencies" cd repo1 dolt checkout -b "new" dolt checkout main start_sql_server repo1 multi_query repo1 1 ' select dolt_checkout("new"); CREATE TABLE t (a int primary key, b int); INSERT INTO t VALUES (2,2),(3,3);' "" server_query repo1 1 "SHOW tables" "" # no tables on main server_query repo1 1 "set GLOBAL repo1_default_branch = 'new';" "" server_query repo1 1 "select @@GLOBAL.repo1_default_branch;" "@@GLOBAL.repo1_default_branch\nnew" server_query repo1 1 "select active_branch()" "active_branch()\nnew" server_query repo1 1 "SHOW tables" "Tables_in_repo1\nt" } @test "sql-server: require_secure_transport no key or cert" { skiponwindows "Missing dependencies" cd repo1 let PORT="$$ % (65536-1024) + 1024" cat >config.yml <config.yml <config.yml <config.yml <config.yml <config.yml < server.yaml start_sql_server_with_config repo1 server.yaml server_query repo1 1 "select dolt_fetch() as f" "f\n1" } @test "sql-server: run mysql from shell" { skiponwindows "Has dependencies that are not installed on Windows CI" if [[ `uname` == 'Darwin' ]]; then skip "Unsupported in MacOS CI" fi cd repo1 dolt sql -q "create table r1t_one (id1 int primary key, col1 varchar(20));" dolt sql -q "insert into r1t_one values (1,'aaaa'), (2,'bbbb'), (3,'cccc');" dolt sql -q "create table r1t_two (id2 int primary key, col2 varchar(20));" dolt commit -am "create two tables" cd ../repo2 dolt sql -q "create table r2t_one (id1 int primary key, col1 varchar(20));" dolt sql -q "create table r2t_two (id2 int primary key, col2 varchar(20));" dolt sql -q "create table r2t_three (id3 int primary key, col3 varchar(20));" dolt sql -q "insert into r2t_three values (4,'dddd'), (3,'gggg'), (2,'eeee'), (1,'ffff');" dolt commit -am "create three tables" cd .. start_sql_server_with_args --user dolt -ltrace --no-auto-commit run expect $BATS_TEST_DIRNAME/sql-server-mysql.expect $PORT repo1 [ "$status" -eq 0 ] } @test "sql-server: sql-server lock cleanup" { cd repo1 start_sql_server stop_sql_server start_sql_server stop_sql_server } @test "sql-server: sql-server locks database" { cd repo1 start_sql_server let PORT="$$ % (65536-1024) + 1024" run dolt sql-server -P $PORT [ "$status" -eq 1 ] } @test "sql-server: multi dir sql-server locks out childen" { start_sql_server cd repo2 let PORT="$$ % (65536-1024) + 1024" run dolt sql-server -P $PORT [ "$status" -eq 1 ] } @test "sql-server: sql-server child locks out parent multi dir" { cd repo2 start_sql_server cd .. let PORT="$$ % (65536-1024) + 1024" run dolt sql-server -P $PORT [ "$status" -eq 1 ] } @test "sql-server: sql-server locks database to writes" { cd repo2 dolt sql -q "create table a (x int primary key)" start_sql_server run dolt sql -q "create table b (x int primary key)" [ "$status" -eq 1 ] [[ "$output" =~ "database is locked to writes" ]] || false run dolt sql -q "insert into b values (0)" [ "$status" -eq 1 ] [[ "$output" =~ "database is locked to writes" ]] || false } @test "sql-server: server fails to start up if there is already a file in the socket file path" { skiponwindows "unix socket is not available on Windows" cd repo2 touch mysql.sock run pwd REPO_NAME=$output let PORT="$$ % (65536-1024) + 1024" dolt sql-server --port=$PORT --socket="$REPO_NAME/mysql.sock" --user dolt > log.txt 2>&1 & SERVER_PID=$! run wait_for_connection $PORT 5000 [ "$status" -eq 1 ] run grep 'address already in use' log.txt [ "$status" -eq 0 ] [ "${#lines[@]}" -eq 1 ] } @test "sql-server: start server with yaml config with socket file path defined" { skiponwindows "unix socket is not available on Windows" cd repo2 DEFAULT_DB="repo2" let PORT="$$ % (65536-1024) + 1024" echo " log_level: debug user: name: dolt listener: host: localhost port: $PORT max_connections: 10 socket: /tmp/mysql.sock behavior: autocommit: true" > server.yaml dolt sql-server --config server.yaml > log.txt 2>&1 & SERVER_PID=$! wait_for_connection $PORT 5000 server_query repo2 1 "select 1 as col1" "col1\n1" run grep '\"/tmp/mysql.sock\"' log.txt [ "$status" -eq 0 ] [ "${#lines[@]}" -eq 1 ] }