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:fresh_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:         end).
  125: 
  126: add_contact(ConfigIn) ->
  127:     Config = mongoose_metrics(ConfigIn, [{['_', modRosterSets], 1}]),
  128: 
  129:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  130: 
  131:         %% add contact
  132:         escalus_client:send(Alice,
  133:                             escalus_stanza:roster_add_contact(Bob,
  134:                                                               [<<"friends">>],
  135:                                                               <<"Bobby">>)),
  136:         Received = escalus_client:wait_for_stanza(Alice),
  137:         escalus_client:send(Alice, escalus_stanza:iq_result(Received)),
  138:         escalus_client:wait_for_stanza(Alice)
  139: 
  140:         end).
  141: 
  142: roster_push(ConfigIn) ->
  143:     Config = mongoose_metrics(ConfigIn, [{['_', modRosterSets], 1},
  144:                                          {['_', modRosterPush], 2}]),
  145: 
  146:     escalus:fresh_story(Config, [{alice, 2}, {bob, 1}], fun(Alice1, Alice2, Bob) ->
  147: 
  148:         %% add contact
  149:         escalus_client:send(Alice1,
  150:                             escalus_stanza:roster_add_contact(Bob,
  151:                                                               [<<"friends">>],
  152:                                                               <<"Bobby">>)),
  153:         Received = escalus_client:wait_for_stanza(Alice1),
  154:         escalus_client:send(Alice1, escalus_stanza:iq_result(Received)),
  155:         escalus_client:wait_for_stanza(Alice1),
  156: 
  157:         Received2 = escalus_client:wait_for_stanza(Alice2),
  158:         escalus_client:send(Alice2, escalus_stanza:iq_result(Received2))
  159: 
  160:         end).
  161: 
  162: 
  163: subscribe(ConfigIn) ->
  164:     Config = mongoose_metrics(ConfigIn, [{['_', modPresenceSubscriptions], 1}]),
  165: 
  166:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice,Bob) ->
  167:         BobJid = escalus_client:short_jid(Bob),
  168:         AliceJid = escalus_client:short_jid(Alice),
  169: 
  170:         %% add contact
  171:         add_sample_contact(Alice, Bob),
  172: 
  173:         %% subscribe
  174:         escalus_client:send(Alice, escalus_stanza:presence_direct(BobJid, <<"subscribe">>)),
  175:         PushReq = escalus_client:wait_for_stanza(Alice),
  176:         escalus_client:send(Alice, escalus_stanza:iq_result(PushReq)),
  177: 
  178:         %% Bob receives subscription request
  179:         escalus_client:wait_for_stanza(Bob),
  180: 
  181:         %% Bob adds new contact to his roster
  182:         escalus_client:send(Bob,
  183:                             escalus_stanza:roster_add_contact(Alice,
  184:                                                               [<<"enemies">>],
  185:                                                               <<"Alice">>)),
  186:         PushReqB = escalus_client:wait_for_stanza(Bob),
  187:         escalus_client:send(Bob, escalus_stanza:iq_result(PushReqB)),
  188:         escalus_client:wait_for_stanza(Bob),
  189: 
  190:         %% Bob sends subscribed presence
  191:         escalus_client:send(Bob, escalus_stanza:presence_direct(AliceJid, <<"subscribed">>)),
  192: 
  193:         %% Alice receives subscribed
  194:         escalus_client:wait_for_stanzas(Alice, 3),
  195: 
  196:         %% Bob receives roster push
  197:         escalus_client:wait_for_stanza(Bob)
  198: 
  199: 
  200:         end).
  201: 
  202: decline_subscription(ConfigIn) ->
  203:     Config = mongoose_metrics(ConfigIn, [{['_', modPresenceUnsubscriptions], 1}]),
  204: 
  205:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice,Bob) ->
  206:         BobJid = escalus_client:short_jid(Bob),
  207:         AliceJid = escalus_client:short_jid(Alice),
  208: 
  209:         %% add contact
  210:         add_sample_contact(Alice, Bob),
  211: 
  212:         %% subscribe
  213:         escalus_client:send(Alice, escalus_stanza:presence_direct(BobJid, <<"subscribe">>)),
  214:         PushReq = escalus_client:wait_for_stanza(Alice),
  215:         escalus_client:send(Alice, escalus_stanza:iq_result(PushReq)),
  216: 
  217:         %% Bob receives subscription request
  218:         escalus_client:wait_for_stanza(Bob),
  219: 
  220:         %% Bob refuses subscription
  221:         escalus_client:send(Bob, escalus_stanza:presence_direct(AliceJid, <<"unsubscribed">>)),
  222: 
  223:         %% Alice receives subscribed
  224:         escalus_client:wait_for_stanzas(Alice, 2)
  225: 
  226:         end).
  227: 
  228: 
  229: unsubscribe(ConfigIn) ->
  230:     Config = mongoose_metrics(ConfigIn, [{['_', modPresenceUnsubscriptions], 1}]),
  231: 
  232:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice,Bob) ->
  233:         BobJid = escalus_client:short_jid(Bob),
  234:         AliceJid = escalus_client:short_jid(Alice),
  235: 
  236:         %% add contact
  237:         add_sample_contact(Alice, Bob),
  238:         %% subscribe
  239:         escalus_client:send(Alice, escalus_stanza:presence_direct(BobJid, <<"subscribe">>)),
  240:         PushReq = escalus_client:wait_for_stanza(Alice),
  241: 
  242:         escalus_client:send(Alice, escalus_stanza:iq_result(PushReq)),
  243: 
  244:         %% Bob receives subscription request
  245:         escalus_client:wait_for_stanza(Bob),
  246:         %% Bob adds new contact to his roster
  247:         escalus_client:send(Bob,
  248:                             escalus_stanza:roster_add_contact(Alice,
  249:                                                               [<<"enemies">>],
  250:                                                               <<"Alice">>)),
  251:         PushReqB = escalus_client:wait_for_stanza(Bob),
  252:         escalus_client:send(Bob, escalus_stanza:iq_result(PushReqB)),
  253:         escalus_client:wait_for_stanza(Bob),
  254: 
  255:         %% Bob sends subscribed presence
  256:         escalus_client:send(Bob, escalus_stanza:presence_direct(AliceJid, <<"subscribed">>)),
  257: 
  258:         %% Alice receives subscribed
  259:         escalus_client:wait_for_stanzas(Alice, 2),
  260: 
  261:         escalus_client:wait_for_stanza(Alice),
  262: 
  263:         %% Bob receives roster push
  264:         PushReqB1 = escalus_client:wait_for_stanza(Bob),
  265:         escalus_assert:is_roster_set(PushReqB1),
  266: 
  267:         %% Alice sends unsubscribe
  268:         escalus_client:send(Alice, escalus_stanza:presence_direct(BobJid, <<"unsubscribe">>)),
  269: 
  270:         PushReqA2 = escalus_client:wait_for_stanza(Alice),
  271:         escalus_client:send(Alice, escalus_stanza:iq_result(PushReqA2)),
  272: 
  273:         %% Bob receives unsubscribe
  274: 
  275:         escalus_client:wait_for_stanzas(Bob, 2)
  276: 
  277:     end).
  278: 
  279: %%-----------------------------------------------------------------
  280: %% Helpers
  281: %%-----------------------------------------------------------------
  282: 
  283: add_sample_contact(Alice, Bob) ->
  284:     add_sample_contact(Alice, Bob, [<<"friends">>], <<"generic :p name">>).
  285: 
  286: add_sample_contact(Alice, Bob, Groups, Name) ->
  287:     escalus_client:send(Alice,
  288:         escalus_stanza:roster_add_contact(Bob, Groups, Name)),
  289:     RosterPush = escalus_client:wait_for_stanza(Alice),
  290:     escalus:assert(is_roster_set, RosterPush),
  291:     escalus_client:send(Alice, escalus_stanza:iq_result(RosterPush)),
  292:     escalus_client:wait_for_stanza(Alice).
  293: 
  294: 
  295: remove_roster(Config, UserSpec) ->
  296:     [Username, Server, _Pass] = escalus_users:get_usp(Config, UserSpec),
  297:     Acc = mongoose_helper:new_mongoose_acc(Server),
  298:     rpc(mim(), mod_roster, remove_user, [Acc, Username, Server]).
  299: 
  300: mongoose_metrics(ConfigIn, Metrics) ->
  301:     Predefined = proplists:get_value(mongoose_metrics, ConfigIn, []),
  302:     MongooseMetrics = Predefined ++ Metrics,
  303:     [{mongoose_metrics, MongooseMetrics} | ConfigIn].
  304: 
  305: roster_rdbms_precondition() ->
  306:     mod_roster_rdbms == rpc(mim(), mongoose_backend, get_backend_name, [domain_helper:host_type(), mod_roster]).