Code Monkey home page Code Monkey logo

escalus's Introduction

Escalus

Escalus is an Erlang XMPP client library. It began as a tool for convenient testing of XMPP servers, but can also be used as a standalone Erlang application.

Escalus is aimed at checking correctness of XMPP server behaviour, in contrast to tools such as Tsung which are about stress testing and don't verify correctness.

This tool, escalus, is used by ESL's amoc for load tests against ESL's MongooseIM.

Quick start

The test/example_SUITE.erl file contains a minimalistic example of an Escalus test suite.

You should include escalus.hrl file and the Common Test header:

-include_lib("escalus/include/escalus.hrl").
-include_lib("common_test/include/ct.hrl").

Escalus contains functions escalus:init_per_suite/1, escalus:end_per_suite/1, escalus:init_per_testcase and escalus:end_per_testcase which should be called in appropriate Common Test callback functions. Calling escalus:init_per_testcase is mandatory as this function initializes the runtime support for escalus:story (i.e. escalus_cleaner -- actually, you can do it manually if you know what you're doing).

You can specify users that will take part in your tests in Common Test config files, look at test/test.config file that comes with Escalus:

{escalus_users, [
    {alice, [
        {username, "alice"},
        {server, "localhost"},
        {password, "makota"}]},
    {bob, [
        {username, "bob"},
        {server, "localhost"},
        {password, "bobcat"}]}
]}.

Escalus can create and delete those users in two ways:

  • using in-band registration XEP-0077 when it is supported by the server and has no limits on number of registrations per second (configure registration_timeout to infinity in case of ejabberd).
  • using erlang rpc calls to the ejabberd_admin:register/2 function (in case of MongooseIM or ejabberd as the tested server and the in-band registration is disabled)

You create and delete the users by calling escalus:create_users/1 and escalus:delete_users/1:

init_per_group(_GroupName, Config) ->
    escalus:create_users(Config).

end_per_group(_GroupName, Config) ->
    escalus:delete_users(Config).

In our exemplary test case it is done in init_per_group and end_per_group functions, but you could as well do it in init-/end_per_suite if you prefer. Deleting users should clean all their data (e.g. roster buddies), so it improves test isolation, but takes longer.

In most of the test cases you will use escalus:story/3 function. Story wraps all the test and does the cleanup and initialisation:

messages_story(Config) ->
    escalus:story(Config, [1, 1], fun(Alice, Bob) ->

        %% Alice sends a message to Bob
        escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"OH, HAI!">>)),

        %% Bob gets the message
        escalus:assert(is_chat_message, [<<"OH, HAI!">>],
                       escalus:wait_for_stanza(Bob))

    end).

The story above involves two users (second argument is a two-element list) each having one resource (list contains ones). As you see from the config files, those users are Alice and Bob. Escalus logs in users at the beginning of the story and logs them out after it ends (either successfully or by crash).

It's also possible to designate users taking part in a story more specifically:

messages_story(Config) ->
    escalus:story(Config, [{alice, 1}, {kate, 1}], fun(Alice, Kate) ->
        ...
    end).

That allows one to choose users which are not consecutive in test/test.config.

Inside the story you can use escalus:send/2 function to send stanzas, functions from escalus_stanza module to create them and escalus:wait_for_stanza to receive them.

wait_for_stanza makes test fail if no stanza arrives up to a timeout. There is also wait_for_stanzas function which takes number of stanzas N as an argument and returns N-element or shorter list of stanzas, returning less stanzas instead of crashing. Both wait_for_stanza and wait_for_stanzas can take an extra argument -- timeout in milliseconds. The default timeout value is one second.

You make assertions using escalus:assert/3 function. First argument is the predicate. It can be a fun, a {module, function} tuple or an atom. Atoms refer to functions from escalus_pred module. Second argument is a parameter list and third is a stanza that we assert things about. There is escalus:assert/2 function that is equivalent to assert/3 with empty parameter list. Calling escalus:assert(Pred, [Param1, Param2], Stanza) makes sure that Pred(Param1, Param2, Stanza) yields true. Stanza is separate from parameters to improve error reporting.

