1: -module(graphql_http_upload_SUITE).
    2: 
    3: -compile([export_all, nowarn_export_all]).
    4: 
    5: -import(common_helper, [unprep/1]).
    6: -import(distributed_helper, [mim/0, require_rpc_nodes/1]).
    7: -import(domain_helper, [host_type/0, domain/0, secondary_domain/0]).
    8: -import(graphql_helper, [execute_user_command/5, execute_command/4, get_ok_value/2,
    9:                          get_err_msg/1, get_err_code/1, get_coercion_err_msg/1, get_unauthorized/1]).
   10: 
   11: -include_lib("eunit/include/eunit.hrl").
   12: 
   13: -define(S3_HOSTNAME, <<"http://bucket.s3-eu-east-25.example.com">>).
   14: 
   15: suite() ->
   16:     require_rpc_nodes([mim]) ++ escalus:suite().
   17: 
   18: all() ->
   19:     [{group, user},
   20:      {group, admin_http},
   21:      {group, admin_cli},
   22:      {group, domain_admin}].
   23: 
   24: groups() ->
   25:     [{user, [], user_groups()},
   26:      {admin_http, [], admin_groups()},
   27:      {admin_cli, [], admin_groups()},
   28:      {domain_admin, [], domain_admin_groups()},
   29:      {user_http_upload, [], user_http_upload_tests()},
   30:      {user_http_upload_not_configured, [], user_http_upload_not_configured_tests()},
   31:      {admin_http_upload, [], admin_http_upload_tests()},
   32:      {admin_http_upload_not_configured, [], admin_http_upload_not_configured_tests()},
   33:      {domain_admin_http_upload, [], domain_admin_http_upload_tests()},
   34:      {domain_admin_http_upload_not_configured, [], domain_admin_http_upload_not_configured_tests()}].
   35: 
   36: user_groups() ->
   37:     [{group, user_http_upload},
   38:      {group, user_http_upload_not_configured}].
   39: 
   40: admin_groups() ->
   41:     [{group, admin_http_upload},
   42:      {group, admin_http_upload_not_configured}].
   43: 
   44: domain_admin_groups() ->
   45:     [{group, domain_admin_http_upload},
   46:      {group, domain_admin_http_upload_not_configured}].
   47: 
   48: user_http_upload_tests() ->
   49:     [user_get_url_test,
   50:      user_get_url_test_no_content_type,
   51:      user_get_url_test_empty_filename,
   52:      user_get_url_zero_size,
   53:      user_get_url_too_large_size,
   54:      user_get_url_zero_timeout].
   55: 
   56: user_http_upload_not_configured_tests() ->
   57:     [user_http_upload_not_configured].
   58: 
   59: admin_http_upload_tests() ->
   60:     [admin_get_url_test,
   61:      admin_get_url_test_no_content_type,
   62:      admin_get_url_test_empty_filename,
   63:      admin_get_url_zero_size,
   64:      admin_get_url_too_large_size,
   65:      admin_get_url_zero_timeout,
   66:      admin_get_url_no_domain].
   67: 
   68: admin_http_upload_not_configured_tests() ->
   69:     [admin_http_upload_not_configured].
   70: 
   71: domain_admin_http_upload_tests() ->
   72:     [admin_get_url_test,
   73:      admin_get_url_test_no_content_type,
   74:      admin_get_url_test_empty_filename,
   75:      admin_get_url_zero_size,
   76:      admin_get_url_too_large_size,
   77:      admin_get_url_zero_timeout,
   78:      domain_admin_get_url_no_permission].
   79: 
   80: domain_admin_http_upload_not_configured_tests() ->
   81:     [admin_http_upload_not_configured].
   82: 
   83: init_per_suite(Config) ->
   84:     Config1 = dynamic_modules:save_modules(host_type(), Config),
   85:     Config2 = ejabberd_node_utils:init(mim(), Config1),
   86:     escalus:init_per_suite(Config2).
   87: 
   88: end_per_suite(Config) ->
   89:     dynamic_modules:restore_modules(Config),
   90:     escalus:end_per_suite(Config).
   91: 
   92: init_per_group(user, Config) ->
   93:     graphql_helper:init_user(Config);
   94: init_per_group(admin_http, Config) ->
   95:     graphql_helper:init_admin_handler(Config);
   96: init_per_group(admin_cli, Config) ->
   97:     graphql_helper:init_admin_cli(Config);
   98: init_per_group(domain_admin, Config) ->
   99:     graphql_helper:init_domain_admin_handler(Config);
  100: init_per_group(user_http_upload, Config) ->
  101:     dynamic_modules:ensure_modules(host_type(),
  102:         [{mod_http_upload, create_opts(?S3_HOSTNAME, true)}]),
  103:     Config;
  104: init_per_group(user_http_upload_not_configured, Config) ->
  105:     dynamic_modules:ensure_modules(host_type(), [{mod_http_upload, stopped}]),
  106:     Config;
  107: init_per_group(admin_http_upload, Config) ->
  108:     dynamic_modules:ensure_modules(host_type(),
  109:         [{mod_http_upload, create_opts(?S3_HOSTNAME, true)}]),
  110:     Config;
  111: init_per_group(domain_admin_http_upload, Config) ->
  112:     dynamic_modules:ensure_modules(host_type(),
  113:         [{mod_http_upload, create_opts(?S3_HOSTNAME, true)}]),
  114:     Config;
  115: init_per_group(admin_http_upload_not_configured, Config) ->
  116:     dynamic_modules:ensure_modules(host_type(), [{mod_http_upload, stopped}]),
  117:     Config;
  118: init_per_group(domain_admin_http_upload_not_configured, Config) ->
  119:     dynamic_modules:ensure_modules(host_type(), [{mod_http_upload, stopped}]),
  120:     Config.
  121: 
  122: end_per_group(GroupName, _Config) when GroupName =:= user;
  123:                                        GroupName =:= admin_http;
  124:                                        GroupName =:= admin_cli ->
  125:     graphql_helper:clean();
  126: end_per_group(_, _Config) ->
  127:     escalus_fresh:clean().
  128: 
  129: init_per_testcase(CaseName, Config) ->
  130:     escalus:init_per_testcase(CaseName, Config).
  131: 
  132: end_per_testcase(CaseName, Config) ->
  133:     escalus:end_per_testcase(CaseName, Config).
  134: 
  135: create_opts(Host, AddAcl) ->
  136:     config_parser_helper:mod_config(mod_http_upload,
  137:         #{
  138:             max_file_size => 1234,
  139:             s3 => #{
  140:                 bucket_url => Host,
  141:                 add_acl => AddAcl,
  142:                 region => <<"eu-east-25">>,
  143:                 access_key_id => <<"AKIAIAOAONIULXQGMOUA">>,
  144:                 secret_access_key => <<"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">>
  145:             }
  146:         }).
  147: 
  148: % User test cases
  149: 
  150: user_get_url_test(Config) ->
  151:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  152:                                     fun user_get_url_test/2).
  153: 
  154: user_get_url_test(Config, Alice) ->
  155:     Result = user_get_url(<<"test">>, 123, <<"Test">>, 123, Alice, Config),
  156:     ParsedResult = get_ok_value([data, httpUpload, getUrl], Result),
  157:     #{<<"putUrl">> := PutURL, <<"getUrl">> := GetURL, <<"headers">> := _Headers} = ParsedResult,
  158:     ?assertMatch({_, _}, binary:match(PutURL, [?S3_HOSTNAME])),
  159:     ?assertMatch({_, _}, binary:match(GetURL, [?S3_HOSTNAME])).
  160: 
  161: user_get_url_test_no_content_type(Config) ->
  162:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  163:                                     fun user_get_url_test_no_content_type/2).
  164: 
  165: user_get_url_test_no_content_type(Config, Alice) ->
  166:     user_get_url_test_no_content_type(Config, Alice, null),
  167:     user_get_url_test_no_content_type(Config, Alice, <<"">>).
  168: 
  169: user_get_url_test_no_content_type(Config, Alice, ContentType) ->
  170:     Result = user_get_url(<<"test">>, 123, ContentType, 123, Alice, Config),
  171:     ParsedResult = get_ok_value([data, httpUpload, getUrl], Result),
  172:     #{<<"putUrl">> := PutURL, <<"getUrl">> := GetURL, <<"headers">> := _Headers} = ParsedResult,
  173:     ?assertMatch({_, _}, binary:match(PutURL, [?S3_HOSTNAME])),
  174:     ?assertMatch({_, _}, binary:match(GetURL, [?S3_HOSTNAME])).
  175: 
  176: user_get_url_test_empty_filename(Config) ->
  177:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  178:                                     fun user_get_url_test_empty_filename/2).
  179: 
  180: user_get_url_test_empty_filename(Config, Alice) ->
  181:     Result = user_get_url(<<"">>, 123, <<"Test">>, 123, Alice, Config),
  182:     ?assertMatch({_, _}, binary:match(get_coercion_err_msg(Result), <<"Given string is empty">>)).
  183: 
  184: user_get_url_zero_size(Config) ->
  185:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  186:                                     fun user_get_url_zero_size/2).
  187: 
  188: user_get_url_zero_size(Config, Alice) ->
  189:     Result = user_get_url(<<"test">>, 0, <<"Test">>, 123, Alice, Config),
  190:     ?assertMatch({_, _}, binary:match(get_coercion_err_msg(Result), <<"Value is not a positive integer">>)).
  191: 
  192: user_get_url_too_large_size(Config) ->
  193:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  194:                                     fun user_get_url_too_large_size/2).
  195: 
  196: user_get_url_too_large_size(Config, Alice) ->
  197:     Result = user_get_url(<<"test">>, 100000, <<"Test">>, 123, Alice, Config),
  198:     ?assertEqual(<<"file_too_large_error">>, get_err_code(Result)),
  199:     ?assertMatch(<<"Declared file size exceeds", _/bits>>, get_err_msg(Result)).
  200: 
  201: user_get_url_zero_timeout(Config) ->
  202:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  203:                                     fun user_get_url_zero_timeout/2).
  204: 
  205: user_get_url_zero_timeout(Config, Alice) ->
  206:     Result = user_get_url(<<"test">>, 123, <<"Test">>, 0, Alice, Config),
  207:     ?assertMatch({_, _}, binary:match(get_coercion_err_msg(Result), <<"Value is not a positive integer">>)).
  208: 
  209: user_http_upload_not_configured(Config) ->
  210:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  211:                                     fun user_http_upload_not_configured/2).
  212: 
  213: user_http_upload_not_configured(Config, Alice) ->
  214:     Result = user_get_url(<<"test">>, 123, <<"Test">>, 123, Alice, Config),
  215:     ?assertEqual(<<"deps_not_loaded">>, get_err_code(Result)),
  216:     ?assertEqual(<<"Some of the required modules are not loaded">>, get_err_msg(Result)).
  217: 
  218: % Admin test cases
  219: 
  220: admin_get_url_test(Config) ->
  221:     admin_get_url_test(Config, domain()),
  222:     admin_get_url_test(Config, unprep(domain())).
  223: 
  224: admin_get_url_test(Config, Domain) ->
  225:     Result = admin_get_url(Domain, <<"test">>, 123, <<"Test">>, 123, Config),
  226:     ParsedResult = get_ok_value([data, httpUpload, getUrl], Result),
  227:     #{<<"putUrl">> := PutURL, <<"getUrl">> := GetURL, <<"headers">> := _Headers} = ParsedResult,
  228:     ?assertMatch({_, _}, binary:match(PutURL, [?S3_HOSTNAME])),
  229:     ?assertMatch({_, _}, binary:match(GetURL, [?S3_HOSTNAME])).
  230: 
  231: admin_get_url_test_no_content_type(Config) ->
  232:     admin_get_url_test_no_content_type(Config, null),
  233:     admin_get_url_test_no_content_type(Config, <<"">>).
  234: 
  235: admin_get_url_test_no_content_type(Config, ContentType) ->
  236:     Result = admin_get_url(domain(), <<"test">>, 123, ContentType, 123, Config),
  237:     ParsedResult = get_ok_value([data, httpUpload, getUrl], Result),
  238:     #{<<"putUrl">> := PutURL, <<"getUrl">> := GetURL, <<"headers">> := _Headers} = ParsedResult,
  239:     ?assertMatch({_, _}, binary:match(PutURL, [?S3_HOSTNAME])),
  240:     ?assertMatch({_, _}, binary:match(GetURL, [?S3_HOSTNAME])).
  241: 
  242: admin_get_url_test_empty_filename(Config) ->
  243:     Result = admin_get_url(domain(), <<"">>, 123, <<"Test">>, 123, Config),
  244:     ?assertMatch({_, _}, binary:match(get_coercion_err_msg(Result), <<"Given string is empty">>)).
  245: 
  246: admin_get_url_zero_size(Config) ->
  247:     Result = admin_get_url(domain(), <<"test">>, 0, <<"Test">>, 123, Config),
  248:     ?assertMatch({_, _}, binary:match(get_coercion_err_msg(Result), <<"Value is not a positive integer">>)).
  249: 
  250: admin_get_url_too_large_size(Config) ->
  251:     Result = admin_get_url(domain(), <<"test">>, 100000, <<"Test">>, 123, Config),
  252:     ?assertEqual(<<"file_too_large_error">>, get_err_code(Result)),
  253:     ?assertMatch(<<"Declared file size exceeds", _/bits>>, get_err_msg(Result)).
  254: 
  255: admin_get_url_zero_timeout(Config) ->
  256:     Result = admin_get_url(domain(), <<"test">>, 123, <<"Test">>, 0, Config),
  257:     ?assertMatch({_, _}, binary:match(get_coercion_err_msg(Result), <<"Value is not a positive integer">>)).
  258: 
  259: admin_get_url_no_domain(Config) ->
  260:     Result = admin_get_url(<<"AAAAA">>, <<"test">>, 123, <<"Test">>, 123, Config),
  261:     ?assertEqual(<<"domain_not_found">>, get_err_code(Result)),
  262:     ?assertEqual(<<"domain does not exist">>, get_err_msg(Result)).
  263: 
  264: admin_http_upload_not_configured(Config) ->
  265:     admin_http_upload_not_configured(Config, domain()),
  266:     admin_http_upload_not_configured(Config, unprep(domain())).
  267: 
  268: admin_http_upload_not_configured(Config, Domain) ->
  269:     Result = admin_get_url(Domain, <<"test">>, 123, <<"Test">>, 123, Config),
  270:     ?assertEqual(<<"deps_not_loaded">>, get_err_code(Result)),
  271:     ?assertEqual(<<"Some of the required modules are not loaded">>, get_err_msg(Result)).
  272: 
  273: domain_admin_get_url_no_permission(Config) ->
  274:     Result1 = admin_get_url(<<"AAAAA">>, <<"test">>, 123, <<"Test">>, 123, Config),
  275:     get_unauthorized(Result1),
  276:     Result2 = admin_get_url(secondary_domain(), <<"test">>, 123, <<"Test">>, 123, Config),
  277:     get_unauthorized(Result2).
  278: 
  279: % Helpers
  280: 
  281: user_get_url(FileName, Size, ContentType, Timeout, User, Config) ->
  282:     Vars = #{<<"filename">> => FileName, <<"size">> => Size,
  283:              <<"contentType">> => ContentType, <<"timeout">> => Timeout},
  284:     execute_user_command(<<"httpUpload">>, <<"getUrl">>, User, Vars, Config).
  285: 
  286: admin_get_url(Domain, FileName, Size, ContentType, Timeout, Config) ->
  287:     Vars = #{<<"domain">> => Domain, <<"filename">> => FileName, <<"size">> => Size,
  288:              <<"contentType">> => ContentType, <<"timeout">> => Timeout},
  289:     execute_command(<<"httpUpload">>, <<"getUrl">>, Vars, Config).