diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 13d9e04..97e79f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,4 +29,4 @@ jobs: - run: make test - run: make ct - run: make dialyzer - if: ${{ matrix.otp == '27' }} + if: ${{ matrix.otp_vsn == '27' }} diff --git a/src/escalus.app.src b/src/escalus.app.src index e43c97e..dd87cd5 100644 --- a/src/escalus.app.src +++ b/src/escalus.app.src @@ -6,6 +6,7 @@ {applications, [ kernel, stdlib, + public_key, ssl, exml, gun, diff --git a/src/escalus.erl b/src/escalus.erl index 04efab4..553868a 100644 --- a/src/escalus.erl +++ b/src/escalus.erl @@ -136,46 +136,60 @@ story(Config, ResourceCounts, Story) -> %% Assertions +-spec assert(atom(), term()) -> ok | no_return(). assert(PredSpec, Arg) -> escalus_new_assert:assert(PredSpec, Arg). +-spec assert(atom(), [term()], term()) -> ok | no_return(). assert(PredSpec, Params, Arg) -> escalus_new_assert:assert(PredSpec, Params, Arg). +-spec assert_many([atom()], [exml:element()]) -> ok | no_return(). assert_many(Predicates, Stanzas) -> escalus_new_assert:assert_many(Predicates, Stanzas). %% Client API +-spec send(client(), exml:element()) -> ok. send(Client, Packet) -> escalus_client:send(Client, Packet). +-spec send_and_wait(client(), exml:element()) -> exml:element(). send_and_wait(Client, Packet) -> escalus_client:send_and_wait(Client, Packet). +-spec wait_for_stanza(client()) -> exml:element(). wait_for_stanza(Client) -> escalus_client:wait_for_stanza(Client). +-spec wait_for_stanza(client(), timeout()) -> exml:element(). wait_for_stanza(Client, Timeout) -> escalus_client:wait_for_stanza(Client, Timeout). +-spec wait_for_stanzas(client(), non_neg_integer()) -> [exml:element()]. wait_for_stanzas(Client, Count) -> escalus_client:wait_for_stanzas(Client, Count). +-spec wait_for_stanzas(client(), non_neg_integer(), timeout()) -> [exml:element()]. wait_for_stanzas(Client, Count, Timeout) -> escalus_client:wait_for_stanzas(Client, Count, Timeout). +-spec peek_stanzas(client()) -> [exml:element()]. peek_stanzas(Client) -> escalus_client:peek_stanzas(Client). +-spec send_iq_and_wait_for_result(client(), exml:element()) -> exml:element() | no_return(). send_iq_and_wait_for_result(Client, Iq) -> escalus_client:send_iq_and_wait_for_result(Client, Iq). +-spec send_iq_and_wait_for_result(client(), exml:element(), timeout()) -> + exml:element() | no_return(). send_iq_and_wait_for_result(Client, Iq, Timeout) -> escalus_client:send_iq_and_wait_for_result(Client, Iq, Timeout). %% Other functions +-spec override(config(), atom(), {atom(), atom()}) -> config(). override(Config, OverrideName, NewValue) -> escalus_overridables:override(Config, OverrideName, NewValue). diff --git a/src/escalus_assert.erl b/src/escalus_assert.erl index cdc2e9c..ed0cba0 100644 --- a/src/escalus_assert.erl +++ b/src/escalus_assert.erl @@ -15,6 +15,7 @@ %%============================================================================== -module(escalus_assert). +-compile(nowarn_missing_spec). -export([is_chat_message/2, has_no_stanzas/1, diff --git a/src/escalus_bosh.erl b/src/escalus_bosh.erl index f7eb829..a49a35e 100644 --- a/src/escalus_bosh.erl +++ b/src/escalus_bosh.erl @@ -412,8 +412,8 @@ handle_info({http_reply, Ref, Body, _Transport} = HttpReply, {_, true} -> S1 = handle_http_reply(Ref, XmlBody, S0, Timestamp), S1#state{ pending_replies = [] }; - {{value, {Ref, _Rid, _Pid}}, _} -> - {{value, {Ref, _Rid, _Pid}}, NewRequests} = queue:out(S0#state.requests), + {{value, {Ref, Rid, Pid}}, _} -> + {{value, {Ref, Rid, Pid}}, NewRequests} = queue:out(S0#state.requests), S1 = handle_http_reply(Ref, XmlBody, S0#state{ requests = NewRequests }, Timestamp), lists:foreach(fun(PendingReply) -> self() ! PendingReply end, S1#state.pending_replies), diff --git a/src/escalus_bosh_gun.erl b/src/escalus_bosh_gun.erl index f4dccda..65caa55 100644 --- a/src/escalus_bosh_gun.erl +++ b/src/escalus_bosh_gun.erl @@ -11,8 +11,7 @@ handle_call/3, handle_cast/2, handle_info/2, - terminate/2, - code_change/3]). + terminate/2]). -record(state, {destination, options, @@ -28,9 +27,11 @@ start_link(Args) -> gen_server:start_link(?MODULE, [Args], []). +-spec stop(pid()) -> ok. stop(Pool) -> gen_server:cast(Pool, stop). +-spec request(pid(), iodata(), gun:req_headers(), iodata()) -> term(). request(Pool, Path, Hdrs, Body) -> case get_client(Pool) of {error, _} = Error -> @@ -62,6 +63,8 @@ init([Args]) -> queue = queue:new() }, 0}. +-spec handle_call(get_client, gen_server:from(), state()) -> + {reply, term(), state()} | {noreply, state()}. handle_call(get_client, _From, State = #state{free = [Client | Free], busy = Busy}) -> {reply, Client, State#state{free = Free, @@ -83,6 +86,8 @@ handle_call(get_client, From, State = #state{free = [], when M == T -> {noreply, State#state{queue = queue:in(From, Queue)}}. +-spec handle_cast({free_client, pid()} | stop, state()) -> + {noreply, state()} | {stop, term(), state()}. handle_cast({free_client, Pid}, State = #state{free = Free, busy = Busy, queue = Queue}) -> @@ -98,6 +103,7 @@ handle_cast({free_client, Pid}, State = #state{free = Free, handle_cast(stop, State) -> {stop, normal, State}. +-spec handle_info(term(), state()) -> {noreply, state()}. handle_info({'EXIT', From, _Reason}, State = #state{free = Free, busy = Busy, total = Total}) -> @@ -113,14 +119,12 @@ handle_info(_Info, State) -> ct:pal("Unknown Info in bosh_gun: ~p", [_Info]), {noreply, State}. +-spec terminate(term(), state()) -> ok. terminate(_Reason, #state{free = Free, busy = Busy}) -> [gun:close(F) || F <- Free], [gun:close(B) || B <- Busy], ok. -code_change(_OldVsn, State, _Extra) -> - {ok, State}. - connect({Host, Port}, Options) -> {ok, Pid} = gun:open(Host, Port, Options#{protocols => [http]}), {ok, http} = gun:await_up(Pid), diff --git a/src/escalus_compat.erl b/src/escalus_compat.erl index f6e0cc6..8d00081 100644 --- a/src/escalus_compat.erl +++ b/src/escalus_compat.erl @@ -31,6 +31,7 @@ %% Public API %%-------------------------------------------------------------------- +-spec bin(binary() | string() | atom() | integer()) -> binary() | no_return(). bin(Arg) when is_binary(Arg) -> Arg; bin(Arg) when is_list(Arg) -> @@ -46,17 +47,21 @@ bin(Other) -> type_complain("???", Other), error(badarg, [Other]). +-spec deprecated(atom(), atom(), T) -> T. deprecated(Old, New, Result) -> error_logger:info_msg("calling deprecated function ~p, use ~p instead~n~p~n", [Old, New, backtrace(1)]), Result. +-spec unimplemented() -> no_return(). unimplemented() -> throw({unimplemented, backtrace(1)}). +-spec complain(term()) -> ok. complain(What) -> error_logger:info_msg("~s at ~p~n", [What, backtrace(1)]). +-spec backtrace(non_neg_integer()) -> list(). backtrace(N) -> {current_stacktrace, Stacktrace} = erlang:process_info(self(), current_stacktrace), lists:nthtail(N + 1, Stacktrace). diff --git a/src/escalus_component.erl b/src/escalus_component.erl index 37b1133..c1dd981 100644 --- a/src/escalus_component.erl +++ b/src/escalus_component.erl @@ -153,6 +153,7 @@ handle_info(Info, #component_state{module = M, client = C, user_state = S} = Sta {noreply, NewState, ?WAIT_AFTER_STANZA}. +-spec terminate(atom(), state()) -> any(). terminate(Reason, #component_state{client = C, module = M, user_state = S}) -> catch escalus_connection:stop(C), case erlang:function_exported(M, terminate, 2) of diff --git a/src/escalus_connection.erl b/src/escalus_connection.erl index 1a69cbf..474922d 100644 --- a/src/escalus_connection.erl +++ b/src/escalus_connection.erl @@ -430,6 +430,7 @@ upgrade_to_tls(#client{module = Mod, rcv_pid = Pid, props = Props}) -> SSLOpts = proplists:get_value(ssl_opts, Props, DefSslOpts), Mod:upgrade_to_tls(Pid, SSLOpts). +-spec wait_for_close(client()) -> boolean(). wait_for_close(Client) -> wait_for_close(Client, default_timeout()). @@ -476,6 +477,8 @@ maybe_forward_to_owner(_, State, Stanzas, Fun, Timestamp) -> stanza_msg(Stanza, Metadata) -> {stanza, self(), Stanza, Metadata}. +-spec separate_ack_requests({boolean(), non_neg_integer(), term()}, [exml_stream:element()]) -> + {{boolean(), non_neg_integer(), term()}, [exml_stream:element()], [exml_stream:element()]}. separate_ack_requests({false, H0, A}, Stanzas) -> %% Don't keep track of H {{false, H0, A}, [], Stanzas}; diff --git a/src/escalus_ct.erl b/src/escalus_ct.erl index a32e1cb..0d51332 100644 --- a/src/escalus_ct.erl +++ b/src/escalus_ct.erl @@ -163,5 +163,6 @@ ct_log_timestamp({MS, S, US}) -> "~2.10.0B:~2.10.0B:~2.10.0B.~3.10.0B", [Year, Month, Day, Hour, Min, Sec, MilliSec])). +-spec log_error(term(), [any()]) -> ok. log_error(Format, Args) -> ct:pal(error, Format, Args). diff --git a/src/escalus_ejabberd.erl b/src/escalus_ejabberd.erl index 96be561..6c80ca9 100644 --- a/src/escalus_ejabberd.erl +++ b/src/escalus_ejabberd.erl @@ -53,21 +53,26 @@ %%% Business API %%% +-spec rpc(atom(), atom(), [any()], timeout()) -> any(). rpc(M, F, A, Timeout) -> Node = escalus_ct:get_config(ejabberd_node), Cookie = escalus_ct:get_config(ejabberd_cookie), escalus_rpc:call(Node, M, F, A, Timeout, Cookie). +-spec rpc(atom(), atom(), [any()]) -> any(). rpc(M, F, A) -> rpc(M, F, A, 3000). +-spec remote_display(string()) -> true. remote_display(String) -> Line = [$\n, [$- || _ <- String], $\n], remote_format("~s~s~s", [Line, String, Line]). +-spec remote_format(string()) -> true. remote_format(Format) -> remote_format(Format, []). +-spec remote_format(string(), [any()]) -> true. remote_format(Format, Args) -> group_leader(rpc(erlang, whereis, [user]), self()), io:format(Format, Args), @@ -106,14 +111,17 @@ with_local_option(Option, Value, Fun) -> end, lists:zip(Hosts, OldValues)) end. -get_c2s_status(#client{jid=Jid}) -> +-spec get_c2s_status(escalus:client()) -> term(). +get_c2s_status(#client{jid = Jid}) -> {match, USR} = re:run(Jid, <<"([^@]*)@([^/]*)/(.*)">>, [{capture, all_but_first, list}]), Pid = rpc(ejabberd_sm, get_session_pid, USR), rpc(sys, get_status, [Pid]). +-spec wait_for_session_count(escalus:config(), non_neg_integer()) -> ok | no_return(). wait_for_session_count(Config, Count) -> wait_for_session_count(Config, Count, 0). +-spec get_remote_sessions(escalus:config()) -> term(). get_remote_sessions(Config) -> escalus_overridables:do(Config, get_remote_sessions, [], {?MODULE, default_get_remote_sessions}). @@ -203,8 +211,13 @@ reset_option({Option, _, Set, _}, Config) -> %% escalus_user_db callbacks %%-------------------------------------------------------------------- -start(_) -> ok. -stop(_) -> ok. +-spec start(_) -> ok. +start(_) -> + ok. + +-spec stop(_) -> ok. +stop(_) -> + ok. -spec create_users(escalus:config(), [escalus_users:named_user()]) -> escalus:config(). create_users(Config, Users) -> @@ -220,11 +233,17 @@ delete_users(Config, Users) -> %% escalus_server callbacks %%-------------------------------------------------------------------- -pre_story(Config) -> Config. +-spec pre_story(escalus:config()) -> escalus:config(). +pre_story(Config) -> + Config. -post_story(Config) -> Config. +-spec post_story(escalus:config()) -> escalus:config(). +post_story(Config) -> + Config. -name() -> ?MODULE. +-spec name() -> atom(). +name() -> + ?MODULE. %%-------------------------------------------------------------------- %% Helpers @@ -245,16 +264,20 @@ unregister_user(Config, {_UserName, UserSpec}) -> [U, S, _P] = USP, rpc(ejabberd_admin, unregister, [U, S], 30000). +-spec default_get_remote_sessions() -> any(). default_get_remote_sessions() -> rpc(ejabberd_sm, get_full_session_list, []). +-spec legacy_get_remote_sessions() -> any(). legacy_get_remote_sessions() -> rpc(ejabberd_sm, dirty_get_sessions_list, []). +-spec unify_str_arg(any()) -> any(). unify_str_arg(Arg) -> StrFormat = escalus_ct:get_config(ejabberd_string_format), unify_str_arg(Arg, StrFormat). +-spec unify_str_arg(any(), str | string()) -> any(). unify_str_arg(Arg, str) when is_binary(Arg) -> binary_to_list(Arg); unify_str_arg(Arg, _) -> diff --git a/src/escalus_event.erl b/src/escalus_event.erl index 4cf2e61..156a53c 100644 --- a/src/escalus_event.erl +++ b/src/escalus_event.erl @@ -22,7 +22,6 @@ -include_lib("exml/include/exml.hrl"). --type config() :: escalus_config:config(). -type event_client() :: list({atom(), any()}). -type manager() :: pid(). -type resource() :: binary(). @@ -41,18 +40,23 @@ add_handler(Mgr, Handler, Args) -> delete_handler(Mgr, Handler, Args) -> gen_event:delete_handler(Mgr, Handler, Args). +-spec incoming_stanza(event_client(), exml_stream:element()) -> ok. incoming_stanza(Client, Stanza) -> notify_stanza(Client, incoming_stanza, Stanza). +-spec pop_incoming_stanza(event_client(), exml_stream:element()) -> ok. pop_incoming_stanza(Client, Stanza) -> notify_stanza(Client, pop_incoming_stanza, Stanza). +-spec outgoing_stanza(event_client(), exml_stream:element()) -> ok. outgoing_stanza(Client, Stanza) -> notify_stanza(Client, outgoing_stanza, Stanza). +-spec story_start(escalus_config:config()) -> ok. story_start(Config) -> gen_event:notify(manager(Config), story_start). +-spec story_end(escalus_config:config()) -> ok. story_end(Config) -> gen_event:notify(manager(Config), story_end). @@ -60,21 +64,23 @@ story_end(Config) -> %% ==================================================================== %% @doc Start the event manager -%% @end +-spec start(escalus_config:config()) -> escalus_config:config(). start(Config) -> {ok, Mgr} = gen_event:start_link(), add_handler(Mgr, escalus_history_h, []), [{escalus_event_mgr, Mgr} | Config]. %% @doc Stop the event manager -%% @end +-spec stop(escalus_config:config()) -> escalus_config:config(). stop(Config) -> gen_event:stop(manager(Config)), Config. +-spec get_history(escalus_config:config()) -> [term()]. get_history(Config) -> escalus_history_h:get_history(manager(Config)). +-spec print_history(escalus_config:config()) -> ok. print_history(Config) -> CaseName = proplists:get_value(tc_name, Config), PrivDir = proplists:get_value(priv_dir, Config), @@ -179,7 +185,7 @@ manager(Config) -> %% @doc Create a new event emitter. -spec new_client(Config, User, MaybeResource) -> undefined | EventClient when - Config :: config(), + Config :: escalus_config:config(), User :: escalus_users:user_name() | escalus_users:user_spec(), MaybeResource :: undefined | resource(), EventClient :: event_client(). @@ -206,7 +212,6 @@ new_client_1(Mgr, UserSpec, Resource) -> %% @doc Notify the event system of an event %%
The system accepts any term as the event.
-%% @end notify_stanza(undefined, _, _) -> ok; notify_stanza(Client, EventName, Stanza) -> diff --git a/src/escalus_fresh.erl b/src/escalus_fresh.erl index 7a89423..0e62292 100644 --- a/src/escalus_fresh.erl +++ b/src/escalus_fresh.erl @@ -117,9 +117,12 @@ create_fresh_user(Config, UserName) when is_atom(UserName) -> %%% Stateful API %%% Required if we expect to be able to clean up autogenerated users. +-spec start(escalus:config()) -> ok. start(_Config) -> application:ensure_all_started(worker_pool), ensure_table_present(nasty_global_table()). + +-spec stop(escalus:config()) -> ok | no_return(). stop(_) -> case whereis(nasty_global_table()) of undefined -> @@ -176,6 +179,7 @@ collect_deletion_results(Pending, Failed) -> %%% Internals nasty_global_table() -> escalus_fresh_db. +-spec work_on_deleting_users(term(), {term(), term()}, pid()) -> ok. work_on_deleting_users(Ord, {_Suffix, Conf} = _Item, CollectingPid) -> try do_delete_users(Conf) of _ -> diff --git a/src/escalus_history_h.erl b/src/escalus_history_h.erl index 7109876..c485847 100644 --- a/src/escalus_history_h.erl +++ b/src/escalus_history_h.erl @@ -1,4 +1,5 @@ -module(escalus_history_h). + -behaviour(gen_event). -export([get_history/1]). @@ -7,23 +8,26 @@ terminate/2, handle_info/2, handle_call/2, - handle_event/2, - code_change/3]). + handle_event/2]). -record(state, { events :: list() }). +-type state() :: #state{}. + -spec get_history(escalus_event:manager()) -> list(). get_history(Mgr) -> gen_event:call(Mgr, escalus_history_h, get_history). +-spec init([]) -> {ok, state()}. init([]) -> S = #state{ events = [] }, {ok, S}. +-spec handle_event(term(), state()) -> {ok, state()}. handle_event({incoming_stanza, Jid, Stanza}, State) -> {ok, save_stanza(incoming_stanza, Jid, Stanza, State)}; handle_event({outgoing_stanza, Jid, Stanza}, State) -> @@ -37,15 +41,15 @@ handle_event(story_end, State) -> handle_event(_Event, State) -> {ok, State}. +-spec handle_info(term(), state()) -> {ok, state()}. handle_info(_, State) -> {ok, State}. +-spec handle_call(get_history, state()) -> {ok, list(), state()}. handle_call(get_history, State=#state{events=Events}) -> {ok, lists:reverse(Events), State}. -code_change(_, _, State) -> - {ok, State}. - +-spec terminate(term(), state()) -> ok. terminate(_, _) -> ok. diff --git a/src/escalus_mongooseim.erl b/src/escalus_mongooseim.erl index 4478978..5cdc6a3 100644 --- a/src/escalus_mongooseim.erl +++ b/src/escalus_mongooseim.erl @@ -100,6 +100,7 @@ metric_type(Metric) -> [{_, Type, _} | _] = escalus_ejabberd:rpc(exometer, find_entries, [Metric]), Type. +-spec check_metric_change(T, [T]) -> [T]. check_metric_change({{Metric, {MinChange, MaxChange}}, Before, After}, Acc) -> Change = After - Before, case {Change < MinChange, Change > MaxChange} of diff --git a/src/escalus_new_assert.erl b/src/escalus_new_assert.erl index 9e572f4..1a6af6e 100644 --- a/src/escalus_new_assert.erl +++ b/src/escalus_new_assert.erl @@ -25,18 +25,21 @@ %% API functions %%============================================================================== +-spec assert(atom(), term()) -> ok | no_return(). assert(PredSpec, Arg) -> Fun = predspec_to_fun(PredSpec), StanzaStr = arg_to_list(Arg), assert_true(Fun(Arg), {assertion_failed, assert, PredSpec, Arg, StanzaStr}). +-spec assert(atom(), [term()], term()) -> ok | no_return(). assert(PredSpec, Params, Arg) -> Fun = predspec_to_fun(PredSpec, length(Params) + 1), StanzaStr = arg_to_list(Arg), assert_true(apply(Fun, Params ++ [Arg]), {assertion_failed, assert, PredSpec, Params, Arg, StanzaStr}). +-spec assert_many([atom()], [exml:element()]) -> ok | no_return(). assert_many(Predicates, Stanzas) -> AllStanzas = length(Predicates) == length(Stanzas), Ok = escalus_utils:mix_match(fun predspec_to_fun/1, Predicates, Stanzas), @@ -49,6 +52,7 @@ assert_many(Predicates, Stanzas) -> assert_true(Ok and AllStanzas, {assertion_failed, assert_many, AllStanzas, Predicates, Stanzas, StanzasStr}). +-spec mix_match([atom()], [exml:element()]) -> ok | no_return(). mix_match(Predicates, Stanzas) -> assert_many(Predicates, Stanzas). diff --git a/src/escalus_pred.erl b/src/escalus_pred.erl index 74ac412..e5b042c 100644 --- a/src/escalus_pred.erl +++ b/src/escalus_pred.erl @@ -110,8 +110,11 @@ %% Deprecation support %%-------------------------------------------------------------------- +-spec is_presence_stanza(any()) -> any(). ?DEPRECATED1(is_presence_stanza, is_presence). +-spec is_presence_type(any(), any()) -> any(). ?DEPRECATED2(is_presence_type, is_presence_with_type). +-spec is_result(any()) -> any(). ?DEPRECATED1(is_result, is_iq_result). %%-------------------------------------------------------------------- @@ -307,6 +310,7 @@ is_iq_set(Stanza) -> is_iq(<<"set">>, Stanza). -spec is_iq_get(exml:element()) -> boolean(). is_iq_get(Stanza) -> is_iq(<<"get">>, Stanza). +-spec is_iq_result_or_error(exml:element(), exml:element()) -> boolean(). is_iq_result_or_error(QueryStanza, ResultStanza) -> (is_iq_error(ResultStanza) orelse is_iq_result(ResultStanza)) andalso has_same_id(QueryStanza, ResultStanza). @@ -540,6 +544,7 @@ has_identity(Category, Type, Stanza) -> Idents). %% TODO: Remove as duplicates escalus_assert:has_no_stanzas/1 functionality. +-spec stanza_timeout(tuple()) -> boolean(). stanza_timeout(Arg) -> case element(1, Arg) of 'EXIT' -> @@ -671,8 +676,7 @@ is_bind_result(#xmlel{} = Stanza) -> %% Functors %%-------------------------------------------------------------------- -%% Not supported by erlang 15 :( -%%-spec 'not'( fun((...) -> boolean()) ) -> fun((...) -> boolean()). +-spec 'not'(fun((any()) -> boolean())) -> fun((any()) -> boolean()). 'not'(Pred) when is_function(Pred, 1) -> fun (Arg) -> not Pred(Arg) end; 'not'(Pred) when is_function(Pred, 2) -> diff --git a/src/escalus_pubsub_stanza.erl b/src/escalus_pubsub_stanza.erl index bd8bbe8..06febf0 100644 --- a/src/escalus_pubsub_stanza.erl +++ b/src/escalus_pubsub_stanza.erl @@ -173,10 +173,13 @@ get_user_subscriptions(User, Id, Node) -> end, pubsub_iq(<<"get">>, User, Id, NodeAddr, [Element]). +-spec get_subscription_options(escalus_utils:jid_spec(), binary(), {_, _}) -> exml:element(). get_subscription_options(User, Id, {NodeAddr, NodeName}) -> Element = subscription_options(NodeName, User), pubsub_iq(<<"get">>, User, Id, NodeAddr, [Element]). +-spec set_subscription_options(escalus_utils:jid_spec(), binary(), {_, _}, [tuple()]) -> + exml:element(). set_subscription_options(User, Id, {NodeAddr, NodeName}, Options) -> FormType = form_type_field_element(<<"subscribe_options">>), EncodedOptions = [FormType | lists:map(fun encode_form_field/1, Options)], @@ -283,22 +286,30 @@ purge_all_items(User, Id, {NodeAddr, NodeName}) -> %% Whole stanzas +-spec iq(binary(), escalus_utils:jid_spec(), binary(), pep | escalus_utils:jid_spec(), + [exml:cdata() | exml:element()]) -> exml:element(). iq(Type, From, Id, pep, Elements) -> Stanza = escalus_stanza:iq(Type, Elements), StanzaWithId = escalus_stanza:set_id(Stanza, Id), - escalus_stanza:from(StanzaWithId, escalus_utils:get_jid(From)); + escalus_stanza:from(StanzaWithId, From); iq(Type, From, Id, To, Elements) -> Stanza = escalus_stanza:iq(To, Type, Elements), StanzaWithId = escalus_stanza:set_id(Stanza, Id), - escalus_stanza:from(StanzaWithId, escalus_utils:get_jid(From)). + escalus_stanza:from(StanzaWithId, From). +-spec pubsub_iq(binary(), escalus_utils:jid_spec(), binary(), pep | escalus_utils:jid_spec(), + [exml:cdata() | exml:element()]) -> exml:element(). pubsub_iq(Type, User, Id, NodeAddr, Elements) -> pubsub_iq(Type, User, Id, NodeAddr, Elements, ?NS_PUBSUB). +-spec pubsub_iq(binary(), escalus_utils:jid_spec(), binary(), pep | escalus_utils:jid_spec(), + [exml:cdata() | exml:element()], binary()) -> exml:element(). pubsub_iq(Type, User, Id, NodeAddr, Elements, NS) -> PubSubElement = pubsub_element(Elements, NS), iq(Type, User, Id, NodeAddr, [PubSubElement]). +-spec pubsub_owner_iq(binary(), escalus_utils:jid_spec(), binary(), pep | escalus_utils:jid_spec(), + [exml:cdata() | exml:element()]) -> exml:element(). pubsub_owner_iq(Type, User, Id, NodeAddr, Elements) -> pubsub_iq(Type, User, Id, NodeAddr, Elements, ?NS_PUBSUB_OWNER). @@ -322,6 +333,7 @@ optional_form(FormName, NodeName, Type, Fields) -> create_node_element(NodeName) -> #xmlel{name = <<"create">>, attrs = #{<<"node">> => NodeName}}. +-spec pubsub_element([exml:cdata() | exml:element()], binary()) -> exml:element(). pubsub_element(Children, NS) -> #xmlel{name = <<"pubsub">>, attrs = #{<<"xmlns">> => NS}, diff --git a/src/escalus_rpc.erl b/src/escalus_rpc.erl index ab112c4..ebcb3dd 100644 --- a/src/escalus_rpc.erl +++ b/src/escalus_rpc.erl @@ -19,6 +19,7 @@ %% in a concurrent environment as it gets/sets the cookie %% with `erlang:get_cookie/0' and `erlang:set_cookie/1'. %% Interleaving these calls in concurrent processes is prone to race conditions. +-spec call(node(), module(), atom(), [term()], timeout(), atom()) -> term(). call(Node, Module, Function, Args, TimeOut, Cookie) -> call_with_cookie_match(Node, Module, Function, Args, TimeOut, Cookie). @@ -43,5 +44,5 @@ set_the_cookie([]) -> []; set_the_cookie(Cookie) -> Cookie0 = erlang:get_cookie(), - erlang:set_cookie(node(),Cookie), + erlang:set_cookie(node(), Cookie), Cookie0. diff --git a/src/escalus_server.erl b/src/escalus_server.erl index 47cc0b3..4bb0d39 100644 --- a/src/escalus_server.erl +++ b/src/escalus_server.erl @@ -33,9 +33,11 @@ pre_story(Config) -> post_story(Config) -> call_server(get_server(Config), post_story, [Config]). +-spec name(escalus:config()) -> any(). name(Config) -> call_server(get_server(Config), name, []). +-spec get_server(escalus:config()) -> any(). get_server(Config) -> escalus_config:get_config(escalus_xmpp_server, Config, undefined). diff --git a/src/escalus_stanza.erl b/src/escalus_stanza.erl index ce6b358..a2bdf03 100644 --- a/src/escalus_stanza.erl +++ b/src/escalus_stanza.erl @@ -86,7 +86,7 @@ search_iq/2]). %% XEP-0280: Message Carbons --export([carbons_disable/0,carbons_enable/0]). +-export([carbons_disable/0, carbons_enable/0]). %% XEP-0313: Message Archive Management -export([mam_archive_query/1, @@ -148,6 +148,7 @@ %% Stream - related functions %%-------------------------------------------------------------------- +-spec stream_start(binary(), binary()) -> exml_stream:start(). stream_start(Server, XMLNS) -> #xmlstreamstart{name = <<"stream:stream">>, attrs = #{<<"to">> => Server, @@ -156,43 +157,51 @@ stream_start(Server, XMLNS) -> <<"xmlns">> => XMLNS, <<"xmlns:stream">> => <<"http://etherx.jabber.org/streams">>}}. +-spec stream_end() -> exml_stream:stop(). stream_end() -> #xmlstreamend{name = <<"stream:stream">>}. +-spec ws_open(binary()) -> exml:element(). ws_open(Server) -> #xmlel{name= <<"open">>, attrs = #{<<"xmlns">> => <<"urn:ietf:params:xml:ns:xmpp-framing">>, <<"to">> => Server, <<"version">> => <<"1.0">>}}. -ws_close()-> +-spec ws_close() -> exml:element(). +ws_close() -> #xmlel{name= <<"close">>, attrs = #{<<"xmlns">> => <<"urn:ietf:params:xml:ns:xmpp-framing">>}}. +-spec starttls() -> exml:element(). starttls() -> #xmlel{name = <<"starttls">>, attrs = #{<<"xmlns">> => <<"urn:ietf:params:xml:ns:xmpp-tls">>}}. +-spec compress(binary()) -> exml:element(). compress(Method) -> #xmlel{name = <<"compress">>, attrs = #{<<"xmlns">> => <<"http://jabber.org/protocol/compress">>}, children = [#xmlel{name = <<"method">>, children = [#xmlcdata{content = Method}]}]}. --spec iq(binary(), [exml:element()]) -> exml:element(). +-spec iq(binary(), [exml:cdata() | exml:element()]) -> exml:element(). iq(Type, Body) -> #xmlel{name = <<"iq">>, attrs = #{<<"type">> => Type, <<"id">> => id()}, children = Body}. +-spec iq(escalus_utils:jid_spec(), binary(), [exml:cdata() | exml:element()]) -> exml:element(). iq(To, Type, Body) -> IQ = iq(Type, Body), - IQ#xmlel{attrs = maps:put(<<"to">>, To, IQ#xmlel.attrs)}. + to(IQ, To). %% slightly naughty, this isn't a stanza but it will go inside an