aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssh/test/ssh_connection_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssh/test/ssh_connection_SUITE.erl')
-rw-r--r--lib/ssh/test/ssh_connection_SUITE.erl504
1 files changed, 215 insertions, 289 deletions
diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl
index 5cd892def8..43a899f974 100644
--- a/lib/ssh/test/ssh_connection_SUITE.erl
+++ b/lib/ssh/test/ssh_connection_SUITE.erl
@@ -21,125 +21,69 @@
-module(ssh_connection_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(SSH_DEFAULT_PORT, 22).
-define(EXEC_TIMEOUT, 10000).
-%% Test server callback functions
%%--------------------------------------------------------------------
-%% 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.
+suite() ->
+ [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [
+ {group, erlang_client},
+ interrupted_send
+ ].
+groups() ->
+ [{erlang_client, [], [simple_exec,
+ small_cat,
+ big_cat,
+ send_after_exit
+ ]}].
+
%%--------------------------------------------------------------------
+
init_per_suite(Config) ->
case catch crypto:start() of
ok ->
- case gen_tcp:connect("localhost", 22, []) of
- {error,econnrefused} ->
- {skip,"No openssh deamon"};
- _ ->
- Config
- end;
+ Config;
_Else ->
- {skip,"Could not start crypto!"}
+ {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) ->
crypto:stop(),
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_group(erlang_client, Config) ->
+ case gen_tcp:connect("localhost", 22, []) of
+ {error,econnrefused} ->
+ {skip,"No openssh deamon"};
+ _ ->
+ Config
+ end;
+init_per_group(_, Config) ->
+ Config.
+
+end_per_group(_, Config) ->
+ Config.
+
%%--------------------------------------------------------------------
init_per_testcase(_TestCase, Config) ->
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) ->
+end_per_testcase(_Config) ->
ssh:stop(),
ok.
+%%% TEST cases starts here.
%%--------------------------------------------------------------------
-%% 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() ->
- case os:find_executable("ssh") of
- false ->
- {skip, "openSSH not installed on host"};
- _ ->
- [{group, erlang_client}
- ]
- end.
-
-groups() ->
- [{erlang_client, [], [
- simple_exec,
- small_cat,
- big_cat,
- send_after_exit,
- interrupted_send
- ]}].
-
-init_per_group(erlang_server, Config) ->
- DataDir = ?config(data_dir, Config),
- UserDir = ?config(priv_dir, Config),
- ssh_test_lib:setup_dsa_known_host(DataDir, UserDir),
- Config;
-init_per_group(_, Config) ->
- Config.
-
-end_per_group(erlang_server, Config) ->
- UserDir = ?config(priv_dir, Config),
- ssh_test_lib:clean_dsa(UserDir),
- Config;
-end_per_group(_, Config) ->
- Config.
-
-%% TEST cases starts here.
-%--------------------------------------------------------------------
simple_exec(doc) ->
["Simple openssh connectivity test for ssh_connection:exec"];
-simple_exec(suite) ->
- [];
-
simple_exec(Config) when is_list(Config) ->
ConnectionRef = ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true},
{user_interaction, false}]),
@@ -147,34 +91,30 @@ simple_exec(Config) when is_list(Config) ->
success = ssh_connection:exec(ConnectionRef, ChannelId0,
"echo testing", infinity),
- %% receive response to input
- receive
- {ssh_cm, ConnectionRef, {data, ChannelId0, 0, <<"testing\n">>}} -> ok
- after ?EXEC_TIMEOUT -> test_server:fail()
- end,
-
- %% receive close messages
- receive
- {ssh_cm, ConnectionRef, {eof, ChannelId0}} -> ok
- after ?EXEC_TIMEOUT -> test_server:fail()
- end,
- receive
- {ssh_cm, ConnectionRef, {exit_status, ChannelId0, 0}} -> ok
- after ?EXEC_TIMEOUT -> test_server:fail()
- end,
- receive
- {ssh_cm, ConnectionRef,{closed, ChannelId0}} -> ok
- after ?EXEC_TIMEOUT -> test_server:fail()
- end.
-
-
-%--------------------------------------------------------------------
+ %% receive response to input
+ receive
+ {ssh_cm, ConnectionRef, {data, ChannelId0, 0, <<"testing\n">>}} ->
+ ok
+ end,
+
+ %% receive close messages
+ receive
+ {ssh_cm, ConnectionRef, {eof, ChannelId0}} ->
+ ok
+ end,
+ receive
+ {ssh_cm, ConnectionRef, {exit_status, ChannelId0, 0}} ->
+ ok
+ end,
+ receive
+ {ssh_cm, ConnectionRef,{closed, ChannelId0}} ->
+ ok
+ end.
+
+%%--------------------------------------------------------------------
small_cat(doc) ->
["Use 'cat' to echo small data block back to us."];
-small_cat(suite) ->
- [];
-
small_cat(Config) when is_list(Config) ->
ConnectionRef = ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true},
{user_interaction, false}]),
@@ -182,37 +122,34 @@ small_cat(Config) when is_list(Config) ->
success = ssh_connection:exec(ConnectionRef, ChannelId0,
"cat", infinity),
- Data = <<"I like spaghetti squash">>,
- ok = ssh_connection:send(ConnectionRef, ChannelId0, Data),
- ok = ssh_connection:send_eof(ConnectionRef, ChannelId0),
-
- %% receive response to input
- receive
- {ssh_cm, ConnectionRef, {data, ChannelId0, 0, Data}} -> ok
- after ?EXEC_TIMEOUT -> test_server:fail()
- end,
-
- %% receive close messages
- receive
- {ssh_cm, ConnectionRef, {eof, ChannelId0}} -> ok
- after ?EXEC_TIMEOUT -> test_server:fail()
- end,
- receive
- {ssh_cm, ConnectionRef, {exit_status, ChannelId0, 0}} -> ok
- after ?EXEC_TIMEOUT -> test_server:fail()
- end,
- receive
- {ssh_cm, ConnectionRef,{closed, ChannelId0}} -> ok
- after ?EXEC_TIMEOUT -> test_server:fail()
- end.
-
-%--------------------------------------------------------------------
+ Data = <<"I like spaghetti squash">>,
+ ok = ssh_connection:send(ConnectionRef, ChannelId0, Data),
+ ok = ssh_connection:send_eof(ConnectionRef, ChannelId0),
+
+ %% receive response to input
+ receive
+ {ssh_cm, ConnectionRef, {data, ChannelId0, 0, Data}} ->
+ ok
+ end,
+
+ %% receive close messages
+ receive
+ {ssh_cm, ConnectionRef, {eof, ChannelId0}} ->
+ ok
+ end,
+ receive
+ {ssh_cm, ConnectionRef, {exit_status, ChannelId0, 0}} ->
+ ok
+ end,
+ receive
+ {ssh_cm, ConnectionRef,{closed, ChannelId0}} ->
+ ok
+ end.
+
+%%--------------------------------------------------------------------
big_cat(doc) ->
["Use 'cat' to echo large data block back to us."];
-big_cat(suite) ->
- [];
-
big_cat(Config) when is_list(Config) ->
ConnectionRef = ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true},
{user_interaction, false}]),
@@ -220,167 +157,156 @@ big_cat(Config) when is_list(Config) ->
success = ssh_connection:exec(ConnectionRef, ChannelId0,
"cat", infinity),
- %% build 10MB binary
- Data = << <<X:32>> || X <- lists:seq(1,2500000)>>,
-
- %% pre-adjust receive window so the other end doesn't block
- ssh_connection:adjust_window(ConnectionRef, ChannelId0, size(Data)),
-
- test_server:format("sending ~p byte binary~n",[size(Data)]),
- ok = ssh_connection:send(ConnectionRef, ChannelId0, Data, 10000),
- %timer:sleep(3000),
- ok = ssh_connection:send_eof(ConnectionRef, ChannelId0),
-
- %% collect echoed data until eof
- case big_cat_rx(ConnectionRef, ChannelId0) of
- {ok, Data} -> ok;
- {ok, Other} ->
- case size(Data) =:= size(Other) of
- true ->
- test_server:format("received and sent data are same size but do not match~n",[]);
- false ->
- test_server:format("sent ~p but only received ~p~n",[size(Data), size(Other)])
- end,
- test_server:fail(receive_data_mismatch);
- Else ->
- test_server:fail(Else)
- end,
-
- %% receive close messages (eof already consumed)
- receive
- {ssh_cm, ConnectionRef, {exit_status, ChannelId0, 0}} -> ok
- after ?EXEC_TIMEOUT -> test_server:fail()
- end,
- receive
- {ssh_cm, ConnectionRef,{closed, ChannelId0}} -> ok
- after ?EXEC_TIMEOUT -> test_server:fail()
- end.
+ %% build 10MB binary
+ Data = << <<X:32>> || X <- lists:seq(1,2500000)>>,
+
+ %% pre-adjust receive window so the other end doesn't block
+ ssh_connection:adjust_window(ConnectionRef, ChannelId0, size(Data)),
+
+ test_server:format("sending ~p byte binary~n",[size(Data)]),
+ ok = ssh_connection:send(ConnectionRef, ChannelId0, Data, 10000),
+ ok = ssh_connection:send_eof(ConnectionRef, ChannelId0),
+
+ %% collect echoed data until eof
+ case big_cat_rx(ConnectionRef, ChannelId0) of
+ {ok, Data} ->
+ ok;
+ {ok, Other} ->
+ case size(Data) =:= size(Other) of
+ true ->
+ test_server:format("received and sent data are same"
+ "size but do not match~n",[]);
+ false ->
+ test_server:format("sent ~p but only received ~p~n",
+ [size(Data), size(Other)])
+ end,
+ ct:fail(receive_data_mismatch);
+ Else ->
+ ct:fail(Else)
+ end,
+
+ %% receive close messages (eof already consumed)
+ receive
+ {ssh_cm, ConnectionRef, {exit_status, ChannelId0, 0}} ->
+ ok
+ end,
+ receive
+ {ssh_cm, ConnectionRef,{closed, ChannelId0}} ->
+ ok
+ end.
big_cat_rx(ConnectionRef, ChannelId) ->
- big_cat_rx(ConnectionRef, ChannelId, []).
+ big_cat_rx(ConnectionRef, ChannelId, []).
big_cat_rx(ConnectionRef, ChannelId, Acc) ->
- receive
- {ssh_cm, ConnectionRef, {data, ChannelId, 0, Data}} ->
- %% ssh_connection:adjust_window(ConnectionRef, ChannelId, size(Data)), % window was pre-adjusted, don't adjust again here
- big_cat_rx(ConnectionRef, ChannelId, [Data | Acc]);
- {ssh_cm, ConnectionRef, {eof, ChannelId}} ->
- {ok, iolist_to_binary(lists:reverse(Acc))}
- after ?EXEC_TIMEOUT -> timeout
- end.
-
-%--------------------------------------------------------------------
+ receive
+ {ssh_cm, ConnectionRef, {data, ChannelId, 0, Data}} ->
+ %% ssh_connection:adjust_window(ConnectionRef, ChannelId, size(Data)),
+ %% window was pre-adjusted, don't adjust again here
+ big_cat_rx(ConnectionRef, ChannelId, [Data | Acc]);
+ {ssh_cm, ConnectionRef, {eof, ChannelId}} ->
+ {ok, iolist_to_binary(lists:reverse(Acc))}
+ after ?EXEC_TIMEOUT ->
+ timeout
+ end.
+
+%%--------------------------------------------------------------------
send_after_exit(doc) ->
["Send channel data after the channel has been closed."];
-send_after_exit(suite) ->
- [];
-
send_after_exit(Config) when is_list(Config) ->
ConnectionRef = ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true},
{user_interaction, false}]),
{ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
- %% Shell command "false" will exit immediately
- success = ssh_connection:exec(ConnectionRef, ChannelId0,
+ %% Shell command "false" will exit immediately
+ success = ssh_connection:exec(ConnectionRef, ChannelId0,
"false", infinity),
- timer:sleep(2000), %% Allow incoming eof/close/exit_status ssh messages to be processed
-
- Data = <<"I like spaghetti squash">>,
- case ssh_connection:send(ConnectionRef, ChannelId0, Data, 2000) of
- {error, closed} -> ok;
- ok -> test_server:fail({expected,{error,closed}});
- {error, timeout} -> test_server:fail({expected,{error,closed}});
- Else -> test_server:fail(Else)
- end,
-
- %% receive close messages
- receive
- {ssh_cm, ConnectionRef, {eof, ChannelId0}} -> ok
- after ?EXEC_TIMEOUT -> test_server:fail()
- end,
- receive
- {ssh_cm, ConnectionRef, {exit_status, ChannelId0, _}} -> ok
- after ?EXEC_TIMEOUT -> test_server:fail()
- end,
- receive
- {ssh_cm, ConnectionRef,{closed, ChannelId0}} -> ok
- after ?EXEC_TIMEOUT -> test_server:fail()
- end.
-
-%--------------------------------------------------------------------
-interrupted_send(doc) ->
- ["Use 'head' to cause a channel exit partway through a large send."];
+ timer:sleep(2000), %% Allow incoming eof/close/exit_status ssh messages to be processed
-interrupted_send(suite) ->
- [];
+ Data = <<"I like spaghetti squash">>,
+ case ssh_connection:send(ConnectionRef, ChannelId0, Data, 2000) of
+ {error, closed} -> ok;
+ ok ->
+ ct:fail({expected,{error,closed}});
+ {error, timeout} ->
+ ct:fail({expected,{error,closed}});
+ Else ->
+ ct:fail(Else)
+ end,
+
+ %% receive close messages
+ receive
+ {ssh_cm, ConnectionRef, {eof, ChannelId0}} ->
+ ok
+ end,
+ receive
+ {ssh_cm, ConnectionRef, {exit_status, ChannelId0, _}} ->
+ ok
+ end,
+ receive
+ {ssh_cm, ConnectionRef,{closed, ChannelId0}} ->
+ ok
+ end.
+%%--------------------------------------------------------------------
+interrupted_send(doc) ->
+ ["Use a subsystem that echos n char and then sends eof to cause a channel exit partway through a large send."];
interrupted_send(Config) when is_list(Config) ->
- ConnectionRef = ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true},
- {user_interaction, false}]),
- {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
- success = ssh_connection:exec(ConnectionRef, ChannelId0,
- "head -c 4000000", infinity),
-
- %% build 10MB binary
- Data = << <<X:32>> || X <- lists:seq(1,2500000)>>,
-
- %% expect remote end to send us 4MB back
- <<ExpectedData:4000000/binary, _/binary>> = Data,
-
- %% pre-adjust receive window so the other end doesn't block
- ssh_connection:adjust_window(ConnectionRef, ChannelId0, size(Data)),
-
- test_server:format("sending ~p byte binary~n",[size(Data)]),
-
- case ssh_connection:send(ConnectionRef, ChannelId0, Data, 10000) of
- {error, closed} -> ok;
- ok -> test_server:fail({expected,{error,closed}});
- {error, timeout} -> test_server:fail({expected,{error,closed}});
- SendElse -> test_server:fail(SendElse)
- end,
-
- case ssh_connection:send_eof(ConnectionRef, ChannelId0) of
- {error, closed} -> ok;
- ok -> test_server:fail({expected,{error,closed}});
- EofElse -> test_server:fail(EofElse)
- end,
-
- %% collect echoed data until eof
- case interrupted_send_rx(ConnectionRef, ChannelId0) of
- {ok, ExpectedData} -> ok;
- {ok, Other} ->
- case size(ExpectedData) =:= size(Other) of
- true ->
- test_server:format("received expected number of bytes, but bytes do not match~n",[]);
- false ->
- test_server:format("expected ~p but only received ~p~n",[size(ExpectedData), size(Other)])
- end,
- test_server:fail(receive_data_mismatch);
- RxElse ->
- test_server:fail(RxElse)
- end,
-
- %% receive close messages (eof already consumed)
- receive
- {ssh_cm, ConnectionRef, {exit_status, ChannelId0, 0}} -> ok
- after ?EXEC_TIMEOUT -> test_server:fail()
- end,
- receive
- {ssh_cm, ConnectionRef,{closed, ChannelId0}} -> ok
- after ?EXEC_TIMEOUT -> test_server:fail()
- end.
-
-interrupted_send_rx(ConnectionRef, ChannelId) ->
- interrupted_send_rx(ConnectionRef, ChannelId, []).
-
-interrupted_send_rx(ConnectionRef, ChannelId, Acc) ->
- receive
- {ssh_cm, ConnectionRef, {data, ChannelId, 0, Data}} ->
- %% ssh_connection:adjust_window(ConnectionRef, ChannelId, size(Data)), % window was pre-adjusted, don't adjust again here
- interrupted_send_rx(ConnectionRef, ChannelId, [Data | Acc]);
- {ssh_cm, ConnectionRef, {eof, ChannelId}} ->
- {ok, iolist_to_binary(lists:reverse(Acc))}
- after ?EXEC_TIMEOUT -> timeout
- end.
+ PrivDir = ?config(priv_dir, Config),
+ UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
+ file:make_dir(UserDir),
+ SysDir = ?config(data_dir, Config),
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
+ {user_dir, UserDir},
+ {password, "morot"},
+ {subsystems, [{"echo_n", {ssh_echo_server, [4000000]}}]}]),
+
+ ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user, "foo"},
+ {password, "morot"},
+ {user_interaction, false},
+ {user_dir, UserDir}]),
+
+ {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
+
+ success = ssh_connection:subsystem(ConnectionRef, ChannelId, "echo_n", infinity),
+
+ %% build 10MB binary
+ Data = << <<X:32>> || X <- lists:seq(1,2500000)>>,
+
+ %% expect remote end to send us 4MB back
+ <<ExpectedData:4000000/binary, _/binary>> = Data,
+
+ %% pre-adjust receive window so the other end doesn't block
+ ssh_connection:adjust_window(ConnectionRef, ChannelId, size(ExpectedData) + 1),
+
+ case ssh_connection:send(ConnectionRef, ChannelId, Data, 10000) of
+ {error, closed} ->
+ ok;
+ Msg ->
+ ct:fail({expected,{error,closed}, got, Msg})
+ end,
+ receive_data(ExpectedData, ConnectionRef, ChannelId),
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid).
+
+
+%% Internal funtions ------------------------------------------------------------------
+
+receive_data(ExpectedData, ConnectionRef, ChannelId) ->
+ ExpectedData = collect_data(ConnectionRef, ChannelId).
+
+collect_data(ConnectionRef, ChannelId) ->
+ collect_data(ConnectionRef, ChannelId, []).
+
+collect_data(ConnectionRef, ChannelId, Acc) ->
+ receive
+ {ssh_cm, ConnectionRef, {data, ChannelId, 0, Data}} ->
+ collect_data(ConnectionRef, ChannelId, [Data | Acc]);
+ {ssh_cm, ConnectionRef, {eof, ChannelId}} ->
+ iolist_to_binary(lists:reverse(Acc))
+ after 5000 ->
+ timeout
+ end.