diff --git a/apps/epp_proxy/test/tcp_client_SUITE.erl b/apps/epp_proxy/test/tcp_client_SUITE.erl new file mode 100644 index 0000000..f4384ec --- /dev/null +++ b/apps/epp_proxy/test/tcp_client_SUITE.erl @@ -0,0 +1,184 @@ +-module(tcp_client_SUITE). + +-include("epp_proxy.hrl"). +-include_lib("common_test/include/ct.hrl"). + +-export([all/0]). +-export([init_per_suite/1, end_per_suite/1]). +-export([frame_size_test_case/1, + greetings_test_case/1, + session_test_case/1, + valid_command_test_case/1, + invalid_command_test_case/1, + error_test_case/1]). + +all() -> + [frame_size_test_case, + greetings_test_case, + session_test_case, + valid_command_test_case, + invalid_command_test_case, + error_test_case]. + +init_per_suite(Config) -> + application:ensure_all_started(epp_proxy), + application:ensure_all_started(hackney), + Options = [binary, + {active, false}], + [{tcp_options, Options} | Config]. + +end_per_suite(Config) -> + application:stop(epp_proxy), + application:stop(hackney), + Config. + +%% Test Cases +frame_size_test_case(Config) -> + Options = proplists:get_value(tcp_options, Config), + {ok, Socket} = gen_tcp:connect("localhost", 1180, Options, 2000), + {ok, Data} = gen_tcp:recv(Socket, 0, 1200), + true = (byte_size(Data) =:= length_of_data(Data)), + ok. + +greetings_test_case(Config) -> + Options = proplists:get_value(tcp_options, Config), + {ok, Socket} = gen_tcp:connect("localhost", 1180, Options, 2000), + Data = receive_data(Socket), + match_data(Data, ""), + ok. + +session_test_case(Config) -> + Options = proplists:get_value(tcp_options, Config), + {ok, Socket} = gen_tcp:connect("localhost", 1180, Options, 2000), + _Data = receive_data(Socket), + ok = send_data(login_command(), Socket), + LoginResponse = receive_data(Socket), + match_data(LoginResponse, "Command completed successfully"), + match_data(LoginResponse, "ccReg-5886259930"), + LogoutCommand = + <<"\n" + "\n" + "\n" + "\n" + "test_bestnames\n" + "testtest\n" + "\n" + "1.0\n" + "en\n" + "\n" + "\n" + "https://epp.tld.ee/schema/domain-eis-1.0.xsd\n" + "https://epp.tld.ee/schema/contact-ee-1.1.xsd\n" + "urn:ietf:params:xml:ns:host-1.0\n" + "urn:ietf:params:xml:ns:keyrelay-1.0\n" + "\n" + "\n" + "\n" + "\n">>, + ok = send_data(LogoutCommand, Socket), + LogoutResponse = receive_data(Socket), + match_data(LogoutResponse, + "Command completed successfully; ending session"), + %% After receiving logout, connection should be closed. + {error, closed} = receive_data(Socket), + ok. + +valid_command_test_case(Config) -> + Options = proplists:get_value(tcp_options, Config), + {ok, Socket} = gen_tcp:connect("localhost", 1180, Options, 2000), + _Data = receive_data(Socket), + ok = send_data(login_command(), Socket), + _LoginResponse = receive_data(Socket), + PollCommand = + <<"\n" + "\n" + "\n" + "\n" + "foo bar baz\n" + "\n" + "\n">>, + ok = send_data(PollCommand, Socket), + PollResponse = receive_data(Socket), + match_data(PollResponse, + "Command completed successfully; no messages"), + ok. + +%% Sending an invalid command frame should close the connection. +%% It also crashes the process. +invalid_command_test_case(Config) -> + Options = proplists:get_value(tcp_options, Config), + {ok, Socket} = gen_tcp:connect("localhost", 1180, Options, 2000), + _Data = receive_data(Socket), + ok = send_data(login_command(), Socket), + _LoginResponse = receive_data(Socket), + InvalidCommand = + <<"\n" + "\n" + "\n" + "\n" + "foo bar baz\n" + "\n" + "\n">>, + ok = send_data(InvalidCommand, Socket), + {error, closed} = receive_data(Socket), + ok. + +error_test_case(Config) -> + Options = proplists:get_value(tcp_options, Config), + {ok, Socket} = gen_tcp:connect("localhost", 1180, Options, 2000), + _Data = receive_data(Socket), + ok = send_data(login_command(), Socket), + _LoginResponse = receive_data(Socket), + InvalidXml = + <<"\n">>, + ok = send_data(InvalidXml, Socket), + ErrorResponse = receive_data(Socket), + match_data(ErrorResponse, + "Command syntax error."), + ok. + +%% Helper functions: +length_of_data(Data) -> + EPPEnvelope = binary:part(Data, {0, 4}), + ReportedLength = binary:decode_unsigned(EPPEnvelope, big), + ReportedLength. + +send_data(Message, Socket) -> + Length = epp_util:frame_length_to_send(Message), + ByteSize = <>, + CompleteMessage = <>, + ok = gen_tcp:send(Socket, CompleteMessage). + +receive_data(Socket) -> + case gen_tcp:recv(Socket, 0, 1200) of + {error, Reason} -> {error, Reason}; + {ok, Data } -> + EppEnvelope = binary:part(Data, {0, 4}), + ReportedLength = binary:decode_unsigned(EppEnvelope, big), + binary:part(Data, {byte_size(Data), 4 - ReportedLength}) + end. + +match_data(Data, Pattern) -> + {ok, MatchPattern} = re:compile(Pattern), + {match, _Captured} = re:run(Data, MatchPattern). + +login_command() -> + <<"\n" + "\n" + "\n" + "\n" + "test_bestnames\n" + "testtest\n" + "\n" + "1.0\n" + "en\n" + "\n" + "\n" + "https://epp.tld.ee/schema/domain-eis-1.0.xsd\n" + "https://epp.tld.ee/schema/contact-ee-1.1.xsd\n" + "urn:ietf:params:xml:ns:host-1.0\n" + "urn:ietf:params:xml:ns:keyrelay-1.0\n" + "\n" + "\n" + "\n" + "\n">>. diff --git a/config/test.config b/config/test.config index 6b9b707..921619e 100644 --- a/config/test.config +++ b/config/test.config @@ -1,6 +1,6 @@ [ - {epp_proxy, [{dev_mode, false}, - {tcp_port, 3333}, + {epp_proxy, [{dev_mode, true}, + {tcp_port, 1180}, {tls_port, 1443}, {epp_session_url, "http://localhost:9292/session/"},