1: %%==============================================================================
    2: %% Copyright 2013 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(metrics_roster_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:                              require_rpc_nodes/1,
   25:                              rpc/4]).
   26: 
   27: -import(metrics_helper, [assert_counter/2,
   28:                          get_counter_value/1]).
   29: 
   30: %%--------------------------------------------------------------------
   31: %% Suite configuration
   32: %%--------------------------------------------------------------------
   33: 
   34: all() ->
   35:     [{group, roster},
   36:      {group, subscriptions}
   37:     ].
   38: 
   39: groups() ->
   40:     [{roster, [sequence], roster_tests()},
   41:      {subscriptions, [sequence], subscription_tests()}].
   42: 
   43: suite() ->
   44:     require_rpc_nodes([mim]) ++ escalus:suite().
   45: 
   46: roster_tests() -> [get_roster,
   47:                    add_contact,
   48:                    roster_push].
   49: 
   50: %%  WARNING: Side-effects & test interference
   51: %%  subscribe affects subsequent tests
   52: %%  by sending a directed presence before the roster push
   53: %%  in add_sample_contact/2
   54: %%  TODO: investigate, fix.
   55: 
   56: subscription_tests() -> [unsubscribe,
   57:                          decline_subscription,
   58:                          subscribe].
   59: %%--------------------------------------------------------------------
   60: %% Init & teardown
   61: %%--------------------------------------------------------------------
   62: 
   63: 
   64: init_per_suite(Config) ->
   65: 
   66:     MongooseMetrics = [{[global, data, xmpp, received, xml_stanza_size], changed},
   67:                        {[global, data, xmpp, sent, xml_stanza_size], changed},
   68:                        {fun roster_rdbms_precondition/0, [global, data, rdbms, default],
   69:                         [{recv_oct, '>'}, {send_oct, '>'}]},
   70:                        {[global, backends, mod_roster, get_subscription_lists], changed}
   71:                        ],
   72:     [{mongoose_metrics, MongooseMetrics} | escalus:init_per_suite(Config)].
   73: 
   74: end_per_suite(Config) ->
   75:     escalus:end_per_suite(Config).
   76: 
   77: init_per_group(_GroupName, Config) ->
   78:     escalus:create_users(Config, escalus:get_users([alice, bob])).
   79: 
   80: end_per_group(_GroupName, Config) ->
   81:     escalus:delete_users(Config, escalus:get_users([alice, bob])).
   82: 
   83: init_per_testcase(CaseName, Config) ->
   84:     escalus:init_per_testcase(CaseName, Config).
   85: 
   86: end_per_testcase(add_contact, Config) ->
   87:     [{_, UserSpec} | _] = escalus_config:get_config(escalus_users, Config),
   88:     remove_roster(Config, UserSpec),
   89:     escalus:end_per_testcase(add_contact, Config);
   90: end_per_testcase(roster_push, Config) ->
   91:     [{_, UserSpec} | _] = escalus_config:get_config(escalus_users, Config),
   92:     remove_roster(Config, UserSpec),
   93:     escalus:end_per_testcase(roster_push, Config);
   94: end_per_testcase(subscribe, Config) ->
   95:     end_rosters_remove(Config);
   96: end_per_testcase(decline_subscription, Config) ->
   97:     end_rosters_remove(Config);
   98: end_per_testcase(unsubscribe, Config) ->
   99:     end_rosters_remove(Config);
  100: end_per_testcase(CaseName, Config) ->
  101:     escalus:end_per_testcase(CaseName, Config).
  102: 
  103: end_rosters_remove(Config) ->
  104:     [{_, UserSpec1}, {_, UserSpec2} | _] =
  105:         escalus_config:get_config(escalus_users, Config),
  106:     remove_roster(Config, UserSpec1),
  107:     remove_roster(Config, UserSpec2),
  108:     escalus:end_per_testcase(subscription, Config).
  109: 
  110: %%--------------------------------------------------------------------
  111: %% Tests
  112: %%--------------------------------------------------------------------
  113: 
  114: get_roster(ConfigIn) ->
  115:     Metrics =
  116:         [{['_', modRosterGets], 1},
  117:          {[global, backends, mod_roster, get_roster], changed}
  118:         ],
  119:     Config = mongoose_metrics(ConfigIn, Metrics),
  120: 
  121:     escalus:story(Config, [{alice, 1}, {bob, 1}], fun(Alice,_Bob) ->
  122:         escalus_client:send(Alice, escalus_stanza:roster_get()),
  123:         escalus_client:wait_for_stanza(Alice)
  124: 
  125:         end).
  126: 
  127: add_contact(ConfigIn) ->
  128:     Config = mongoose_metrics(ConfigIn, [{['_', modRosterSets], 1}]),
  129: 
  130:     escalus:story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  131: 
  132:         %% add contact
  133:         escalus_client:send(Alice,
  134:                             escalus_stanza:roster_add_contact(Bob,
  135:                                                               [<<"friends">>],
  136:                                                               <<"Bobby">>)),
  137:         Received = escalus_client:wait_for_stanza(Alice),
  138:         escalus_client:send(Alice, escalus_stanza:iq_result(Received)),
  139:         escalus_client:wait_for_stanza(Alice)
  140: 
  141:         end).
  142: 
  143: roster_push(ConfigIn) ->
  144:     Config = mongoose_metrics(ConfigIn, [{['_', modRosterSets], 1},
  145:                                          {['_', modRosterPush], 2}]),
  146: 
  147:     escalus:story(Config, [{alice, 2}, {bob, 1}], fun(Alice1, Alice2, Bob) ->
  148: 
  149:         %% add contact
  150:         escalus_client:send(Alice1,
  151:                             escalus_stanza:roster_add_contact(Bob,
  152:                                                               [<<"friends">>],
  153:                                                               <<"Bobby">>)),
  154:         Received = escalus_client:wait_for_stanza(Alice1),
  155:         escalus_client:send(Alice1, escalus_stanza:iq_result(Received)),
  156:         escalus_client:wait_for_stanza(Alice1),
  157: 
  158:         Received2 = escalus_client:wait_for_stanza(Alice2),
  159:         escalus_client:send(Alice2, escalus_stanza:iq_result(Received2))
  160: 
  161:         end).
  162: 
  163: 
  164: subscribe(ConfigIn) ->
  165:     Config = mongoose_metrics(ConfigIn, [{['_', modPresenceSubscriptions], 1}]),
  166: 
  167:     escalus:story(Config, [{alice, 1}, {bob, 1}], fun(Alice,Bob) ->
  168:         BobJid = escalus_client:short_jid(Bob),
  169:         AliceJid = escalus_client:short_jid(Alice),
  170: 
  171:         %% add contact
  172:         add_sample_contact(Alice, Bob),
  173: 
  174:         %% subscribe
  175:         escalus_client:send(Alice, escalus_stanza:presence_direct(BobJid, <<"subscribe">>)),
  176:         PushReq = escalus_client:wait_for_stanza(Alice),
  177:         escalus_client:send(Alice, escalus_stanza:iq_result(PushReq)),
  178: 
  179:         %% Bob receives subscription request
  180:         escalus_client:wait_for_stanza(Bob),
  181: 
  182:         %% Bob adds new contact to his roster
  183:         escalus_client:send(Bob,
  184:                             escalus_stanza:roster_add_contact(Alice,
  185:                                                               [<<"enemies">>],
  186:                                                               <<"Alice">>)),
  187:         PushReqB = escalus_client:wait_for_stanza(Bob),
  188:         escalus_client:send(Bob, escalus_stanza:iq_result(PushReqB)),
  189:         escalus_client:wait_for_stanza(Bob),
  190: 
  191:         %% Bob sends subscribed presence
  192:         escalus_client:send(Bob, escalus_stanza:presence_direct(AliceJid, <<"subscribed">>)),
  193: 
  194:         %% Alice receives subscribed
  195:         escalus_client:wait_for_stanzas(Alice, 3),
  196: 
  197:         %% Bob receives roster push
  198:         escalus_client:wait_for_stanza(Bob)
  199: 
  200: 
  201:         end).
  202: 
  203: decline_subscription(ConfigIn) ->
  204:     Config = mongoose_metrics(ConfigIn, [{['_', modPresenceUnsubscriptions], 1}]),
  205: 
  206:     escalus:story(Config, [{alice, 1}, {bob, 1}], fun(Alice,Bob) ->
  207:         BobJid = escalus_client:short_jid(Bob),
  208:         AliceJid = escalus_client:short_jid(Alice),
  209: 
  210:         %% add contact
  211:         add_sample_contact(Alice, Bob),
  212: 
  213:         %% subscribe
  214:         escalus_client:send(Alice, escalus_stanza:presence_direct(BobJid, <<"subscribe">>)),
  215:         PushReq = escalus_client:wait_for_stanza(Alice),
  216:         escalus_client:send(Alice, escalus_stanza:iq_result(PushReq)),
  217: 
  218:         %% Bob receives subscription request
  219:         escalus_client:wait_for_stanza(Bob),
  220: 
  221:         %% Bob refuses subscription
  222:         escalus_client:send(Bob, escalus_stanza:presence_direct(AliceJid, <<"unsubscribed">>)),
  223: 
  224:         %% Alice receives subscribed
  225:         escalus_client:wait_for_stanzas(Alice, 2)
  226: 
  227:         end).
  228: 
  229: 
  230: unsubscribe(ConfigIn) ->
  231:     Config = mongoose_metrics(ConfigIn, [{['_', modPresenceUnsubscriptions], 1}]),
  232: 
  233:     escalus:story(Config, [{alice, 1}, {bob, 1}], fun(Alice,Bob) ->
  234:         BobJid = escalus_client:short_jid(Bob),
  235:         AliceJid = escalus_client:short_jid(Alice),
  236: 
  237:         %% add contact
  238:         add_sample_contact(Alice, Bob),
  239:         %% subscribe
  240:         escalus_client:send(Alice, escalus_stanza:presence_direct(BobJid, <<"subscribe">>)),
  241:         PushReq = escalus_client:wait_for_stanza(Alice),
  242: 
  243:         escalus_client:send(Alice, escalus_stanza:iq_result(PushReq)),
  244: 
  245:         %% Bob receives subscription request
  246:         escalus_client:wait_for_stanza(Bob),
  247:         %% Bob adds new contact to his roster
  248:         escalus_client:send(Bob,
  249:                             escalus_stanza:roster_add_contact(Alice,
  250:                                                               [<<"enemies">>],
  251:                                                               <<"Alice">>)),
  252:         PushReqB = escalus_client:wait_for_stanza(Bob),
  253:         escalus_client:send(Bob, escalus_stanza:iq_result(PushReqB)),
  254:         escalus_client:wait_for_stanza(Bob),
  255: 
  256:         %% Bob sends subscribed presence
  257:         escalus_client:send(Bob, escalus_stanza:presence_direct(AliceJid, <<"subscribed">>)),
  258: 
  259:         %% Alice receives subscribed
  260:         escalus_client:wait_for_stanzas(Alice, 2),
  261: 
  262:         escalus_client:wait_for_stanza(Alice),
  263: 
  264:         %% Bob receives roster push
  265:         PushReqB1 = escalus_client:wait_for_stanza(Bob),
  266:         escalus_assert:is_roster_set(PushReqB1),
  267: 
  268:         %% Alice sends unsubscribe
  269:         escalus_client:send(Alice, escalus_stanza:presence_direct(BobJid, <<"unsubscribe">>)),
  270: 
  271:         PushReqA2 = escalus_client:wait_for_stanza(Alice),
  272:         escalus_client:send(Alice, escalus_stanza:iq_result(PushReqA2)),
  273: 
  274:         %% Bob receives unsubscribe
  275: 
  276:         escalus_client:wait_for_stanzas(Bob, 2)
  277: 
  278:     end).
  279: 
  280: %%-----------------------------------------------------------------
  281: %% Helpers
  282: %%-----------------------------------------------------------------
  283: 
  284: add_sample_contact(Alice, Bob) ->
  285:     add_sample_contact(Alice, Bob, [<<"friends">>], <<"generic :p name">>).
  286: 
  287: add_sample_contact(Alice, Bob, Groups, Name) ->
  288:     escalus_client:send(Alice,
  289:         escalus_stanza:roster_add_contact(Bob, Groups, Name)),
  290:     RosterPush = escalus_client:wait_for_stanza(Alice),
  291:     escalus:assert(is_roster_set, RosterPush),
  292:     escalus_client:send(Alice, escalus_stanza:iq_result(RosterPush)),
  293:     escalus_client:wait_for_stanza(Alice).
  294: 
  295: 
  296: remove_roster(Config, UserSpec) ->
  297:     [Username, Server, _Pass] = escalus_users:get_usp(Config, UserSpec),
  298:     Acc = mongoose_helper:new_mongoose_acc(Server),
  299:     rpc(mim(), mod_roster, remove_user, [Acc, Username, Server]).
  300: 
  301: mongoose_metrics(ConfigIn, Metrics) ->
  302:     Predefined = proplists:get_value(mongoose_metrics, ConfigIn, []),
  303:     MongooseMetrics = Predefined ++ Metrics,
  304:     [{mongoose_metrics, MongooseMetrics} | ConfigIn].
  305: 
  306: roster_rdbms_precondition() ->
  307:     mod_roster_rdbms == rpc(mim(), mongoose_backend, get_backend_name, [domain_helper:host_type(), mod_roster]).