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_fresh:clean(),
   76:     escalus:end_per_suite(Config).
   77: 
   78: init_per_group(_GroupName, Config) ->
   79:     escalus:create_users(Config, escalus:get_users([alice, bob])).
   80: 
   81: end_per_group(_GroupName, Config) ->
   82:     escalus:delete_users(Config, escalus:get_users([alice, bob])).
   83: 
   84: init_per_testcase(CaseName, Config) ->
   85:     escalus:init_per_testcase(CaseName, Config).
   86: 
   87: end_per_testcase(add_contact, Config) ->
   88:     [{_, UserSpec} | _] = escalus_config:get_config(escalus_users, Config),
   89:     remove_roster(Config, UserSpec),
   90:     escalus:end_per_testcase(add_contact, Config);
   91: end_per_testcase(roster_push, Config) ->
   92:     [{_, UserSpec} | _] = escalus_config:get_config(escalus_users, Config),
   93:     remove_roster(Config, UserSpec),
   94:     escalus:end_per_testcase(roster_push, Config);
   95: end_per_testcase(subscribe, Config) ->
   96:     end_rosters_remove(Config);
   97: end_per_testcase(decline_subscription, Config) ->
   98:     end_rosters_remove(Config);
   99: end_per_testcase(unsubscribe, Config) ->
  100:     end_rosters_remove(Config);
  101: end_per_testcase(CaseName, Config) ->
  102:     escalus:end_per_testcase(CaseName, Config).
  103: 
  104: end_rosters_remove(Config) ->
  105:     [{_, UserSpec1}, {_, UserSpec2} | _] =
  106:         escalus_config:get_config(escalus_users, Config),
  107:     remove_roster(Config, UserSpec1),
  108:     remove_roster(Config, UserSpec2),
  109:     escalus:end_per_testcase(subscription, Config).
  110: 
  111: %%--------------------------------------------------------------------
  112: %% Tests
  113: %%--------------------------------------------------------------------
  114: 
  115: get_roster(ConfigIn) ->
  116:     Metrics =
  117:         [{['_', modRosterGets], 1},
  118:          {[global, backends, mod_roster, get_roster], changed}
  119:         ],
  120:     Config = mongoose_metrics(ConfigIn, Metrics),
  121: 
  122:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice,_Bob) ->
  123:         escalus_client:send(Alice, escalus_stanza:roster_get()),
  124:         escalus_client:wait_for_stanza(Alice)
  125:         end).
  126: 
  127: add_contact(ConfigIn) ->
  128:     Config = mongoose_metrics(ConfigIn, [{['_', modRosterSets], 1}]),
  129: 
  130:     escalus:fresh_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:fresh_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:fresh_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:fresh_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:fresh_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:     Extra = #{host_type => domain_helper:host_type()},
  300:     Params = #{jid => jid:make_bare(Username, Server)},
  301:     rpc(mim(), mod_roster, remove_user, [Acc, Params, Extra]).
  302: 
  303: mongoose_metrics(ConfigIn, Metrics) ->
  304:     Predefined = proplists:get_value(mongoose_metrics, ConfigIn, []),
  305:     MongooseMetrics = Predefined ++ Metrics,
  306:     [{mongoose_metrics, MongooseMetrics} | ConfigIn].
  307: 
  308: roster_rdbms_precondition() ->
  309:     mod_roster_rdbms == rpc(mim(), mongoose_backend, get_backend_name, [domain_helper:host_type(), mod_roster]).