Escalus as a standalone application

It's possible to use Escalus as a standalone application, i.e. outside a Common Test test suite (and without any reliance on the common_test application and its modules). If you use rebar3 tool there are only few steps to generate full escalus release. Just type in your bash shell:

rebar3 release

and wait until it finishes. It is now possible to start erlang shell with command:

$ESCALUS_ROOT/_build/default/rel/escalus/bin/escalus

You can now enjoy usage of escalus application in your erlang release! In order to use escalus as standalone application without rebar3 some prerequisites must be met.

Firstly, Escalus must be started just like any other application:

> application:ensure_all_started(escalus).

This makes predefined environment variables from escalus.app available for access by application:get_env. These options and their respective values for running without Common Test are:

{env, [{config_file, "priv/escalus.config"}]}

To recap:

  • config_file must be set to a configuration file location; this location may be absolute or relative (in which case the file will be searched for relative to the project directory).

Note, that in a real security-conscious setting you probably shouldn't store clear text user passwords in this file (though that's exactly what the example does - remember Escalus is still mostly a testing tool).

If you don't want to rely on the application resource file (escalus.app/escalus.app.src) you can set both of these options just after loading Escalus:

> application:ensure_all_started(escalus).
> application:set_env(escalus, config_file, "/absolute/or/relative/path").

Keep in mind that calling application:ensure_all_started(escalus) will overwrite the values with stuff from escalus.app. Set the variables after the application is started.

Config file location

If the config_file value starts with / it's interpreted as an absolute path and left as is. Otherwise, it's interpreted as a relative path to the project directory. The project directory is the directory one level higher than the directory containing ejabberd_ct.beam. In case of a standard Git checkout the project directory is simply escalus.

escalus/
├── .git/
├── ...
├── docs/
├── ebin/
│   ├── ...
│   ├── escalus_ct.beam
│   └── ...
├── src/
└── ...

Example shell session

Fire an Erlang shell:

