blob: dc11a9a9aa6b688e7d4070e68618766d343fcb8c [file] [log] [blame]
%%
%% Licensed to the Apache Software Foundation (ASF) under one
%% or more contributor license agreements. See the NOTICE file
%% distributed with this work for additional information
%% regarding copyright ownership. The ASF licenses this file
%% to you under the Apache License, Version 2.0 (the
%% "License"); you may not use this file except in compliance
%% with the License. You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied. See the License for the
%% specific language governing permissions and limitations
%% under the License.
%%
%% Tests the behavior of clients in the face of transport errors.
%% Makes sure start, start_linked, and start_tethered work as expected.
-module(test_tether).
-compile(export_all).
t() ->
io:format("Beginning transport error test.~n"),
Pid1 = erlang:spawn(?MODULE, t_sub, [2]),
wait_for(Pid1),
io:format("Beginning protocol error test.~n"),
Pid2 = erlang:spawn(?MODULE, t_sub, [22]),
wait_for(Pid2),
ok.
t_sub(Port) ->
io:format("Starting.~n", []),
register(tester, self()),
Pid1 = erlang:spawn(?MODULE, test_start, [Port]),
receive after 200 -> ok end, % Wait for completion.
case is_up(Pid1) of
true ->
io:format("PASS. Unlinked owner still alive.~n");
false ->
io:format("FAIL. Unlinked owner is dead.~n")
end,
Pid2 = erlang:spawn(?MODULE, test_linked, [Port]),
receive after 200 -> ok end, % Wait for completion.
case is_up(Pid2) of
true ->
io:format("FAIL. Linked owner still alive.~n");
false ->
io:format("PASS. Linked owner is dead.~n")
end,
Pid3 = erlang:spawn(?MODULE, test_tethered, [Port]),
receive after 200 -> ok end, % Wait for completion.
case is_up(Pid3) of
true ->
io:format("PASS. Tethered owner still alive.~n");
false ->
io:format("FAIL. Tethered owner is dead.~n")
end,
check_extras(3).
is_up(Pid) ->
MonitorRef = erlang:monitor(process, Pid),
receive
{'DOWN', MonitorRef, process, Pid, _Info} ->
false
after
50 ->
erlang:demonitor(MonitorRef),
true
end.
wait_for(Pid) ->
MonitorRef = erlang:monitor(process, Pid),
receive
{'DOWN', MonitorRef, process, Pid, _Info} ->
ok
end.
check_extras(0) -> ok;
check_extras(N) ->
receive
{client, Type, Pid} ->
case {Type, is_up(Pid)} of
{unlinked, true} ->
io:format("PASS. Unlinked client still alive.~n");
{unlinked, false} ->
io:format("FAIL. Unlinked client dead.~n");
{linked, true} ->
io:format("FAIL. Linked client still alive.~n");
{linked, false} ->
io:format("PASS. Linked client dead.~n");
{tethered, true} ->
io:format("FAIL. Tethered client still alive.~n");
{tethered, false} ->
io:format("PASS. Tethered client dead.~n")
end,
check_extras(N-1)
after
500 ->
io:format("FAIL. Expected ~p more clients.~n", [N])
end.
make_thrift_client(Opts) ->
thrift_client:start(fun()->ok end, thriftTest_thrift, Opts).
make_protocol_factory(Port) ->
{ok, TransportFactory} =
thrift_socket_transport:new_transport_factory(
"127.0.0.1", Port, []),
{ok, ProtocolFactory} =
thrift_binary_protocol:new_protocol_factory(
TransportFactory, []),
ProtocolFactory.
test_start(Port) ->
{ok, Client1} = make_thrift_client([{connect, false}]),
tester ! {client, unlinked, Client1},
{ok, Client2} = make_thrift_client([{connect, false}]),
io:format("PASS. Unlinked clients created.~n"),
try
gen_server:call(Client2, {connect, make_protocol_factory(Port)}),
thrift_client:call(Client2, testVoid, []),
io:format("FAIL. Unlinked client connected and called.~n", [])
catch
Kind:Info ->
io:format("PASS. Caught unlinked error. ~p:~p~n", [Kind, Info])
end,
receive after 100 ->
io:format("PASS. Still alive after unlinked death.~n"),
%% Hang around a little longer so our parent can verify.
receive after 200 -> ok end
end,
%% Exit abnormally to not kill our unlinked extra client.
exit(die).
test_linked(Port) ->
{ok, Client1} = make_thrift_client([{connect, false}, {monitor, link}]),
tester ! {client, linked, Client1},
{ok, Client2} = make_thrift_client([{connect, false}, {monitor, link}]),
io:format("PASS. Linked clients created.~n"),
try
gen_server:call(Client2, {connect, make_protocol_factory(Port)}),
thrift_client:call(Client2, testVoid, []),
io:format("FAIL. Linked client connected and called.~n", [])
catch
Kind:Info ->
io:format("FAIL. Caught linked error. ~p:~p~n", [Kind, Info])
end,
receive after 100 ->
io:format("FAIL. Still alive after linked death.~n"),
% Hang around a little longer so our parent can verify.
receive after 200 -> ok end
end,
%% Exit abnormally to kill our linked extra client.
%% But we should never get here.
exit(die).
test_tethered(Port) ->
{ok, Client1} = make_thrift_client([{connect, false}, {monitor, tether}]),
tester ! {client, tethered, Client1},
{ok, Client2} = make_thrift_client([{connect, false}, {monitor, tether}]),
io:format("PASS. Tethered clients created.~n"),
try
gen_server:call(Client2, {connect, make_protocol_factory(Port)}),
thrift_client:call(Client2, testVoid, []),
io:format("FAIL. Tethered client connected and called.~n", [])
catch
Kind:Info ->
io:format("PASS. Caught tethered error. ~p:~p~n", [Kind, Info])
end,
receive after 100 ->
io:format("PASS. Still alive after tethered death.~n"),
% Hang around a little longer so our parent can verify.
receive after 200 -> ok end
end,
%% Exit abnormally to kill our tethered extra client.
exit(die).