%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2008-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. %% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. %% %% %CopyrightEnd% %% %% -module(ssh_basic_SUITE). -include_lib("common_test/include/ct.hrl"). -include("test_server_line.hrl"). %% Note: This directive should only be used in test suites. -compile(export_all). -define(NEWLINE, <<"\r\n">>). %%-------------------------------------------------------------------- %% Function: init_per_suite(Config) -> Config %% Config - [tuple()] %% A list of key/value pairs, holding the test case configuration. %% Description: Initialization before the whole suite %% %% Note: This function is free to add any key/value pairs to the Config %% variable, but should NOT alter/remove any existing entries. %%-------------------------------------------------------------------- init_per_suite(Config) -> case catch crypto:start() of ok -> Dir = ?config(priv_dir, Config), ssh_test_lib:save_known_hosts(Dir), {ok, _} = ssh_test_lib:get_id_keys(Dir), Config; _Else -> {skip, "Crypto could not be started!"} end. %%-------------------------------------------------------------------- %% Function: end_per_suite(Config) -> _ %% Config - [tuple()] %% A list of key/value pairs, holding the test case configuration. %% Description: Cleanup after the whole suite %%-------------------------------------------------------------------- end_per_suite(Config) -> Dir = ?config(priv_dir, Config), crypto:stop(), ssh_test_lib:remove_id_keys(Dir), ssh_test_lib:restore_known_hosts(Dir), ok. %%-------------------------------------------------------------------- %% Function: init_per_testcase(TestCase, Config) -> Config %% Case - atom() %% Name of the test case that is about to be run. %% Config - [tuple()] %% A list of key/value pairs, holding the test case configuration. %% %% Description: Initialization before each test case %% %% Note: This function is free to add any key/value pairs to the Config %% variable, but should NOT alter/remove any existing entries. %% Description: Initialization before each test case %%-------------------------------------------------------------------- init_per_testcase(_TestCase, Config) -> rename_known_hosts(backup), ssh:start(), Config. %%-------------------------------------------------------------------- %% Function: end_per_testcase(TestCase, Config) -> _ %% Case - atom() %% Name of the test case that is about to be run. %% Config - [tuple()] %% A list of key/value pairs, holding the test case configuration. %% Description: Cleanup after each test case %%-------------------------------------------------------------------- end_per_testcase(_TestCase, _Config) -> ssh:stop(), rename_known_hosts(restore), ok. %%-------------------------------------------------------------------- %% Function: all(Clause) -> TestCases %% Clause - atom() - suite | doc %% TestCases - [Case] %% Case - atom() %% Name of a test case. %% Description: Returns a list of all test cases in this test suite %%-------------------------------------------------------------------- all() -> [exec, exec_compressed, shell, daemon_allready_started, server_password_option, server_userpassword_option, known_hosts]. groups() -> []. init_per_group(_GroupName, Config) -> Config. end_per_group(_GroupName, Config) -> Config. %% Test cases starts here. %%-------------------------------------------------------------------- exec(doc) -> ["Test api function ssh_connection:exec"]; exec(suite) -> []; exec(Config) when is_list(Config) -> process_flag(trap_exit, true), SystemDir = ?config(data_dir, Config), Host = ssh_test_lib:hostname(), Port = ssh_test_lib:inet_port(), {ok, Pid} = ssh:daemon(Port, [{system_dir, SystemDir}, {failfun, fun ssh_test_lib:failfun/2}]), {ok, ConnectionRef} = ssh:connect(Host, Port, [{silently_accept_hosts, true}, {user_interaction, false}]), {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity), success = ssh_connection:exec(ConnectionRef, ChannelId0, "1+1.", infinity), Data0 = {ssh_cm, ConnectionRef, {data, ChannelId0, 0, <<"2\n">>}}, case ssh_test_lib:receive_exec_result(Data0) of expected -> ok; Other0 -> test_server:fail(Other0) end, ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId0), %% Test that it is possible to start a new channel and %% run an other exec on the same connection. {ok, ChannelId1} = ssh_connection:session_channel(ConnectionRef, infinity), success = ssh_connection:exec(ConnectionRef, ChannelId1, "2+2.", infinity), Data1 = {ssh_cm, ConnectionRef, {data, ChannelId1, 0, <<"4\n">>}}, case ssh_test_lib:receive_exec_result(Data1) of expected -> ok; Other1 -> test_server:fail(Other1) end, ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId1), ssh:stop_daemon(Pid). %%-------------------------------------------------------------------- exec_compressed(doc) -> ["Test that compression option works"]; exec_compressed(suite) -> []; exec_compressed(Config) when is_list(Config) -> process_flag(trap_exit, true), SystemDir = ?config(data_dir, Config), Host = ssh_test_lib:hostname(), Port = ssh_test_lib:inet_port(), {ok, Pid} = ssh:daemon(Port, [{system_dir, SystemDir}, {compression, zlib}, {failfun, fun ssh_test_lib:failfun/2}]), {ok, ConnectionRef} = ssh:connect(Host, Port, [{silently_accept_hosts, true}, {user_interaction, false}]), {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity), success = ssh_connection:exec(ConnectionRef, ChannelId, "1+1.", infinity), Data = {ssh_cm, ConnectionRef, {data, ChannelId, 0, <<"2\n">>}}, case ssh_test_lib:receive_exec_result(Data) of expected -> ok; Other -> test_server:fail(Other) end, ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId), ssh:stop_daemon(Pid). %%-------------------------------------------------------------------- shell(doc) -> ["Test that ssh:shell/2 works"]; shell(suite) -> []; shell(Config) when is_list(Config) -> process_flag(trap_exit, true), SystemDir = ?config(data_dir, Config), Port = ssh_test_lib:inet_port(), {ok, _Pid} = ssh:daemon(Port, [{system_dir, SystemDir}, {failfun, fun ssh_test_lib:failfun/2}]), test_server:sleep(500), IO = ssh_test_lib:start_io_server(), Shell = ssh_test_lib:start_shell(Port, IO), receive ErlShellStart -> test_server:format("Erlang shell start: ~p~n", [ErlShellStart]) end, receive ErlPrompt0 -> test_server:format("Erlang prompt: ~p~n", [ErlPrompt0]) end, IO ! {input, self(), "1+1.\r\n"}, receive Echo0 -> test_server:format("Echo: ~p ~n", [Echo0]) end, receive ?NEWLINE -> ok end, receive Result0 = <<"2">> -> test_server:format("Result: ~p~n", [Result0]) end, receive ?NEWLINE -> ok end, receive ErlPrompt1 -> test_server:format("Erlang prompt: ~p~n", [ErlPrompt1]) end, exit(Shell, kill), %% Does not seem to work in the testserver! %% IO ! {input, self(), "q().\r\n"}, %% receive %% ?NEWLINE -> %% ok %% end, %% receive %% Echo1 -> %% test_server:format("Echo: ~p ~n", [Echo1]) %% end, %% receive %% ?NEWLINE -> %% ok %% end, %% receive %% Result1 -> %% test_server:format("Result: ~p~n", [Result1]) %% end, receive {'EXIT', Shell, killed} -> ok end. %%-------------------------------------------------------------------- daemon_allready_started(doc) -> ["Test that get correct error message if you try to start a daemon", "on an adress that allready runs a daemon see also seq10667" ]; daemon_allready_started(suite) -> []; daemon_allready_started(Config) when is_list(Config) -> SystemDir = ?config(data_dir, Config), Port = ssh_test_lib:inet_port(), {ok, Pid} = ssh:daemon(Port, [{system_dir, SystemDir}, {failfun, fun ssh_test_lib:failfun/2}]), {error, eaddrinuse} = ssh:daemon(Port, [{system_dir, SystemDir}, {failfun, fun ssh_test_lib:failfun/2}]), ssh:stop_daemon(Pid). %%-------------------------------------------------------------------- server_password_option(doc) -> ["validate to server that uses the 'password' option"]; server_password_option(suite) -> []; server_password_option(Config) when is_list(Config) -> UserDir = ?config(data_dir, Config), % to make sure we don't use SysDir = ?config(data_dir, Config), % public-key-auth Port = ssh_test_lib:inet_port(), {ok, Pid} = ssh:daemon(Port, [{system_dir, SysDir}, {password, "morot"}]), Host = ssh_test_lib:hostname(), {ok, ConnectionRef} = ssh:connect(Host, Port, [{silently_accept_hosts, true}, {user, "foo"}, {password, "morot"}, {user_interaction, false}, {user_dir, UserDir}]), {error, Reason} = ssh:connect(Host, Port, [{silently_accept_hosts, true}, {user, "vego"}, {password, "foo"}, {user_interaction, false}, {user_dir, UserDir}]), test_server:format("Test of wrong pasword: Error msg: ~p ~n", [Reason]), ssh:close(ConnectionRef), ssh:stop_daemon(Pid). %%-------------------------------------------------------------------- server_userpassword_option(doc) -> ["validate to server that uses the 'password' option"]; server_userpassword_option(suite) -> []; server_userpassword_option(Config) when is_list(Config) -> UserDir = ?config(data_dir, Config), % to make sure we don't use SysDir = ?config(data_dir, Config), % public-key-auth Port = ssh_test_lib:inet_port(), {ok, Pid} = ssh:daemon(Port, [{system_dir, SysDir}, {user_passwords, [{"vego", "morot"}]}]), Host = ssh_test_lib:hostname(), {ok, ConnectionRef} = ssh:connect(Host, Port, [{silently_accept_hosts, true}, {user, "vego"}, {password, "morot"}, {user_interaction, false}, {user_dir, UserDir}]), ssh:close(ConnectionRef), {error, Reason0} = ssh:connect(Host, Port, [{silently_accept_hosts, true}, {user, "foo"}, {password, "morot"}, {user_interaction, false}, {user_dir, UserDir}]), test_server:format("Test of user foo that does not exist. " "Error msg: ~p ~n", [Reason0]), {error, Reason1} = ssh:connect(Host, Port, [{silently_accept_hosts, true}, {user, "vego"}, {password, "foo"}, {user_interaction, false}, {user_dir, UserDir}]), test_server:format("Test of wrong Pasword. " "Error msg: ~p ~n", [Reason1]), ssh:stop_daemon(Pid). %%-------------------------------------------------------------------- known_hosts(doc) -> ["check that known_hosts is updated correctly"]; known_hosts(suite) -> []; known_hosts(Config) when is_list(Config) -> SystemDir = ?config(data_dir, Config), UserDir = ?config(priv_dir, Config), Port = ssh_test_lib:inet_port(), {ok, Pid} = ssh:daemon(Port, [{system_dir, SystemDir}, {failfun, fun ssh_test_lib:failfun/2}]), KnownHosts = filename:join(UserDir, "known_hosts"), file:delete(KnownHosts), {error, enoent} = file:read_file(KnownHosts), Host = ssh_test_lib:hostname(), {ok, ConnectionRef} = ssh:connect(Host, Port, [{user_dir, UserDir}, {user_interaction, false}, silently_accept_hosts]), {ok, _Channel} = ssh_connection:session_channel(ConnectionRef, infinity), ok = ssh:close(ConnectionRef), {ok, Binary} = file:read_file(KnownHosts), Lines = string:tokens(binary_to_list(Binary), "\n"), [Line] = Lines, {ok, Hostname} = inet:gethostname(), [HostAndIp, Alg, _KeyData] = string:tokens(Line, " "), [Hostname, _Ip] = string:tokens(HostAndIp, ","), "ssh-" ++ _ = Alg, ssh:stop_daemon(Pid). %%-------------------------------------------------------------------- %% Internal functions %%-------------------------------------------------------------------- rename_known_hosts(BR) -> KnownHosts = ssh_file:file_name(user, "known_hosts", []), B = KnownHosts ++ "xxx", case BR of backup -> file:rename(KnownHosts, B); restore -> file:delete(KnownHosts), file:rename(B, KnownHosts) end.