erl -pa ebin deps/*/ebin

Basic example

Run example:

application:ensure_all_started(escalus).
{ok, Config} = file:consult("priv/escalus.config").
CarolSpec = escalus_users:get_options(Config, carol).
{ok, Carol, _, _} = escalus_connection:start(CarolSpec).
escalus_connection:send(Carol, escalus_stanza:chat_to(alice, "hi")).
escalus_connection:stop(Carol).

Story example

Please note that escalus:story/3 and escalus:create_users/2 are intended to be used in a testing environment, i.e. with Common Test available. Specifically, escalus:create_users/2 will not work without Common Test and with non-XMPP registration method chosen (i.e. RPC based user registration). In case of MongooseIM or ejabberd, please ensure mod_register is enabled (and, depending on your scenario, probably configured not to send a welcome message).

Run example:

X2SFun = fun(X) -> lists:flatten(io_lib:format("~p~n", [X])) end.
{ok, Config0} = file:consult("priv/escalus.config").
application:ensure_all_started(escalus).
escalus:create_users(Config0, {by_name, [alice, mike]}).
Config = escalus_event:start(escalus_cleaner:start(Config0)).
SendFun = fun(A, B) -> escalus:send(A, escalus_stanza:chat_to(B, "hi")), ok end.
RecvFun = fun(B) -> [S] = escalus:wait_for_stanzas(B, 1), {ok, S} end.
StoryFun = fun(A, B) -> SendFun(A, B), {ok, S} = RecvFun(B), erlang:display(X2SFun(S)) end.
escalus:story(Config, [{mike, 1}, {alice,1}], StoryFun).
escalus_cleaner:stop(escalus_event:stop(Config)).
escalus:delete_users(Config, {by_name, [alice, mike]}).

Naming

According to Wikipedia, Prince Escalus, of the House Escalus, is the voice of authority in Verona, and appears only three times within the text and only to administer justice.

It follows the great tradition to use characters of William Shakespeare's Romeo and Juliet in the XMPP specifications.

escalus's People

Contributors

aleklisi avatar alipiec avatar arcusfelis avatar arkgil avatar astachurski avatar bartekgorny avatar chrzaszcz avatar denysgonchar avatar erszcz avatar fenek avatar goj avatar gustawlippa avatar janciesla8818 avatar kianmeng avatar kzemek avatar legoscia avatar ludwikbukowski avatar michalwski avatar mkacper avatar mpmiszczyk avatar nelsonvides avatar nyco avatar paulgray avatar philwitty avatar pianiel avatar ppikula avatar pzel avatar studzien avatar vkatsuba avatar zofpolkowska avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

escalus's Issues

Race condition in reset function

Here are debug prints from reset_stream and handle_data functions:

----------------------------------------------------
2016-08-31 17:25:32.262
escalus_ws:handle_data <0.15121.0> <<"<stream:stream version='1.0' xml:lang='en' xmlns='jabber:client' xmlns:stream='http://etherx.jabbe
r.org/streams' id='D56D29B61CDE6C91' from='localhost'>">>


----------------------------------------------------
2016-08-31 17:25:32.262
escalus_ws:handle_data <0.15121.0> <<"<stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>PLAIN</mechanism>
<mechanism>X-OAUTH</mechanism><mechanism>DIGEST-MD5</mechanism><mechanism>SCRAM-SHA-1</mechanism></mechanisms><register xmlns='http://ja
bber.org/features/iq-register'/><amp xmlns='http://jabber.org/feature/amp'/><sm xmlns='urn:xmpp:sm:3'/></stream:features>">>


----------------------------------------------------
2016-08-31 17:25:32.265
escalus_ws:handle_data <0.15121.0> <<"<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>">>


----------------------------------------------------
2016-08-31 17:25:32.265
escalus_ws:reset_parser <0.15121.0>


----------------------------------------------------
2016-08-31 17:25:32.267
escalus_ws:handle_data <0.15121.0> <<"<stream:features><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><session xmlns='urn:ietf:params:$
ml:ns:xmpp-session'/><register xmlns='http://jabber.org/features/iq-register'/><amp xmlns='http://jabber.org/feature/amp'/><sm xmlns='u$
n:xmpp:sm:3'/></stream:features>">>

TODO: add debug printing to other functions.
Can be escalus or mongooseim error.

Issue is in progress.

Escalus - basic example issues (not sure if related to #130)

hi, just trying the basic example (and fixed the config file per issue #130 and also created the users alice, bob, carol, .... on localhost) but getting the following error:

** exception exit: undef in function fusco_cp:start_link/3 called as fusco_cp:start_link({"localhost",5280,false}, [{on_connect, #Fun<escalus_bosh.1.18338422>}], 2) in call from escalus_bosh:init/1 (/home/ubuntu/escalus/_build/default/lib/escalus/src/escalus_bosh.erl, line 325) in call from gen_server:init_it/6 (gen_server.erl, line 328) in call from proc_lib:init_p_do_apply/3 (proc_lib.erl, line 240)

Cannot resolve meck dependency

Is this still working. I am looking for XMPP erlang client library, I tried to include it via Makefile in my app and seems there is this meck dependency which is not getting resolved.
I am getting this Dependency meck is specified as a dependency but is not reachable by the system.

Make it possible to provide custom TCP options

Such work has already been made in:

However I see a few issues here:

  • we allow to set the mode: {mode, Mode :: binary | list} - but this is wrong as escalus expect the received data to be binary (e.g. the calls erlang:byte_size/1 on it here
  • if would say the same is for active
  • we disable Nagle's algorithm by default {nodelay, true} but have we measured it helps us?
  • we set {reuseaddr, true} but we already know that setting this to true prevents us from squeezing ~50K users from one Amoc node

IMO that is to be fixed.

cc @erszcz, @michalwski @bszaf

Merge records #client and #transport

In many places #transport record is used when #client record is used. Merging these 2 records into one should simplify the API. The #client.con field contains transport record. Merged record may look like the following:

-record(client, {
        jid :: binary(),
        module :: atom(),
        socket :: term(),
        ssl :: boolean(),
        compress :: {zlib, {Zin::zlib:zstream(), Zout::zlib:zstream()}} |  false,
        rcv_pid :: pid(),
        event_client :: any()}).

[RFC] On being a poet (or about writing stanzas)

Most, if not all, of stanzas in escalus_stanza and custom stanzas in tests use the following style of building up the Erlang representation - that is, records are composed directly:

-spec attach(binary(), binary()) -> #xmlel{}.
attach(User, Host) ->
    iq(<<"set">>,
       [#xmlel{name = <<"attach">>,
               attrs = [{<<"xmlns">>, <<"urn:ietf:params:xml:ns:xmpp-attach">>}],
               children = [#xmlel{name = <<"node">>,
                                  children = [exml:escape_cdata(User)]},
                           #xmlel{name = <<"domain">>,
                                  children = [exml:escape_cdata(Host)]}]}]).

While this approach is easily understandable for Erlang developers, it requires extra effort to get the XML as it really looks in text format, e.g. in cases where we want to provide snippets for tutorials or communication with client app devs.

However, for some time there's also some support for using Mustache for generating stanzas, which makes the constructors look like this:

-spec attach(binary(), binary()) -> #xmlel{}.
attach(User, Host) ->
    T = <<"<iq type='set' id='attach1'>
             <attach xmlns='urn:ietf:params:xml:ns:xmpp-attach'>
               <node>{{user}}</node>
               <domain>{{host}}</domain>
             </attach>
           </iq>">>,
    escalus_stanza:from_template(T, [{user, User}, {host, Host}]).

This approach is also composable, because of the following form:

-spec attach(binary()) -> #xmlel{}.
attach(Host) ->
    Node = escalus_stanza:from_xml(<<"<node>john</node>">>),
    T = <<"<iq type='set' id='attach1'>
             <attach xmlns='urn:ietf:params:xml:ns:xmpp-attach'>
               {{{node}}}
               <domain>{{host}}</domain>
             </attach>
           </iq>">>,
    escalus_stanza:from_template(T, [{node, Node}, {host, Host}]).

escalus_stanza:from_xml/1 and escalus_stanza:from_template/2 differ in the fact that the former doesn't take any parameters to substitute - effectively it's the same as exml:parse/1. Both return an Erlang/exml representation of XML. Triple braces {{{some_element}}} mean that the element passed will be treated as an exml style XML element to ensure composability.

The main benefit is regular represenation of XML in documentation, XEPs, test code and in communication with front-end / client developers. In this case it's pretty easy to just copy and paste the template and turn it into an example for non-Erlangers.

The main disadvantage of this solution is heavily decreased performance due to the templates being parsed first by mustache and then by exml, especially if we use rendered templates to parameterize subsequent templates. Therefore, this method probably should not be used in MongooseIM itself, only in the test code.

I wanted to ask about your opinion:

  • what pros / cons of both approaches do you see?
  • should we switch?

I'm asking these questions now, because I'm going to write support for a new extension and would like to avoid using code that will be frowned upon in the longer run.

Shortcut for calling user by atom

93ee6ee deprecates calls like:

escalus_stanza:last_activity(bob)

which have to be replaced by:

BobShortJID = escalus_client:short_jid(Bob),
escalus_stanza:last_activity(BobShortJID)

To make test development easier, maybe we could consider this:

escalus_stanza:last_activity(bob, Config)

Escalus basic example issue

OTP: 19

I tried to follow escalus quick start tuto to run a basic example, but I got an error after executing this erlang line.

{ok, Carol, _, _} = escalus_connection:start(CarolSpec). ** exception error: undefined function bosh:connect/1 in function escalus_connection:connect/1 (src/escalus_connection.erl, line 144) in call from escalus_connection:start/2 (src/escalus_connection.erl, line 103)

Support for XEP-0105 Extended Capabilities ?

I would like to use a Personal Eventing Protocol feature of generating notifications based on presence. Correct if I'm wrong, but what I understood from reading the XEPs is that in order to do so, a client (entity) has to announce presence with extended capabilities and with that announce the features it is interested, so that the pubsub (pep) service of an entity can automatically publish the messages to the subscribed (presence) entities.
I would be great to have library support to generate a iq disco result stanzas with identities, features, forms, and also be able to generate a hash out of that to include it in the presence stanzas.

I looked at processone library and they seem to support it:
https://github.com/processone/exmpp/blob/master/src/core/exmpp_caps.erl

delete_users fails for in-band registration

When there few users with same username in config file, escalus_users:delete_users() tries to login for second user with same username to unregister and fails.

Temporary workaround could be to pass second argument {by_name, List} with list of users omitting duplicates.

Possible fix would be filtering list of users in delete_users/2.

Please let me know if you like me to prepare a PR for that.

Possible issue with r16b03 and ssl 5.3.2

After updating to r16b03 I was unable to successfully run tests as I was getting an error in the ssl:connection_cb(). I think I have tracked it down to the following:

in escalus_tcp:handle_call({upgrade_to_tls,SSLOpts}, From, State)

around line 109 SSLOpts1 is initialized to

SSLOpts1 = [{protocol,tlsv1},{reuse_sessions, true}]

Im not 100% certain but I think the protocol tuple is not needed and it seems to be the cause of the function clause error in ssl:connection_cb(). Looking at the docs for the ssl application I don't seem to see a ssl_opt() that matches {protocol, tlsv1}. Removing it allows me to successfully run tests. Hopefully this info assists in some way.

To clarify when I say 'run tests' I am talking about the MongooseIM tests.

Hex Package

Make sure the repo is rebar3-compatible and its deps are also hex.pm packages, then publish it on hex.pm.

Better logging

Sometimes I get race conditions randomly and the only information that I have is badmatch and stacktrace.
The idea is to convert escalus_client into gen_server, that will contain all incoming and outgoing stanzas and there timestamps. In case of an error, this information can be written into the CT report.

How to use escalus component from elixir?

I am trying to connect escalus_component to mongooseim locally from elixir

I call this:

Interactive Elixir (1.6.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> conarg = [{:host, "localhost"}, {:password, "secret"},{:port, 8888},{:component,"mongooseim@localhost"}]
[
  host: "localhost",
  password: "secret",
  port: 8888,
  component: "mongooseim@localhost"
]
iex(2)> :escalus_component.start_link(:escalus_component, conarg, [])  
** (EXIT from #PID<0.282.0>) shell process exited with reason: an exception was raised:
    ** (FunctionClauseError) no function clause matching in :escalus_component.init/1
        /Users/gibranrodriguez/everdays/full-stack-react-phoenix/chat_app/deps/escalus/src/escalus_component.erl:103: :escalus_component.init([])
        /Users/gibranrodriguez/everdays/full-stack-react-phoenix/chat_app/deps/escalus/src/escalus_component.erl:109: :escalus_component.init/1
        (stdlib) gen_server.erl:365: :gen_server.init_it/2
        (stdlib) gen_server.erl:333: :gen_server.init_it/6
        (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3

On Mongooseim node this happens:

2019-04-05 09:28:39.751 [debug] <0.425.0>@shaper_srv:handle_info:146 Deleted old shapers
2019-04-05 09:29:01.988 [info] <0.1040.0>@ejabberd_listener:accept:322 (#Port<0.18466>) Accepted connection {{127,0,0,1},62553} -> {{127,0,0,1},8888}
2019-04-05 09:29:01.988 [info] <0.1273.0>@ejabberd_service:init:158 ({socket_state,gen_tcp,#Port<0.18466>,<0.1272.0>}) External service connected
2019-04-05 09:29:02.009 [debug] <0.1272.0>@ejabberd_receiver:process_data:317 Received XML on stream = "<stream:stream to='mongooseim@localhost' xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams'>"
2019-04-05 09:29:02.009 [debug] <0.1272.0>@shaper:update:60 Tokens: 49879 (+1025,-121), delay: 0 ms
2019-04-05 09:29:02.011 [debug] <0.1272.0>@ejabberd_receiver:process_data:317 Received XML on stream = "<handshake>86dd3e2badc5df02a1254b8545d206c8de9f81a5</handshake>"
2019-04-05 09:29:02.011 [debug] <0.1272.0>@shaper:update:60 Tokens: 49915 (+99,-63), delay: 0 ms
2019-04-05 09:29:02.012 [info] <0.1273.0>@ejabberd_service:terminate:389 terminated: normal

I guess I would like some help on an example how to connect escalus_component to mongooseim either from elixir or erlang

1012 connections in time max

I am tring to use escalus for load testing
Start:
erl -pa ebin deps/*/ebin -P 50000 -cookie 'somecookie'

