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 = mongoose_helper:backend_for_module(mod_private, Backend),
   52:     dynamic_modules:ensure_modules(HostType, ModConfig),
   53:     escalus:init_per_suite([{backend, Backend} | Config1]).
   54: 
   55: end_per_suite(Config) ->
   56:     dynamic_modules:restore_modules(Config),
   57:     escalus:end_per_suite(Config).
   58: 
   59: init_per_group(_GroupName, Config) ->
   60:     escalus:create_users(Config, escalus:get_users([alice, bob])).
   61: 
   62: end_per_group(_GroupName, Config) ->
   63:     escalus:delete_users(Config, escalus:get_users([alice, bob])).
   64: 
   65: init_per_testcase(CaseName, Config) ->
   66:     escalus:init_per_testcase(CaseName, Config).
   67: 
   68: end_per_testcase(CaseName, Config) ->
   69:     escalus:end_per_testcase(CaseName, Config).
   70: 
   71: %%--------------------------------------------------------------------
   72: %% Private storage tests
   73: %%--------------------------------------------------------------------
   74: store_retrieve(Config) ->
   75:     escalus:story(Config, [{alice, 1}],
   76:                   fun(Alice) ->
   77:                           NS = <<"alice:private:ns">>,
   78: 
   79:                           %% Alice stores some data in her private storage
   80:                           PrivateStanza = escalus_stanza:private_set(my_banana(NS)),
   81:                           escalus_client:send(Alice, PrivateStanza),
   82: 
   83:                           %% Alice receives store confirmation
   84:                           escalus:assert(
   85:                             is_iq_result,
   86:                             [PrivateStanza],
   87:                             escalus_client:wait_for_stanza(Alice)),
   88: 
   89:                           %% Alice asks for the data
   90:                           escalus_client:send(Alice, escalus_stanza:private_get(NS, <<"my_element">>)),
   91: 
   92:                           %% Alice ensures data has not been changed
   93:                           Stanza = escalus_client:wait_for_stanza(Alice),
   94:                           escalus:assert(is_private_result, Stanza),
   95:                           check_body(Stanza, [<<"my_element">>, <<"banana">>]),
   96: 
   97:                           %% Alice asks for non-existing data
   98:                           escalus_client:send(Alice, escalus_stanza:private_get(<<"non_existing_ns">>,
   99:                                                                                 <<"my_element">>)),
  100: 
  101:                           %% Alice receives an empty response
  102:                           Stanza2 = escalus_client:wait_for_stanza(Alice),
  103:                           escalus:assert(is_private_result, Stanza2),
  104:                           check_body(Stanza, [<<"my_element">>])
  105:                   end).
  106: 
  107: get_other_user(Config) ->
  108:     escalus:story(Config, [{alice, 1}, {bob, 1}],
  109:                   fun(Alice, _Bob) ->
  110:                           NS = <<"bob:private:ns">>,
  111: 
  112:                           %% Alice asks for Bob's private data
  113:                           GetIQ = escalus_stanza:private_get(NS, <<"my_element">>),
  114:                           IQ = escalus_stanza:to(GetIQ, escalus_users:get_jid(Config, bob)),
  115:                           escalus_client:send(Alice, IQ),
  116: 
  117:                           %% Alice gets an error
  118:                           Stanza = escalus_client:wait_for_stanza(Alice),
  119:                           escalus:assert(is_private_error, Stanza),
  120:                           escalus_pred:is_error(<<"cancel">>, forbidden, Stanza)
  121:                   end).
  122: 
  123: set_other_user(Config) ->
  124:     escalus:story(Config, [{alice, 1}, {bob, 1}],
  125:                   fun(Alice, _Bob) ->
  126:                           NS = <<"bob:private:ns">>,
  127: 
  128:                           %% Alice asks for Bob's private data
  129:                           IQ = escalus_stanza:to(escalus_stanza:private_set(my_banana(NS)),
  130:                                                  escalus_users:get_jid(Config, bob)),
  131:                           escalus_client:send(Alice, IQ),
  132: 
  133:                           %% Alice gets a forbidden error
  134:                           Stanza = escalus_client:wait_for_stanza(Alice),
  135:                           escalus:assert(is_private_error, Stanza),
  136:                           escalus_pred:is_error(<<"cancel">>, forbidden, Stanza)
  137:                   end).
  138: 
  139: missing_ns(Config) ->
  140:     escalus:story(Config, [{alice, 1}],
  141:                   fun(Alice) ->
  142:                           %% Alice asks for her own private storage, without
  143:                           %% providing a namespace for a child
  144:                           MyBanana = #xmlel{name = <<"my_element">>,
  145:                                                  children = [#xmlel{name = <<"banana">>}]},
  146:                           IQ = escalus_stanza:private_get(MyBanana),
  147:                           escalus_client:send(Alice, IQ),
  148: 
  149:                           %% Alice gets a bad-format error
  150:                           Stanza = escalus_client:wait_for_stanza(Alice),
  151:                           escalus:assert(is_private_error, Stanza),
  152:                           escalus_pred:is_error(<<"modify">>, 'bad-format', Stanza)
  153:                   end).
  154: 
  155: %%-----------------------------------------------------------------
  156: %% Helpers
  157: %%-----------------------------------------------------------------
  158: 
  159: my_banana(NS) ->
  160:     #xmlel{
  161:         name = <<"my_element">>,
  162:         attrs = [{<<"xmlns">>, NS}],
  163:         children = [#xmlel{name = <<"banana">>}]}.
  164: 
  165: check_body(Stanza, Names) ->
  166:     Query = exml_query:subelement(Stanza, <<"query">>),
  167:     check_body_rec(Query, Names).
  168: 
  169: check_body_rec(_, []) ->
  170:     ok;
  171: check_body_rec(Element, [Name | Names]) ->
  172:     [Child] = Element#xmlel.children,
  173:     Name = Child#xmlel.name,
  174:     check_body_rec(Child, Names).
  175: 
  176: required_modules(Backend) ->
  177:     [{mod_private, [{backend, Backend}]}].