%% MySQL/OTP – MySQL client library for Erlang/OTP %% Copyright (C) 2019 Jan Uhlig %% %% This file is part of MySQL/OTP. %% %% MySQL/OTP is free software: you can redistribute it and/or modify it under %% the terms of the GNU Lesser General Public License as published by the Free %% Software Foundation, either version 3 of the License, or (at your option) %% any later version. %% %% This program is distributed in the hope that it will be useful, but WITHOUT %% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or %% FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for %% more details. %% %% You should have received a copy of the GNU Lesser General Public License %% along with this program. If not, see . %% @doc This module performs test to an actual database. -module(mysql_change_user_tests). -include_lib("eunit/include/eunit.hrl"). -define(user1, "otptest"). -define(password1, "otptest"). -define(user2, "otptest2"). -define(password2, "otptest2"). %% Ensure that the current user can be changed to another user %% when given correct credentials. correct_credentials_test() -> Pid = connect_db(?user1), ?assertEqual(ok, mysql:change_user(Pid, ?user2, ?password2)), ?assert(is_current_user(Pid, ?user2)), close_conn(Pid), ok. %% Ensure that change user fails when given incorrect credentials, %% and that the current user still works. incorrect_credentials_fail_test() -> Pid = connect_db(?user1), TrapExit = erlang:process_flag(trap_exit, true), ?assertError({1045, <<"28000">>, <<"Access denied", _/binary>>}, mysql:change_user(Pid, ?user2, ?password1)), ExitReason = receive {'EXIT', Pid, Reason} -> Reason after 1000 -> error(timeout) end, erlang:process_flag(trap_exit, TrapExit), ?assertEqual(change_user_failed, ExitReason), close_conn(Pid), ok. %% Ensure that user variables are reset after a successful change user %% operation. reset_variables_test() -> Pid = connect_db(?user1), ok = mysql:query(Pid, <<"SET @foo=123">>), ?assertEqual(ok, mysql:change_user(Pid, ?user2, ?password2)), ?assert(is_current_user(Pid, ?user2)), ?assertEqual({ok, [<<"@foo">>], [[null]]}, mysql:query(Pid, <<"SELECT @foo">>)), close_conn(Pid), ok. %% Ensure that temporary tables are reset after a successful change user %% operation. reset_temptables_test() -> Pid = connect_db(?user1), ok = mysql:query(Pid, <<"CREATE DATABASE IF NOT EXISTS otptest">>), ok = mysql:query(Pid, <<"CREATE TEMPORARY TABLE otptest.foo (bar INT)">>), ?assertEqual(ok, mysql:change_user(Pid, ?user2, ?password2)), ?assert(is_current_user(Pid, ?user2)), ?assertMatch({error, {1146, <<"42S02">>, _}}, mysql:query(Pid, <<"SELECT * FROM otptest.foo">>)), ok = mysql:query(Pid, <<"DROP DATABASE IF EXISTS otptest">>), close_conn(Pid), ok. %% Ensure that change user fails when inside an unmanaged transaction. fail_in_unmanaged_transaction_test() -> Pid = connect_db(?user1), ok = mysql:query(Pid, <<"BEGIN">>), ?assert(mysql:in_transaction(Pid)), ?assertError(change_user_in_transaction, mysql:change_user(Pid, ?user2, ?password2)), ?assert(is_current_user(Pid, ?user1)), ?assert(mysql:in_transaction(Pid)), close_conn(Pid), ok. %% Ensure that change user fails when inside a managed transaction. fail_in_managed_transaction_test() -> Pid = connect_db(?user1), ?assertError(change_user_in_transaction, mysql:transaction(Pid, fun () -> mysql:change_user(Pid, ?user2, ?password2) end)), ?assert(is_current_user(Pid, ?user1)), close_conn(Pid), ok. with_db_test() -> Pid = connect_db(?user1), ok = mysql:query(Pid, <<"CREATE DATABASE IF NOT EXISTS otptest">>), ?assertEqual(ok, mysql:change_user(Pid, ?user2, ?password2, [{database, <<"otptest">>}])), ?assert(is_current_user(Pid, ?user2)), ?assertEqual({ok, [<<"DATABASE()">>], [[<<"otptest">>]]}, mysql:query(Pid, <<"SELECT DATABASE()">>)), ok = mysql:query(Pid, <<"DROP DATABASE IF EXISTS otptest">>), close_conn(Pid), ok. execute_queries_test() -> Pid = connect_db(?user1), ?assertEqual(ok, mysql:change_user(Pid, ?user2, ?password2, [{queries, [<<"SET @foo=123">>]}])), ?assert(is_current_user(Pid, ?user2)), ?assertEqual({ok, [<<"@foo">>], [[123]]}, mysql:query(Pid, <<"SELECT @foo">>)), close_conn(Pid), ok. prepare_statements_test() -> Pid = connect_db(?user1), ?assertEqual(ok, mysql:change_user(Pid, ?user2, ?password2, [{prepare, [{foo, <<"SELECT ? AS foo">>}]}])), ?assert(is_current_user(Pid, ?user2)), ?assertEqual({ok, [<<"foo">>], [[123]]}, mysql:execute(Pid, foo, [123])), close_conn(Pid), ok. connect_db(User) -> {ok, Pid} = mysql:start_link([{user, User}, {password, ?password1}, {log_warnings, false}]), Pid. close_conn(Pid) -> exit(Pid, normal). is_current_user(Pid, User) when is_binary(User) -> {ok, [<<"CURRENT_USER()">>], [[CurUser]]}=mysql:query(Pid, <<"SELECT CURRENT_USER()">>), <> =:= CurUser; is_current_user(Pid, User) -> is_current_user(Pid, iolist_to_binary(User)).