trying to connect users :
lists:map(fun(X) ->
User =
iolist_to_binary([<<"0">>, integer_to_list(X)]),
F = [{username, User},
{server,<<"myserver">>},
{host,<<"myserver.com">>},
{port,5222},
{auth,{escalus_auth,auth_plain}},
{wspath,undefined},
{username,User},
{server,<<"myserver">>},
{host,<<"myserver.com">>},
{password,<<"p1">>},
{starttls,true}],
timer:sleep(50), %arrival time
erlang:Fun(escalus_connection, start, [F])
end,
lists:seq(1, 5000, 1))

No matter there are 5000 or 3000 or after 1012 I don't see any tries to connect on server log
If I start escalus parralel in new tab in console, I can connect 2000,3000

Introduce a behaviour for `on_connect`, `on_request`, and `on_reply`

This comment applies just as well to our case of the callbacks in question. Introducing a behaviour will document the expected callback interface and might even make the code simpler.

We should probably use erlang:function_defined/3 to save the callback module implementer the hassle of reimplementing and exporting noop functions.

Setting filter_pred and stream_management=true breaks automatic SM

The problem happens at least in case of escalus_tcp transport due to escalus_connection:maybe_forward_to_owner running the filter before escalus_tcp:forward_to_owner, which extracts SM elements intended for automatic handling. In other words, the filter might filter out SM <r/> elements, which ought to be handled by escalus_tcp. This problem occurred when trying to run an AMOC scenario with SM enabled, but the filter set to only allow messages:

