1: %%==============================================================================
    2: %% Copyright 2012 Erlang Solutions Ltd.
    3: %%
    4: %% Licensed under the Apache License, Version 2.0 (the "License");
    5: %% you may not use this file except in compliance with the License.
    6: %% You may obtain a copy of the License at
    7: %%
    8: %% http://www.apache.org/licenses/LICENSE-2.0
    9: %%
   10: %% Unless required by applicable law or agreed to in writing, software
   11: %% distributed under the License is distributed on an "AS IS" BASIS,
   12: %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13: %% See the License for the specific language governing permissions and
   14: %% limitations under the License.
   15: %%==============================================================================
   16: 
   17: -module(tcp_listener_SUITE).
   18: -compile([export_all, nowarn_export_all]).
   19: 
   20: -import(distributed_helper, [mim/0, require_rpc_nodes/1, rpc/4]).
   21: 
   22: %%--------------------------------------------------------------------
   23: %% Suite configuration
   24: %%--------------------------------------------------------------------
   25: 
   26: all() ->
   27:     [s2s_inet_sockname_returns_error,
   28:      service_inet_sockname_returns_error].
   29: 
   30: suite() ->
   31:     require_rpc_nodes([mim]).
   32: 
   33: %%--------------------------------------------------------------------
   34: %% Init & teardown
   35: %%--------------------------------------------------------------------
   36: 
   37: init_per_suite(Config) ->
   38:     setup_meck(),
   39:     Config.
   40: 
   41: end_per_suite(_Config) ->
   42:     teardown_meck().
   43: 
   44: setup_meck() ->
   45:     {Mod, Code} = rpc(mim(), dynamic_compile, from_string, [tcp_listener_helper_code()]),
   46:     rpc(mim(), code, load_binary, [Mod, "tcp_listener_helper.erl", Code]),
   47:     ok = rpc(mim(), meck, new, [mongoose_tcp_listener, [passthrough, no_link]]),
   48:     ok = rpc(mim(), tcp_listener_helper, setup_meck, []).
   49: 
   50: teardown_meck() ->
   51:     rpc(mim(), meck, unload, []).
   52: 
   53: tcp_listener_helper_code() ->
   54:     "-module(tcp_listener_helper).\n"
   55:     "-compile([export_all, nowarn_export_all]).\n"
   56:     "setup_meck() ->\n"
   57:     "    meck:expect(mongoose_tcp_listener, read_connection_details, fun read_connection_details/2).\n\n"
   58:     "read_connection_details(Socket, Opts) ->\n"
   59:     "    persistent_term:put(tcp_listener_helper_info, {Socket, self()}),\n"
   60:     "    gen_tcp:close(Socket),\n"
   61:     "    Result = meck:passthrough([Socket, Opts]),\n"
   62:     "    persistent_term:put(tcp_listener_helper_result, Result),\n"
   63:     "    Result.\n".
   64: 
   65: %%--------------------------------------------------------------------
   66: %% Test cases
   67: %%--------------------------------------------------------------------
   68: 
   69: s2s_inet_sockname_returns_error(_Config) ->
   70:     inet_sockname_returns_error(incoming_s2s_port).
   71: 
   72: service_inet_sockname_returns_error(_Config) ->
   73:     inet_sockname_returns_error(service_port).
   74: 
   75: %% Checks that the listener does not crash if inet:sockname/1 call returns an error
   76: inet_sockname_returns_error(PortName) ->
   77:     Port = ct:get_config({hosts, mim, PortName}),
   78:     {ok, ClientSocket} = gen_tcp:connect(localhost, Port, []),
   79:     receive {tcp_closed, ClientSocket} -> gen_tcp:close(ClientSocket)
   80:     after 5000 -> ct:fail("Socket was not closed by the server")
   81:     end,
   82:     {_ServerSocket, Pid} = rpc(mim(), persistent_term, get, [tcp_listener_helper_info]),
   83:     %% The listener process is still alive
   84:     [_|_] = rpc:pinfo(Pid),
   85:     {error, einval} = rpc(mim(), persistent_term, get, [tcp_listener_helper_result]),
   86:     ok.