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(websockets_SUITE).
   18: -compile([export_all, nowarn_export_all]).
   19: 
   20: -include_lib("escalus/include/escalus.hrl").
   21: -include_lib("common_test/include/ct.hrl").
   22: 
   23: -import(distributed_helper, [mim/0]).
   24: 
   25: %%--------------------------------------------------------------------
   26: %% Suite configuration
   27: %%--------------------------------------------------------------------
   28: 
   29: -define(REGISTRATION_TIMEOUT, 2).  %% seconds
   30: -define(MAX_STANZA_SIZE, 200).
   31: 
   32: all() ->
   33:     [metrics_test,
   34:      {group, ws_chat},
   35:      {group, wss_chat}].
   36: 
   37: groups() ->
   38:     [{ws_chat, [sequence], test_cases()},
   39:      {wss_chat, [sequence], test_cases()}].
   40: 
   41: test_cases() ->
   42:     [chat_msg,
   43:      escape_chat_msg,
   44:      escape_attrs,
   45:      too_big_stanza_is_rejected].
   46: 
   47: suite() ->
   48:     escalus:suite().
   49: 
   50: %%--------------------------------------------------------------------
   51: %% Init & teardown
   52: %%--------------------------------------------------------------------
   53: 
   54: init_per_suite(Config) ->
   55:     Config1 = escalus:init_per_suite(Config),
   56:     Config2 = setup_listeners(Config1),
   57:     escalus:create_users(Config2, escalus:get_users([alice, geralt, geralt_s, carol])).
   58: 
   59: end_per_suite(Config) ->
   60:     Listeners = ?config(original_listeners, Config),
   61:     [mongoose_helper:restart_listener(mim(), Listener) || Listener <- Listeners],
   62:     Config1 = escalus:delete_users(Config, escalus:get_users([alice, geralt, geralt_s, carol])),
   63:     escalus:end_per_suite(Config1).
   64: 
   65: init_per_group(GroupName, Config) ->
   66:     case GroupName of
   67:         wss_chat ->
   68:             [{user, geralt_s} | Config];
   69:         _ ->
   70:             [{user, geralt} | Config]
   71:     end.
   72: 
   73: end_per_group(_GroupName, _Config) ->
   74:     ok.
   75: 
   76: init_per_testcase(CaseName, Config) ->
   77:     escalus:init_per_testcase(CaseName, Config).
   78: 
   79: end_per_testcase(CaseName, Config) ->
   80:     escalus:end_per_testcase(CaseName, Config).
   81: 
   82: setup_listeners(Config) ->
   83:     Listeners = mongoose_helper:get_listeners(mim(), #{module => ejabberd_cowboy}),
   84:     [mongoose_helper:restart_listener(mim(), update_listener(Listener)) || Listener <- Listeners],
   85:     [{original_listeners, Listeners} | Config].
   86: 
   87: update_listener(Listener = #{handlers := Handlers}) ->
   88:     Listener#{handlers := lists:map(fun update_handler/1, Handlers)}.
   89: 
   90: update_handler(Handler = #{module := mod_websockets}) ->
   91:     Handler#{max_stanza_size := ?MAX_STANZA_SIZE};
   92: update_handler(Handler) ->
   93:     Handler.
   94: 
   95: %%--------------------------------------------------------------------
   96: %% Message tests
   97: %%--------------------------------------------------------------------
   98: 
   99: metrics_test(Config) ->
  100:     MongooseMetrics = [{[global, data, xmpp, received, xml_stanza_size], changed},
  101:                        {[global, data, xmpp, sent, xml_stanza_size], changed},
  102:                        {[global, data, xmpp, received, c2s, websocket], changed},
  103:                        {[global, data, xmpp, sent, c2s, websocket], changed},
  104:                        {[global, data, xmpp, received, c2s, tcp], 0},
  105:                        {[global, data, xmpp, sent, c2s, tcp], 0}],
  106:     escalus:story([{mongoose_metrics, MongooseMetrics} | Config],
  107:                   [{geralt, 1}, {geralt_s, 1}],
  108:                   fun(Geralt, GeraltS) ->
  109: 
  110:         escalus_client:send(GeraltS, escalus_stanza:chat_to(Geralt, <<"Hi!">>)),
  111:         escalus:assert(is_chat_message, [<<"Hi!">>], escalus_client:wait_for_stanza(Geralt)),
  112: 
  113:         escalus_client:send(Geralt, escalus_stanza:chat_to(GeraltS, <<"Hello!">>)),
  114:         escalus:assert(is_chat_message, [<<"Hello!">>], escalus_client:wait_for_stanza(GeraltS))
  115: 
  116:         end).
  117: 
  118: too_big_stanza_is_rejected(Config) ->
  119:     escalus:story(
  120:       Config, [{alice, 1}, {?config(user, Config), 1}],
  121:       fun(Alice, Geralt) ->
  122:               BigBody = base16:encode(crypto:strong_rand_bytes(?MAX_STANZA_SIZE)),
  123:               escalus_client:send(Geralt, escalus_stanza:chat_to(Alice, BigBody)),
  124:               escalus:assert(is_stream_error, [<<"policy-violation">>, <<>>], escalus_client:wait_for_stanza(Geralt)),
  125:               escalus:assert(is_stream_end, escalus_client:wait_for_stanza(Geralt)),
  126:               true = escalus_connection:wait_for_close(Geralt, timer:seconds(1)),
  127:               escalus_assert:has_no_stanzas(Alice)
  128:       end).
  129: 
  130: chat_msg(Config) ->
  131:     escalus:story(Config, [{alice, 1}, {?config(user, Config), 1}, {carol, 1}],
  132:                   fun(Alice, Geralt, Carol) ->
  133: 
  134:         escalus_client:send(Alice, escalus_stanza:chat_to(Geralt, <<"Hi!">>)),
  135:         FromAlice = escalus_client:wait_for_stanza(Geralt),
  136:         escalus:assert(is_chat_message, [<<"Hi!">>], FromAlice),
  137:         escalus:assert(has_ns, [<<"jabber:client">>], FromAlice),
  138: 
  139:         escalus_client:send(Geralt, escalus_stanza:chat_to(Alice, <<"Hello!">>)),
  140:         escalus:assert(is_chat_message, [<<"Hello!">>], escalus_client:wait_for_stanza(Alice)),
  141: 
  142:         escalus_client:send(Geralt, escalus_stanza:chat_to(Carol, <<"Hey!">>)),
  143:         escalus_assert:is_chat_message(<<"Hey!">>, escalus_client:wait_for_stanza(Carol))
  144: 
  145:         end).
  146: 
  147: escape_chat_msg(Config) ->
  148:     escalus:story(Config, [{alice, 1}, {?config(user, Config), 1}, {carol, 1}],
  149:                   fun(Alice, Geralt, Carol) ->
  150:         special_chars_helper:check_cdata_from_to(Alice, Geralt, <<"Hi! & < >">>),
  151:         special_chars_helper:check_cdata_from_to(Geralt, Alice, <<"Hello! & < >">>),
  152:         special_chars_helper:check_cdata_from_to(Geralt, Carol, <<"Hey! & < >">>)
  153: 
  154:     end).
  155: 
  156: escape_attrs(Config) ->
  157:     escalus:story(Config, [{alice, 1}, {?config(user, Config), 1}, {carol, 1}],
  158:                   fun(Alice, Geralt, Carol) ->
  159:         special_chars_helper:check_attr_from_to(Alice, Geralt),
  160:         special_chars_helper:check_attr_from_to(Geralt, Alice),
  161:         special_chars_helper:check_attr_from_to(Geralt, Carol)
  162: 
  163:     end).