escalus_connection:set_filter_predicate(Client, fun escalus_pred:is_message/1)

Compiling hamcrest fails

I'm compiling the escalus XMPP client

But everything goes well with rebar3 until it compiles hamcrest, it throws me this error:

===> Compiling hamcrest ===> Compiling _build/default/lib/hamcrest/src/hamcrest.erl failed _build/default/lib/hamcrest/src/hamcrest.erl:59: syntax error before: '/' _build/default/lib/hamcrest/src/hamcrest.erl:63: syntax error before: '/' _build/default/lib/hamcrest/src/hamcrest.erl:67: syntax error before: '/' _build/default/lib/hamcrest/src/hamcrest.erl:72: syntax error before: '/' _build/default/lib/hamcrest/src/hamcrest.erl:79: syntax error before: '/' _build/default/lib/hamcrest/src/hamcrest.erl:90: syntax error before: '/' _build/default/lib/hamcrest/src/hamcrest.erl:108: syntax error before: '/'

Any ideas about this?

Thanks in advance!

Changing domain in config file causes crash

Hello,
I am trying to include escalus in my erlang app which is trying to send and receive a small message.
Here's what I have done:

application:ensure_all_started(escalus), {ok,Config} = file:consult("priv/escalus.config"), CarolSpec = escalus_users:get_options(Config, carol), Carol = escalus_connection:start(CarolSpec),
But it is failing with
** Reason for termination == ** {{badmatch,{error,"XML or text declaration not at start of entity"}}, [{escalus_bosh,handle_info,2, [{file,"/home/shobhit/escalus/escalus/_build/default/lib/escalus/src/escalus_bosh.erl"}, {line,414}]}, {gen_server,try_dispatch,4,[{file,"gen_server.erl"},{line,601}]}, {gen_server,handle_msg,5,[{file,"gen_server.erl"},{line,667}]}, {proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,247}]}]} ** exception exit: {badmatch,{error,"XML or text declaration not at start of entity"}} in function escalus_bosh:handle_info/2 (/home/shobhit/escalus/escalus/_build/default/lib/escalus/src/escalus_bosh.erl, line 414) in call from gen_server:try_dispatch/4 (gen_server.erl, line 601) in call from gen_server:handle_msg/5 (gen_server.erl, line 667) in call from proc_lib:init_p_do_apply/3 (proc_lib.erl, line 247)
I have changed the config file to include my domain.
Any pointers would be really helpful.

