1: %% @doc Tests for the SSE handling of GraphQL subscriptions
    2: -module(graphql_sse_SUITE).
    3: 
    4: -compile([export_all, nowarn_export_all]).
    5: 
    6: -import(distributed_helper, [mim/0, require_rpc_nodes/1, rpc/4]).
    7: -import(graphql_helper, [get_bad_request/1, get_unauthorized/1, get_method_not_allowed/1,
    8:                          build_request/4, make_creds/1, execute_auth/2,
    9:                          execute_sse/3, execute_user_sse/3, execute_auth_sse/2]).
   10: 
   11: %% common_test callbacks
   12: 
   13: suite() ->
   14:     require_rpc_nodes([mim]) ++ escalus:suite().
   15: 
   16: all() ->
   17:     [{group, admin},
   18:      {group, user}].
   19: 
   20: groups() ->
   21:     [{admin, [parallel], admin_tests()},
   22:      {user, [parallel], user_tests()}].
   23: 
   24: init_per_suite(Config) ->
   25:     Config1 = escalus:init_per_suite(Config),
   26:     application:ensure_all_started(gun),
   27:     Config1.
   28: 
   29: end_per_suite(Config) ->
   30:     escalus:end_per_suite(Config).
   31: 
   32: init_per_group(user, Config) ->
   33:     graphql_helper:init_user(Config);
   34: init_per_group(admin, Config) ->
   35:     graphql_helper:init_admin_handler(Config).
   36: 
   37: end_per_group(user, _Config) ->
   38:     escalus_fresh:clean(),
   39:     graphql_helper:clean();
   40: end_per_group(admin, _Config) ->
   41:     graphql_helper:clean().
   42: 
   43: init_per_testcase(CaseName, Config) ->
   44:     escalus:init_per_testcase(CaseName, Config).
   45: 
   46: end_per_testcase(CaseName, Config) ->
   47:     escalus:end_per_testcase(CaseName, Config).
   48: 
   49: admin_tests() ->
   50:     [admin_missing_query,
   51:      admin_invalid_query_string,
   52:      admin_missing_creds,
   53:      admin_invalid_creds,
   54:      admin_invalid_method,
   55:      admin_invalid_operation_type].
   56: 
   57: user_tests() ->
   58:     [user_missing_query,
   59:      user_invalid_query_string,
   60:      user_missing_creds,
   61:      user_invalid_creds,
   62:      user_invalid_method,
   63:      user_invalid_operation_type].
   64: 
   65: %% Test cases and stories
   66: 
   67: admin_missing_query(Config) ->
   68:     get_bad_request(execute_auth_sse(#{}, Config)).
   69: 
   70: user_missing_query(Config) ->
   71:     escalus:fresh_story_with_config(Config, [{alice, 1}], fun user_missing_query_story/2).
   72: 
   73: user_missing_query_story(Config, Alice) ->
   74:     get_bad_request(execute_user_sse(#{}, Alice, Config)).
   75: 
   76: admin_invalid_query_string(_Config) ->
   77:     Port = graphql_helper:get_listener_port(admin),
   78:     get_bad_request(sse_helper:connect_to_sse(Port, "/api/graphql/sse?=invalid", undefined, #{})).
   79: 
   80: user_invalid_query_string(Config) ->
   81:     escalus:fresh_story(Config, [{alice, 1}], fun user_invalid_query_string_story/1).
   82: 
   83: user_invalid_query_string_story(Alice) ->
   84:     Port = graphql_helper:get_listener_port(user),
   85:     Creds = make_creds(Alice),
   86:     get_bad_request(sse_helper:connect_to_sse(Port, "/api/graphql/sse?=invalid", Creds, #{})).
   87: 
   88: admin_missing_creds(_Config) ->
   89:     get_unauthorized(execute_sse(admin, #{query => doc(), variables => args()}, undefined)).
   90: 
   91: user_missing_creds(_Config) ->
   92:     get_unauthorized(execute_sse(user, #{query => doc()}, undefined)).
   93: 
   94: admin_invalid_creds(_Config) ->
   95:     Creds = {<<"invalid">>, <<"creds">>},
   96:     get_unauthorized(execute_sse(admin, #{query => doc(), variables => args()}, Creds)).
   97: 
   98: user_invalid_creds(_Config) ->
   99:     get_unauthorized(execute_sse(user, #{query => doc()}, {<<"invalid">>, <<"creds">>})).
  100: 
  101: admin_invalid_method(_Config) ->
  102:     #{node := Node} = mim(),
  103:     Request = build_request(Node, admin, #{query => doc(), variables => args()}, undefined),
  104:     %% POST was used, while SSE accepts only GET
  105:     get_method_not_allowed(rest_helper:make_request(Request#{path => "/graphql/sse"})).
  106: 
  107: user_invalid_method(Config) ->
  108:     escalus:fresh_story(Config, [{alice, 1}], fun user_invalid_method_story/1).
  109: 
  110: user_invalid_method_story(Alice) ->
  111:     #{node := Node} = mim(),
  112:     Request = build_request(Node, user, #{query => doc()}, make_creds(Alice)),
  113:     %% POST was used, while SSE accepts only GET
  114:     get_method_not_allowed(rest_helper:make_request(Request#{path => "/graphql/sse"})).
  115: 
  116: admin_invalid_operation_type(Config) ->
  117:     Creds = graphql_helper:make_admin_creds(admin, Config),
  118:     get_bad_request(execute_sse(admin, #{query => query_doc(), variables => args()}, Creds)).
  119: 
  120: user_invalid_operation_type(Config) ->
  121:     escalus:fresh_story(Config, [{alice, 1}], fun user_invalid_operation_type_story/1).
  122: 
  123: user_invalid_operation_type_story(Alice) ->
  124:     get_bad_request(execute_sse(user, #{query => query_doc()}, make_creds(Alice))).
  125: 
  126: %% Helpers
  127: 
  128: %% Subscription - works only with the SSE handler
  129: doc() ->
  130:     graphql_helper:get_doc(<<"stanza">>, <<"subscribeForMessages">>).
  131: 
  132: %% Query - works only with the REST handler
  133: query_doc() ->
  134:     graphql_helper:get_doc(<<"stanza">>, <<"getLastMessages">>).
  135: 
  136: %% Same args used by both operations - only for Admin
  137: args() ->
  138:     #{caller => <<"alice@localhost">>}.