1: %%==============================================================================
    2: %% Copyright 2011 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: -module(private_SUITE).
   17: -compile([export_all, nowarn_export_all]).
   18: 
   19: -include_lib("exml/include/exml.hrl").
   20: -include_lib("escalus/include/escalus.hrl").
   21: -include_lib("common_test/include/ct.hrl").
   22: 
   23: %%--------------------------------------------------------------------
   24: %% Suite configuration
   25: %%--------------------------------------------------------------------
   26: all() ->
   27:     [{group, private_positive},
   28:      {group, private_negative}].
   29: 
   30: groups() ->
   31:     G = [{private_positive, [sequence], positive_test_cases()},
   32:          {private_negative, [sequence], negative_test_cases()}],
   33:     ct_helper:repeat_all_until_all_ok(G).
   34:     %% FIXME: broken exmpp prevents us from sending
   35:     %% out elements without NS set missing_ns]}].
   36: 
   37: positive_test_cases() ->
   38:     [store_retrieve].
   39: 
   40: negative_test_cases() ->
   41:     [get_other_user,
   42:      set_other_user].
   43: 
   44: suite() ->
   45:     escalus:suite().
   46: 
   47: init_per_suite(Config0) ->
   48:     HostType = domain_helper:host_type(),
   49:     Config1 = dynamic_modules:save_modules(HostType, Config0),
   50:     Backend = mongoose_helper:get_backend_mnesia_rdbms_riak(HostType),
   51:     ModConfig = create_config(Backend),
   52:     dynamic_modules:ensure_modules(HostType, ModConfig),
   53:     escalus:init_per_suite([{backend, Backend} | Config1]).
   54: 
   55: create_config(riak) ->
   56:     [{mod_private, #{backend => riak,
   57:                      iqdisc => one_queue,
   58:                      riak => #{bucket_type => <<"private">>}}}];
   59: create_config(Backend) ->
   60:     [{mod_private, #{backend => Backend, iqdisc => one_queue}}].
   61: 
   62: end_per_suite(Config) ->
   63:     dynamic_modules:restore_modules(Config),
   64:     escalus:end_per_suite(Config).
   65: 
   66: init_per_group(_GroupName, Config) ->
   67:     escalus:create_users(Config, escalus:get_users([alice, bob])).
   68: 
   69: end_per_group(_GroupName, Config) ->
   70:     escalus:delete_users(Config, escalus:get_users([alice, bob])).
   71: 
   72: init_per_testcase(CaseName, Config) ->
   73:     escalus:init_per_testcase(CaseName, Config).
   74: 
   75: end_per_testcase(CaseName, Config) ->
   76:     escalus:end_per_testcase(CaseName, Config).
   77: 
   78: %%--------------------------------------------------------------------
   79: %% Private storage tests
   80: %%--------------------------------------------------------------------
   81: store_retrieve(Config) ->
   82:     escalus:story(Config, [{alice, 1}],
   83:                   fun(Alice) ->
   84:                           NS = <<"alice:private:ns">>,
   85: 
   86:                           %% Alice stores some data in her private storage
   87:                           PrivateStanza = escalus_stanza:private_set(my_banana(NS)),
   88:                           escalus_client:send(Alice, PrivateStanza),
   89: 
   90:                           %% Alice receives store confirmation
   91:                           escalus:assert(
   92:                             is_iq_result,
   93:                             [PrivateStanza],
   94:                             escalus_client:wait_for_stanza(Alice)),
   95: 
   96:                           %% Alice asks for the data
   97:                           escalus_client:send(Alice, escalus_stanza:private_get(NS, <<"my_element">>)),
   98: 
   99:                           %% Alice ensures data has not been changed
  100:                           Stanza = escalus_client:wait_for_stanza(Alice),
  101:                           escalus:assert(is_private_result, Stanza),
  102:                           check_body(Stanza, [<<"my_element">>, <<"banana">>]),
  103: 
  104:                           %% Alice asks for non-existing data
  105:                           escalus_client:send(Alice, escalus_stanza:private_get(<<"non_existing_ns">>,
  106:                                                                                 <<"my_element">>)),
  107: 
  108:                           %% Alice receives an empty response
  109:                           Stanza2 = escalus_client:wait_for_stanza(Alice),
  110:                           escalus:assert(is_private_result, Stanza2),
  111:                           check_body(Stanza, [<<"my_element">>])
  112:                   end).
  113: 
  114: get_other_user(Config) ->
  115:     escalus:story(Config, [{alice, 1}, {bob, 1}],
  116:                   fun(Alice, _Bob) ->
  117:                           NS = <<"bob:private:ns">>,
  118: 
  119:                           %% Alice asks for Bob's private data
  120:                           GetIQ = escalus_stanza:private_get(NS, <<"my_element">>),
  121:                           IQ = escalus_stanza:to(GetIQ, escalus_users:get_jid(Config, bob)),
  122:                           escalus_client:send(Alice, IQ),
  123: 
  124:                           %% Alice gets an error
  125:                           Stanza = escalus_client:wait_for_stanza(Alice),
  126:                           escalus:assert(is_private_error, Stanza),
  127:                           escalus_pred:is_error(<<"cancel">>, forbidden, Stanza)
  128:                   end).
  129: 
  130: set_other_user(Config) ->
  131:     escalus:story(Config, [{alice, 1}, {bob, 1}],
  132:                   fun(Alice, _Bob) ->
  133:                           NS = <<"bob:private:ns">>,
  134: 
  135:                           %% Alice asks for Bob's private data
  136:                           IQ = escalus_stanza:to(escalus_stanza:private_set(my_banana(NS)),
  137:                                                  escalus_users:get_jid(Config, bob)),
  138:                           escalus_client:send(Alice, IQ),
  139: 
  140:                           %% Alice gets a forbidden error
  141:                           Stanza = escalus_client:wait_for_stanza(Alice),
  142:                           escalus:assert(is_private_error, Stanza),
  143:                           escalus_pred:is_error(<<"cancel">>, forbidden, Stanza)
  144:                   end).
  145: 
  146: missing_ns(Config) ->
  147:     escalus:story(Config, [{alice, 1}],
  148:                   fun(Alice) ->
  149:                           %% Alice asks for her own private storage, without
  150:                           %% providing a namespace for a child
  151:                           MyBanana = #xmlel{name = <<"my_element">>,
  152:                                                  children = [#xmlel{name = <<"banana">>}]},
  153:                           IQ = escalus_stanza:private_get(MyBanana),
  154:                           escalus_client:send(Alice, IQ),
  155: 
  156:                           %% Alice gets a bad-format error
  157:                           Stanza = escalus_client:wait_for_stanza(Alice),
  158:                           escalus:assert(is_private_error, Stanza),
  159:                           escalus_pred:is_error(<<"modify">>, 'bad-format', Stanza)
  160:                   end).
  161: 
  162: %%-----------------------------------------------------------------
  163: %% Helpers
  164: %%-----------------------------------------------------------------
  165: 
  166: my_banana(NS) ->
  167:     #xmlel{
  168:         name = <<"my_element">>,
  169:         attrs = [{<<"xmlns">>, NS}],
  170:         children = [#xmlel{name = <<"banana">>}]}.
  171: 
  172: check_body(Stanza, Names) ->
  173:     Query = exml_query:subelement(Stanza, <<"query">>),
  174:     check_body_rec(Query, Names).
  175: 
  176: check_body_rec(_, []) ->
  177:     ok;
  178: check_body_rec(Element, [Name | Names]) ->
  179:     [Child] = Element#xmlel.children,
  180:     Name = Child#xmlel.name,
  181:     check_body_rec(Child, Names).
  182: 
  183: required_modules(Backend) ->
  184:     [{mod_private, [{backend, Backend}]}].