Thanks

Config file:
{ejabberd_node, '[email protected]'}.
{ejabberd_cookie, ejabberd}.
{ejabberd_domain, <<"domain.com">>}.

{escalus_users, [
{alice, [
{username, <<"alice">>},
{server, <<"localhost">>},
{password, <<"makota">>},
{compression, <<"zlib">>}]},
{carol, [
{username, <<"carol">>},
{server, <<"domain.com">>},
{password, <<"jinglebells">>},
{transport, escalus_bosh},
{path, <<"/http-bind">>},
{port, 5280}]}
]}.

Websocket connection problems

Hi, I've run into several issues, trying to use escalus websocket transport.

  1. Some of underlying libs (wsock) uses re:replace as template parser to create HTTP message, but if wspath has parameters with '&'s re:replace changes this to {{resource}}, so websocket connection fails.
  2. Another issue with wsecli/wsock is that it's not possible to provide sec-websocket-protocol: xmpp header. Not sure if it makes sense to add wsheaders param to escalus or just hardcode somewhere in escalus_ws. My server required this, so again connection failed.
  3. I saw that new version of escalus has a nice feature of user-defined transport modules, so I decided to implement one instead of patching wsock/wsecli. But some websocket specific logic works only if transport=ws, so it doesn't work with my own module name as transport. This one can be easily fixed by separating transport and module parameters.

