diff --git a/Makefile.in b/Makefile.in index a663f9a85..0ae51b612 100644 --- a/Makefile.in +++ b/Makefile.in @@ -252,6 +252,9 @@ dialyzer: plt --get_warnings -o dialyzer.log ebin test: + @echo "************************** NOTICE ***************************************" + @cat test/README + @echo "*************************************************************************" $(REBAR) skip_deps=true ct .PHONY: src doc edoc dialyzer Makefile TAGS clean clean-rel distclean rel plt \ diff --git a/test/README b/test/README new file mode 100644 index 000000000..c82b791bf --- /dev/null +++ b/test/README @@ -0,0 +1,15 @@ +You need MySQL and PostgreSQL up and running. +Both of them should grant access to user 'ejabberd_test' with +password 'ejabberd_test' on database 'ejabberd_test'. + +Here is a quick setup example: + +$ psql template1 +template1=# CREATE USER ejabberd_test WITH PASSWORD 'ejabberd_test'; +template1=# CREATE DATABASE ejabberd_test; +template1=# GRANT ALL PRIVILEGES ON DATABASE ejabberd_test TO ejabberd_test; + +$ mysql +mysql> CREATE USER ejabberd_test IDENTIFIED BY 'ejabberd_test'; +mysql> CREATE DATABASE ejabberd_test; +mysql> GRANT ALL ON ejabberd_test.* TO ejabberd_test; diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index baa1e39f2..05c7db275 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -65,12 +65,19 @@ end end)()). +-define(COMMON_VHOST, <<"localhost">>). +-define(MNESIA_VHOST, <<"mnesia.localhost">>). +-define(MYSQL_VHOST, <<"mysql.localhost">>). +-define(PGSQL_VHOST, <<"pgsql.localhost">>). + suite() -> [{timetrap, {seconds,10}}]. init_per_suite(Config) -> DataDir = proplists:get_value(data_dir, Config), PrivDir = proplists:get_value(priv_dir, Config), + [_, _|Tail] = lists:reverse(filename:split(DataDir)), + BaseDir = filename:join(lists:reverse(Tail)), ConfigPath = filename:join([DataDir, "ejabberd.cfg"]), LogPath = filename:join([PrivDir, "ejabberd.log"]), SASLPath = filename:join([PrivDir, "sasl.log"]), @@ -83,10 +90,12 @@ init_per_suite(Config) -> application:set_env(sasl, sasl_error_logger, {file, SASLPath}), application:set_env(mnesia, dir, MnesiaDir), ok = application:start(ejabberd), - [{server, <<"localhost">>}, - {port, 5222}, - {host, "localhost"}, + [{server_port, 5222}, + {server_host, "localhost"}, + {server, ?COMMON_VHOST}, + {user, <<"test_single">>}, {certfile, CertFile}, + {base_dir, BaseDir}, {resource, <<"resource">>}, {password, <<"password">>} |Config]. @@ -94,20 +103,47 @@ init_per_suite(Config) -> end_per_suite(_Config) -> ok. +init_per_group(no_db, Config) -> + User = ?config(user, Config), + Server = ?config(server, Config), + Password = ?config(password, Config), + {atomic, ok} = ejabberd_auth:try_register(User, Server, Password), + Config; +init_per_group(mnesia, Config) -> + set_opt(server, ?MNESIA_VHOST, Config); +init_per_group(mysql, Config) -> + case catch ejabberd_odbc:sql_query(?MYSQL_VHOST, [<<"select 1;">>]) of + {selected, _, _} -> + create_sql_tables(mysql, ?config(base_dir, Config)), + set_opt(server, ?MYSQL_VHOST, Config); + Err -> + {skip, {mysql_not_available, Err}} + end; +init_per_group(pgsql, Config) -> + case catch ejabberd_odbc:sql_query(?PGSQL_VHOST, [<<"select 1;">>]) of + {selected, _, _} -> + create_sql_tables(pgsql, ?config(base_dir, Config)), + set_opt(server, ?PGSQL_VHOST, Config); + Err -> + {skip, {pgsql_not_available, Err}} + end; init_per_group(_GroupName, Config) -> Pid = start_event_relay(), set_opt(event_relay, Pid, Config). +end_per_group(mnesia, _Config) -> + ok; +end_per_group(mysql, _Config) -> + ok; +end_per_group(pgsql, _Config) -> + ok; +end_per_group(no_db, _Config) -> + ok; end_per_group(_GroupName, Config) -> stop_event_relay(Config), ok. -init_per_testcase(stop_ejabberd, OrigConfig) -> - User = <<"test_stop">>, - Config = set_opt(user, User, OrigConfig), - ejabberd_auth:try_register(User, - ?config(server, Config), - ?config(password, Config)), +init_per_testcase(stop_ejabberd, Config) -> open_session(bind(auth(connect(Config)))); init_per_testcase(TestCase, OrigConfig) -> subscribe_to_events(OrigConfig), @@ -155,49 +191,58 @@ init_per_testcase(TestCase, OrigConfig) -> end_per_testcase(_TestCase, _Config) -> ok. -groups() -> - [{single_user, [sequence], +generic_tests() -> + [{generic, [sequence], [test_connect, test_starttls, test_zlib, - test_register, - auth_plain, - auth_md5, test_auth, test_bind, test_open_session, - roster_get, - presence_broadcast, + presence, ping, version, time, stats, - disco, + disco]}, + {test_proxy65, [parallel], + [proxy65_master, proxy65_slave]}]. + +tests() -> + [{single_user, [sequence], + [test_register, + auth_plain, + auth_md5, + presence_broadcast, last, + roster_get, private, privacy, blocking, vcard, - pubsub, muc_single, + pubsub, test_unregister]}, {test_roster_subscribe, [parallel], [roster_subscribe_master, roster_subscribe_slave]}, - {test_proxy65, [parallel], - [proxy65_master, proxy65_slave]}, {test_offline, [sequence], [offline_master, offline_slave]}, {test_roster_remove, [parallel], [roster_remove_master, roster_remove_slave]}]. +groups() -> + [{no_db, [sequence], generic_tests()}, + {mnesia, [sequence], tests()}, + {mysql, [sequence], tests()}, + {pgsql, [sequence], tests()}]. + all() -> - [{group, single_user}, - {group, test_roster_subscribe}, - {group, test_proxy65}, - {group, test_offline}, - {group, test_roster_remove}, + [{group, no_db}, + {group, mnesia}, + {group, mysql}, + {group, pgsql}, stop_ejabberd]. stop_ejabberd(Config) -> @@ -211,8 +256,8 @@ test_connect(Config) -> connect(Config) -> {ok, Sock} = ejabberd_socket:connect( - ?config(host, Config), - ?config(port, Config), + ?config(server_host, Config), + ?config(server_port, Config), [binary, {packet, 0}, {active, false}]), init_stream(set_opt(socket, Sock, Config)). @@ -362,6 +407,12 @@ roster_get(Config) -> send_recv(Config, #iq{type = get, sub_els = [#roster{}]}), disconnect(Config). +presence(Config) -> + send(Config, #presence{}), + JID = my_jid(Config), + #presence{from = JID, to = JID} = recv(), + disconnect(Config). + presence_broadcast(Config) -> send(Config, #presence{}), JID = my_jid(Config), @@ -778,8 +829,7 @@ proxy65_master(Config) -> Peer = ?config(slave, Config), wait_for_slave(Config), send(Config, #presence{}), - ?recv2(#presence{from = MyJID, type = undefined}, - #presence{from = Peer, type = undefined}), + #presence{from = MyJID, type = undefined} = recv(), true = is_feature_advertised(Config, ?NS_BYTESTREAMS, Proxy), #iq{type = result, sub_els = [#bytestreams{hosts = [StreamHost]}]} = send_recv( @@ -795,7 +845,7 @@ proxy65_master(Config) -> #iq{type = set, to = Proxy, sub_els = [#bytestreams{activate = Peer, sid = SID}]}), socks5_send(Socks5, Data), - #presence{type = unavailable, from = Peer} = recv(), + %%#presence{type = unavailable, from = Peer} = recv(), disconnect(Config). proxy65_slave(Config) -> @@ -804,7 +854,6 @@ proxy65_slave(Config) -> send(Config, #presence{}), #presence{from = MyJID, type = undefined} = recv(), wait_for_master(Config), - #presence{from = Peer, type = undefined} = recv(), {StreamHost, SID, Data} = get_event(Config), Socks5 = socks5_connect(StreamHost, {SID, Peer, MyJID}), wait_for_master(Config), @@ -1216,3 +1265,78 @@ insert(Val, N, Tuple) -> L = tuple_to_list(Tuple), {H, T} = lists:split(N-1, L), list_to_tuple(H ++ [Val|T]). + +%%%=================================================================== +%%% SQL stuff +%%%=================================================================== +create_sql_tables(Type, BaseDir) -> + {VHost, File} = case Type of + mysql -> + {?MYSQL_VHOST, "mysql.sql"}; + pgsql -> + {?PGSQL_VHOST, "pg.sql"} + end, + SQLFile = filename:join([BaseDir, "sql", File]), + CreationQueries = read_sql_queries(SQLFile), + DropTableQueries = drop_table_queries(CreationQueries), + case ejabberd_odbc:sql_transaction( + VHost, DropTableQueries ++ CreationQueries) of + {atomic, ok} -> + ok; + Err -> + ct:fail({failed_to_create_sql_tables, Type, Err}) + end. + +read_sql_queries(File) -> + case file:open(File, [read, binary]) of + {ok, Fd} -> + read_lines(Fd, File, []); + Err -> + ct:fail({open_file_failed, File, Err}) + end. + +drop_table_queries(Queries) -> + lists:foldl( + fun(Query, Acc) -> + case split(str:to_lower(Query)) of + [<<"create">>, <<"table">>, Table|_] -> + [<<"DROP TABLE IF EXISTS ", Table/binary, ";">>|Acc]; + _ -> + Acc + end + end, [], Queries). + +read_lines(Fd, File, Acc) -> + case file:read_line(Fd) of + {ok, Line} -> + NewAcc = case str:strip(str:strip(Line, both, $\r), both, $\n) of + <<"--", _/binary>> -> + Acc; + <<>> -> + Acc; + _ -> + [Line|Acc] + end, + read_lines(Fd, File, NewAcc); + eof -> + QueryList = str:tokens(list_to_binary(lists:reverse(Acc)), <<";">>), + lists:flatmap( + fun(Query) -> + case str:strip(str:strip(Query, both, $\r), both, $\n) of + <<>> -> + []; + Q -> + [<>] + end + end, QueryList); + {error, _} = Err -> + ct:fail({read_file_failed, File, Err}) + end. + +split(Data) -> + lists:filter( + fun(<<>>) -> + false; + (_) -> + true + end, re:split(Data, <<"\s">>)). diff --git a/test/ejabberd_SUITE_data/ejabberd.cfg b/test/ejabberd_SUITE_data/ejabberd.cfg index bf7839e13..c104d9c4e 100644 --- a/test/ejabberd_SUITE_data/ejabberd.cfg +++ b/test/ejabberd_SUITE_data/ejabberd.cfg @@ -1,5 +1,5 @@ {loglevel, 4}. -{hosts, ["localhost"]}. +{hosts, ["localhost", "mnesia.localhost", "mysql.localhost", "pgsql.localhost"]}. {define_macro, 'CERTFILE', "cert.pem"}. {listen, [ @@ -18,8 +18,6 @@ captcha ]} ]}. -{define_macro, 'DB_TYPE', internal}. -{auth_method, 'DB_TYPE'}. {shaper, normal, {maxrate, 1000}}. {shaper, fast, {maxrate, 50000}}. {max_fsm_queue, 1000}. @@ -44,35 +42,79 @@ {modules, [ {mod_adhoc, []}, - {mod_announce, [{db_type, 'DB_TYPE'}]}, - {mod_blocking, [{db_type, 'DB_TYPE'}]}, - {mod_caps, [{db_type, 'DB_TYPE'}]}, {mod_configure, []}, {mod_disco, []}, - {mod_last, [{db_type, 'DB_TYPE'}]}, - {mod_muc, []}, - {mod_offline, [{db_type, 'DB_TYPE'}]}, {mod_ping, []}, - {mod_privacy, [{db_type, 'DB_TYPE'}]}, - {mod_private, [{db_type, 'DB_TYPE'}]}, {mod_proxy65, []}, - {mod_pubsub, [ - {access_createnode, pubsub_createnode}, - {ignore_pep_from_offline, true}, - %%{ignore_pep_from_offline, false}, - {last_item_cache, false}, - {plugins, ["flat", "hometree", "pep", "public", - "private", "mb"]} - ]}, {mod_register, [ {welcome_message, {"Welcome!", - "Hi.\nWelcome to this XMPP server."}} + "Hi.\nWelcome to this XMPP server."}} ]}, - {mod_roster, [{db_type, 'DB_TYPE'}]}, {mod_stats, []}, {mod_time, []}, - {mod_vcard, [{db_type, 'DB_TYPE'}]}, {mod_version, []} +]}. +{host_config, "localhost", [{auth_method, internal}]}. +{host_config, "mnesia.localhost", + [{auth_method, internal}, + {{add, modules}, [{mod_announce, [{db_type, internal}]}, + {mod_blocking, [{db_type, internal}]}, + {mod_caps, [{db_type, internal}]}, + {mod_last, [{db_type, internal}]}, + {mod_muc, [{db_type, internal}]}, + {mod_offline, [{db_type, internal}]}, + {mod_privacy, [{db_type, internal}]}, + {mod_private, [{db_type, internal}]}, + {mod_pubsub, [{access_createnode, pubsub_createnode}, + {ignore_pep_from_offline, true}, + {last_item_cache, false}, + {plugins, ["flat", "hometree", "pep"]}]}, + {mod_roster, [{db_type, internal}]}, + {mod_vcard, [{db_type, internal}]}]} + ]}. +{host_config, "mysql.localhost", + [{auth_method, odbc}, + {odbc_pool_size, 1}, + {odbc_server, {mysql, "localhost", "ejabberd_test", + "ejabberd_test", "ejabberd_test"}}, + {{add, modules}, [{mod_announce, [{db_type, odbc}]}, + {mod_blocking, [{db_type, odbc}]}, + {mod_caps, [{db_type, odbc}]}, + {mod_last, [{db_type, odbc}]}, + {mod_muc, [{db_type, odbc}]}, + {mod_offline, [{db_type, odbc}]}, + {mod_privacy, [{db_type, odbc}]}, + {mod_private, [{db_type, odbc}]}, + {mod_pubsub_odbc, [{access_createnode, pubsub_createnode}, + {ignore_pep_from_offline, true}, + {last_item_cache, false}, + {plugins, ["flat_odbc", + "hometree_odbc", + "pep_odbc"]}]}, + {mod_roster, [{db_type, odbc}]}, + {mod_vcard, [{db_type, odbc}]}]} + ]}. +{host_config, "pgsql.localhost", + [{auth_method, odbc}, + {odbc_pool_size, 1}, + {odbc_server, {pgsql, "localhost", "ejabberd_test", + "ejabberd_test", "ejabberd_test"}}, + {{add, modules}, [{mod_announce, [{db_type, odbc}]}, + {mod_blocking, [{db_type, odbc}]}, + {mod_caps, [{db_type, odbc}]}, + {mod_last, [{db_type, odbc}]}, + {mod_muc, [{db_type, odbc}]}, + {mod_offline, [{db_type, odbc}]}, + {mod_privacy, [{db_type, odbc}]}, + {mod_private, [{db_type, odbc}]}, + {mod_pubsub_odbc, [{access_createnode, pubsub_createnode}, + {ignore_pep_from_offline, true}, + {last_item_cache, false}, + {plugins, ["flat_odbc", + "hometree_odbc", + "pep_odbc"]}]}, + {mod_roster, [{db_type, odbc}]}, + {mod_vcard, [{db_type, odbc}]}]} ]}. %%% Local Variables: