1: -module(graphql_domain_SUITE).
    2: 
    3:  -include_lib("common_test/include/ct.hrl").
    4:  -include_lib("eunit/include/eunit.hrl").
    5:  -include_lib("exml/include/exml.hrl").
    6: 
    7:  -compile([export_all, nowarn_export_all]).
    8: 
    9: -import(distributed_helper, [mim/0, require_rpc_nodes/1, rpc/4]).
   10: -import(graphql_helper, [execute_auth/2, init_admin_handler/1]).
   11: 
   12: -define(HOST_TYPE, <<"dummy auth">>).
   13: -define(SECOND_HOST_TYPE, <<"test type">>).
   14: 
   15: suite() ->
   16:     require_rpc_nodes([mim]) ++ escalus:suite().
   17: 
   18: all() ->
   19:      [{group, domain_handler}].
   20: 
   21: groups() ->
   22:      [{domain_handler, [sequence], domain_handler()}].
   23: 
   24: domain_handler() ->
   25:     [create_domain,
   26:      unknown_host_type_error_formatting,
   27:      static_domain_error_formatting,
   28:      domain_duplicate_error_formatting,
   29:      domain_not_found_error_formatting_after_mutation_disable_domain,
   30:      domain_not_found_error_formatting_after_mutation_enable_domain,
   31:      domain_not_found_error_formatting_after_query,
   32:      wrong_host_type_error_formatting,
   33:      disable_domain,
   34:      enable_domain,
   35:      get_domains_by_host_type,
   36:      get_domain_details,
   37:      delete_domain,
   38:      get_domains_after_deletion,
   39:      set_domain_password,
   40:      set_nonexistent_domain_password,
   41:      delete_domain_password
   42:     ].
   43: 
   44: init_per_suite(Config) ->
   45:     case mongoose_helper:is_rdbms_enabled(?HOST_TYPE) of
   46:         true -> escalus:init_per_suite(init_admin_handler(Config));
   47:         false -> {skip, require_rdbms}
   48:     end.
   49: 
   50: end_per_suite(Config) ->
   51:     escalus_fresh:clean(),
   52:     escalus:end_per_suite(Config).
   53: 
   54: init_per_testcase(CaseName, Config) ->
   55:      escalus:init_per_testcase(CaseName, Config).
   56: 
   57: end_per_testcase(CaseName, Config) ->
   58:      escalus:end_per_testcase(CaseName, Config).
   59: 
   60: create_domain(Config) ->
   61:     create_domain(Config, <<"exampleDomain">>),
   62:     create_domain(Config, <<"exampleDomain2">>).
   63: 
   64: create_domain(Config, DomainName) ->
   65:     Vars = #{domain => DomainName, hostType => ?HOST_TYPE},
   66:     Result = execute_auth(#{query => create_domain_call(), variables => Vars,
   67:         operationName => <<"M1">>}, Config),
   68:     ParsedResult = ok_result(<<"domains">>, <<"addDomain">>, Result),
   69:     ?assertEqual(#{<<"domain">> => DomainName,
   70:         <<"hostType">> => ?HOST_TYPE,
   71:         <<"enabled">> => null}, ParsedResult).
   72: 
   73: unknown_host_type_error_formatting(Config) ->
   74:     DomainName = <<"exampleDomain">>,
   75:     HostType = <<"NonExistingHostType">>,
   76:     Vars = #{domain => DomainName, hostType => HostType},
   77:     Result = execute_auth(#{query => create_domain_call(), variables => Vars,
   78:                    operationName => <<"M1">>}, Config),
   79:     ParsedResult = error_result(1, Result),
   80:     ?assertEqual(#{<<"extensions">> =>
   81:                      #{<<"code">> => <<"unknown_host_type">>,
   82:                        <<"hostType">> => HostType},
   83:                    <<"message">> => <<"Unknown host type">>,
   84:                    <<"path">> => [<<"domains">>, <<"addDomain">>]}, ParsedResult).
   85: 
   86: static_domain_error_formatting(Config) ->
   87:     DomainName = <<"localhost">>,
   88:     Vars = #{domain => DomainName, hostType => ?HOST_TYPE},
   89:     Result = execute_auth(#{query => create_domain_call(), variables => Vars,
   90:                    operationName => <<"M1">>}, Config),
   91:     ParsedResult = error_result(1, Result),
   92:     ?assertEqual(#{<<"extensions">> =>
   93:                      #{<<"code">> => <<"domain_static">>,
   94:                        <<"domain">> => DomainName},
   95:                    <<"message">> => <<"Domain static">>,
   96:                    <<"path">> => [<<"domains">>, <<"addDomain">>]}, ParsedResult).
   97: 
   98: domain_duplicate_error_formatting(Config) ->
   99:     DomainName = <<"exampleDomain">>,
  100:     Vars = #{domain => DomainName, hostType => ?SECOND_HOST_TYPE},
  101:     Result = execute_auth(#{query => create_domain_call(), variables => Vars,
  102:                    operationName => <<"M1">>}, Config),
  103:     ParsedResult = error_result(1, Result),
  104:     ?assertEqual(#{<<"extensions">> =>
  105:                      #{<<"code">> => <<"domain_duplicate">>,
  106:                        <<"domain">> => DomainName},
  107:                    <<"message">> => <<"Domain already exists">>,
  108:                    <<"path">> => [<<"domains">>, <<"addDomain">>]}, ParsedResult).
  109: 
  110: domain_not_found_error_formatting_after_mutation_enable_domain(Config) ->
  111:     DomainName = <<"NonExistingDomain">>,
  112:     Vars = #{domain => DomainName},
  113:     Result = execute_auth(#{query => enable_domain_call(), variables => Vars,
  114:                    operationName => <<"M1">>}, Config),
  115:     domain_not_found_error_formatting(Result, DomainName, <<"enableDomain">>).
  116: 
  117: domain_not_found_error_formatting_after_mutation_disable_domain(Config) ->
  118:     DomainName = <<"NonExistingDomain">>,
  119:     Vars = #{domain => DomainName},
  120:     Result = execute_auth(#{query => disable_domain_call(), variables => Vars,
  121:                    operationName => <<"M1">>}, Config),
  122:     domain_not_found_error_formatting(Result, DomainName, <<"disableDomain">>).
  123: 
  124: domain_not_found_error_formatting_after_query(Config) ->
  125:     DomainName = <<"NonExistingDomain">>,
  126:     Vars = #{domain => DomainName},
  127:     Result = execute_auth(#{query => get_domain_details_call(), variables => Vars,
  128:                    operationName => <<"Q1">>}, Config),
  129:     domain_not_found_error_formatting(Result, DomainName, <<"domainDetails">>).
  130: 
  131: domain_not_found_error_formatting(Result, DomainName, GraphqlCall) ->
  132:     ParsedResult = error_result(1, Result),
  133:     ?assertEqual(#{<<"extensions">> =>
  134:                      #{<<"code">> => <<"domain_not_found">>,
  135:                        <<"domain">> => DomainName},
  136:                    <<"message">> => <<"Given domain does not exist">>,
  137:                    <<"path">> => [<<"domains">>, GraphqlCall]}, ParsedResult).
  138: 
  139: wrong_host_type_error_formatting(Config) ->
  140:     DomainName = <<"exampleDomain">>,
  141:     Vars = #{domain => DomainName, hostType => ?SECOND_HOST_TYPE},
  142:     Result = execute_auth(#{query => delete_domain_call(), variables => Vars,
  143:                    operationName => <<"M1">>}, Config),
  144:     ParsedResult = error_result(1, Result),
  145:     ?assertEqual(#{<<"extensions">> =>
  146:                      #{<<"code">> => <<"wrong_host_type">>,
  147:                        <<"hostType">> => ?SECOND_HOST_TYPE},
  148:                    <<"message">> => <<"Wrong host type">>,
  149:                    <<"path">> => [<<"domains">>, <<"removeDomain">>]}, ParsedResult).
  150: 
  151: disable_domain(Config) ->
  152:     Vars = #{domain => <<"exampleDomain">>},
  153:     Result = execute_auth(#{query => disable_domain_call(), variables => Vars,
  154:                    operationName => <<"M1">>}, Config),
  155:     ParsedResult = ok_result(<<"domains">>, <<"disableDomain">>, Result),
  156:     ?assertEqual(#{<<"domain">> => <<"exampleDomain">>, <<"enabled">> => false}, ParsedResult),
  157:     {ok, Domain} = rpc(mim(), mongoose_domain_sql, select_domain, [<<"exampleDomain">>]),
  158:     ?assertEqual(#{host_type => ?HOST_TYPE,
  159:                    enabled => false}, Domain).
  160: 
  161: 
  162: enable_domain(Config) ->
  163:     Vars = #{domain => <<"exampleDomain">>},
  164:     Result = execute_auth(#{query => enable_domain_call(), variables => Vars,
  165:                    operationName => <<"M1">>}, Config),
  166:     ParsedResult = ok_result(<<"domains">>, <<"enableDomain">>, Result),
  167:     ?assertEqual(#{<<"domain">> => <<"exampleDomain">>, <<"enabled">> => true}, ParsedResult).
  168: 
  169: get_domains_by_host_type(Config) ->
  170:     Vars = #{hostType => ?HOST_TYPE},
  171:     Result = execute_auth(#{query => get_domains_by_host_type_call(),
  172:                    variables => Vars,
  173:                    operationName => <<"Q1">>}, Config),
  174:     ParsedResult = ok_result(<<"domains">>, <<"domainsByHostType">>, Result),
  175:     ?assertEqual(lists:sort([<<"exampleDomain">>, <<"exampleDomain2">>]),
  176:                  lists:sort(ParsedResult)).
  177: 
  178: get_domain_details(Config) ->
  179:     Vars = #{domain => <<"exampleDomain">>},
  180:     Result = execute_auth(#{query => get_domain_details_call(),
  181:                    variables => Vars,
  182:                    operationName => <<"Q1">>}, Config),
  183:     ParsedResult = ok_result(<<"domains">>, <<"domainDetails">>, Result),
  184:     ?assertEqual(#{<<"domain">> => <<"exampleDomain">>,
  185:                    <<"hostType">> => ?HOST_TYPE,
  186:                    <<"enabled">> => true}, ParsedResult).
  187: 
  188: delete_domain(Config) ->
  189:     Vars = #{domain => <<"exampleDomain">>, hostType => ?HOST_TYPE},
  190:     Result1 = execute_auth(#{query => delete_domain_call(), variables => Vars,
  191:                    operationName => <<"M1">>}, Config),
  192:     ParsedResult1 = ok_result(<<"domains">>, <<"removeDomain">>, Result1),
  193:     ?assertEqual(#{<<"msg">> => <<"Domain removed!">>,
  194:                    <<"domain">> => #{<<"domain">> => <<"exampleDomain">>}},
  195:                    ParsedResult1),
  196: 
  197:     Vars2 = #{domain => <<"exampleDomain2">>, hostType => ?HOST_TYPE},
  198:     Result2 = execute_auth(#{query => delete_domain_call(), variables => Vars2,
  199:                    operationName => <<"M1">>}, Config),
  200:     ParsedResult2 = ok_result(<<"domains">>, <<"removeDomain">>, Result2),
  201:     ?assertEqual(#{<<"msg">> => <<"Domain removed!">>,
  202:                    <<"domain">> => #{<<"domain">> => <<"exampleDomain2">>}},
  203:                    ParsedResult2).
  204: 
  205: get_domains_after_deletion(Config) ->
  206:     Vars = #{hostType => ?HOST_TYPE},
  207:     Result = execute_auth(#{query => get_domains_by_host_type_call(),
  208:                    variables => Vars,
  209:                    operationName => <<"Q1">>}, Config),
  210:     ParsedResult = ok_result(<<"domains">>, <<"domainsByHostType">>, Result),
  211:     ?assertEqual([], ParsedResult).
  212: 
  213: set_domain_password(Config) ->
  214:     Result = execute_auth(#{query => set_domain_password_call(),
  215:                    variables => #{domain => domain_helper:domain(),
  216:                                   password => <<"secret">>},
  217:                    operationName => <<"M1">>}, Config),
  218:     ParsedResult = ok_result(<<"domains">>, <<"setDomainPassword">>, Result),
  219:     ?assertNotEqual(nomatch, binary:match(ParsedResult, <<"successfully">>)).
  220: 
  221: set_nonexistent_domain_password(Config) ->
  222:     Domain = <<"unknown-domain.com">>,
  223:     Result = execute_auth(#{query => set_domain_password_call(),
  224:                    variables => #{domain => Domain,
  225:                                   password => <<"secret">>},
  226:                    operationName => <<"M1">>}, Config),
  227:     domain_not_found_error_formatting(Result, Domain, <<"setDomainPassword">>).
  228: 
  229: delete_domain_password(Config) ->
  230:     Result = execute_auth(#{query => delete_domain_password_call(),
  231:                    variables => #{domain => domain_helper:domain()},
  232:                    operationName => <<"M1">>}, Config),
  233:     ParsedResult = ok_result(<<"domains">>, <<"deleteDomainPassword">>, Result),
  234:     ?assertNotEqual(nomatch, binary:match(ParsedResult, <<"successfully">>)).
  235: 
  236: create_domain_call() ->
  237:     <<"mutation M1($domain: String!, $hostType: String!)
  238:            {domains
  239:                {addDomain(domain: $domain, hostType: $hostType)
  240:                    {
  241:                        domain
  242:                        hostType
  243:                        enabled
  244:                    }
  245:                }
  246:            }">>.
  247: 
  248: enable_domain_call() ->
  249:     <<"mutation M1($domain: String!)
  250:            {domains
  251:                {enableDomain(domain: $domain)
  252:                    {
  253:                        enabled
  254:                        domain
  255:                    }
  256:                }
  257:            }">>.
  258: 
  259: disable_domain_call() ->
  260:     <<"mutation M1($domain: String!)
  261:            {domains
  262:                {disableDomain(domain: $domain)
  263:                    {
  264:                        enabled
  265:                        domain
  266:                    }
  267:                }
  268:            }">>.
  269: 
  270: get_domains_by_host_type_call() ->
  271:     <<"query Q1($hostType: String!)
  272:            {domains
  273:                {domainsByHostType(hostType: $hostType)}
  274:            }">>.
  275: 
  276: get_domain_details_call() ->
  277:     <<"query Q1($domain: String!)
  278:            {domains
  279:                {domainDetails(domain: $domain)
  280:                    {
  281:                        domain
  282:                        hostType
  283:                        enabled
  284:                    }
  285:                }
  286:            }">>.
  287: 
  288: delete_domain_call() ->
  289:     <<"mutation M1($domain: String!, $hostType: String!)
  290:            {domains
  291:                {removeDomain(domain: $domain, hostType: $hostType)
  292:                    {
  293:                        msg
  294:                        domain
  295:                            {domain}
  296:                    }
  297:                }
  298:            }">>.
  299: 
  300: set_domain_password_call() ->
  301:     <<"mutation M1($domain: String!, $password: String!)"
  302:       "{ domains { setDomainPassword(domain: $domain, password: $password)} }">>.
  303: 
  304: delete_domain_password_call() ->
  305:     <<"mutation M1($domain: String!)"
  306:       "{ domains { deleteDomainPassword(domain: $domain)} }">>.
  307: 
  308: %% Helpers
  309: ok_result(What1, What2, {{<<"200">>, <<"OK">>}, #{<<"data">> := Data}}) ->
  310:     maps:get(What2, maps:get(What1, Data)).
  311: 
  312: error_result(ErrorNumber, {{<<"200">>, <<"OK">>}, #{<<"errors">> := Errors}}) ->
  313:     lists:nth(ErrorNumber, Errors).