Just thought this info could be helpful for improving escalus.

Elixir support?

Hi,
Im new to erlang and elixir, so sorry for (maybe) obvious question.

Is it possible to use Escalus on elixir project? Im planning to write some tests for custom functionality in MongooseIM, but I prefer Elixir over Erlang because of the ruby like syntax etc.

Im kinda stuck on getting config file:

:application.set_env :escalus, :config_file, "test/test.config"
:escalus.create_users(:alice)
** (MatchError) no match of right hand side value: {:error, :enoent}

Escalus will look in to wrong dir(I insert erlang:display(Path) in to escalus_ct.erl:50):
/Users/brbrr/Development/Vega/eliTests/_build/test/lib/escalus/test/test.config instead of /Users/brbrr/Development/Vega/eliTests/test/test.config

Get rid of ct:get_config

It is very hard to use esaclus without common tests because of using ct:get_config in several places.
Application settings should be used instead.

Exception in user creation via xmpp

I tried to create two user with

escalus:create_users(Config0, {by_name, [mike, geralt]}).

but I got this exception:

 exception error: no function clause matching escalus_users:'-create_users_via_xmpp/2-lc$^0/1-0-'({by_name,[mike,geralt]}) (src/escalus_users.erl, line 99)
     in function  escalus_users:create_users_via_xmpp/2 (src/escalus_users.erl, line 99)

What's the source of this exception please ?

[ Roster] How can I manipulate user roster ?

I tried to manipulate user roster with escalus API.
After diving a little bit in Escalus code I found some functions that have relations with my need like:

escalus_pred:roster_contains
escalus_pred:count_roster_items
escalus_pred:get_roster_items
escalus_stanza:roster_get
escalus_stanza:roster_add_contact

I tried for example to use one of them to count roster item as follows:

escalus_pred:count_roster_items(0,{xmlel,<<"iq">>,[{<<"type">>,<<"get">>},{<<"id">>,<<"230c60e893af03efbcf2fed3b8cdd585">>}],[{xmlel,<<"query">>,[{<<"from">>,<<"carol@localhost">>},{<<"xmlns">>,<<"jabber:iq:roster">>}],[]}]}).

I have a doubt if my stanza element is well formatted, also I have another question about getting roster items, Should I use escalus_pred:get_roster_items ?

econnrefused errors give no insight to cause

As I've been working with escalus, I have noticed that any time it cannot connect, it gives nothing more than a badmatch on {error, econnrefused} with no insight into what it is trying to connect to, how the host responded, etc.

Can this be expanded to include useful information on dumps? I end up having to start tcpdumping traffic just to figure out where escalus is trying to connect to.

Tag OTP19 support

Hey,

Now that #118 is merged could you guys tag?
We'd rather depend on tags than commits & I couldn't find a tag that had #118 changes.

Thanks!

Error starting escalus story when user have offline messages

I'm trying to test offline messages using escalus. When I'm trying to start escalus story for user who have offline messages, I'm getting following error:

     ** (ErlangError) Erlang error: {:assertion_failed, :assert, :is_presence, {:xmlel, "message", [{"xml:lang", "en"}, {"to", "[email protected]/res1"}, {"from", "[email protected]/res1"}], [{:xmlel, "archived", [{"by", "[email protected]"}, {"id", "8512ba7a-04fd-11e9-bc0e-69dacdbc2072"}, {"xmlns", "urn:xmpp:mam:tmp"}], []}, {:xmlel, "stanza-id", [{"by", "[email protected]"}, {"id", "8512ba7a-04fd-11e9-bc0e-69dacdbc2072"}, {"xmlns", "urn:xmpp:sid:0"}], []}, {:xmlel, "seq", [{"id", "2"}, {"xmlns", "urn:message:seq"}], []}, {:xmlel, "delay", [{"from", "example2.com"}, {"stamp", "2018-12-21T08:50:51.830393Z"}, {"xmlns", "urn:xmpp:delay"}], [xmlcdata: "Offline storage"]}, {:xmlel, "body", [], [xmlcdata: "offline message"]}]}, '<message xml:lang=\'en\' to=\'[email protected]/res1\' from=\'[email protected]/res1\'><archived by=\'[email protected]\' id=\'8512ba7a-04fd-11e9-bc0e-69dacdbc2072\' xmlns=\'urn:xmpp:mam:tmp\'/><stanza-id by=\'[email protected]\' id=\'8512ba7a-04fd-11e9-bc0e-69dacdbc2072\' xmlns=\'urn:xmpp:sid:0\'/><seq id=\'2\' xmlns=\'urn:message:seq\'/><delay from=\'example2.com\' stamp=\'2018-12-21T08:50:51.830393Z\' xmlns=\'urn:xmpp:delay\'>Offline storage</delay><body>offline message</body></message>'}

Short investigation shows that escalus story aways wait for presences after starting client (https://github.com/esl/escalus/blob/master/src/escalus_story.erl#L136) but this behaviour is not fully correct in my case.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.