1: -module(service_domain_db_SUITE). 2: 3: -include_lib("common_test/include/ct.hrl"). 4: -include_lib("eunit/include/eunit.hrl"). 5: 6: -compile([export_all, nowarn_export_all]). 7: -import(distributed_helper, [mim/0, mim2/0, mim3/0, require_rpc_nodes/1, rpc/4, 8: remove_node_from_cluster/2]). 9: -import(graphql_helper, [execute_command/4]). 10: 11: -import(domain_rest_helper, 12: [set_invalid_creds/1, 13: set_no_creds/1, 14: set_valid_creds/1]). 15: 16: -import(domain_rest_helper, 17: [rest_patch_enabled/3, 18: rest_put_domain/3, 19: putt_domain_with_custom_body/2, 20: rest_select_domain/2, 21: rest_delete_domain/3, 22: delete_custom/4, 23: patch_custom/4]). 24: 25: -import(domain_helper, [domain/0]). 26: -import(config_parser_helper, [config/2]). 27: 28: suite() -> 29: require_rpc_nodes([mim, mim2, mim3]). 30: 31: all() -> 32: [ 33: api_lookup_works, 34: api_lookup_not_found, 35: api_cannot_insert_static, 36: api_cannot_disable_static, 37: api_cannot_enable_static, 38: api_get_all_static, 39: api_get_domains_by_host_type, 40: {group, db} 41: ]. 42: 43: groups() -> 44: [{db, [], db_cases()}, 45: {rest_with_auth, [], [{group, rest_with_auth_parallel}|rest_cases()]}, 46: {rest_without_auth, [], [{group, rest_without_auth_parallel}|rest_cases()]}, 47: {rest_with_auth_parallel, [parallel], rest_auth_cases(true)}, 48: {rest_without_auth_parallel, [parallel], rest_auth_cases(false)}]. 49: 50: db_cases() -> [ 51: db_inserted_domain_is_in_db, 52: db_inserted_domain_is_in_core, 53: db_deleted_domain_from_db, 54: db_deleted_domain_fails_with_wrong_host_type, 55: db_deleted_domain_from_core, 56: rest_cannot_enable_deleting, 57: db_disabled_domain_is_in_db, 58: db_disabled_domain_not_in_core, 59: db_reenabled_domain_is_in_db, 60: db_reenabled_domain_is_in_core, 61: db_cannot_insert_domain_twice_with_the_same_host_type, 62: db_cannot_insert_domain_twice_with_another_host_type, 63: db_cannot_insert_domain_with_unknown_host_type, 64: db_cannot_delete_domain_with_unknown_host_type, 65: db_cannot_enable_domain_with_unknown_host_type, 66: db_cannot_disable_domain_with_unknown_host_type, 67: db_domains_with_unknown_host_type_are_ignored_by_core, 68: db_can_insert_update_delete_dynamic_domain_password, 69: db_can_insert_update_delete_static_domain_password, 70: db_cannot_set_password_for_unknown_domain, 71: db_can_check_domain_password, 72: db_cannot_check_password_for_unknown_domain, 73: db_deleting_domain_deletes_domain_admin, 74: sql_select_from, 75: sql_find_gaps_between, 76: db_records_are_restored_on_mim_restart, 77: db_record_is_ignored_if_domain_static, 78: db_events_table_gets_truncated, 79: db_get_all_static, 80: db_get_all_dynamic, 81: db_could_sync_between_nodes, 82: db_deleted_from_one_node_while_service_disabled_on_another, 83: db_inserted_from_one_node_while_service_disabled_on_another, 84: db_reinserted_from_one_node_while_service_disabled_on_another, 85: db_out_of_sync_restarts_service, 86: db_crash_on_initial_load_restarts_service, 87: db_restarts_properly, 88: db_keeps_syncing_after_cluster_join, 89: db_gaps_are_getting_filled_automatically, 90: db_event_could_appear_with_lower_id, 91: {group, rest_with_auth}, 92: {group, rest_without_auth}]. 93: 94: rest_auth_cases(false) -> 95: %% auth provided but not configured: 96: [rest_cannot_insert_domain_if_auth_provided_but_not_configured, 97: rest_cannot_delete_domain_if_auth_provided_but_not_configured, 98: rest_cannot_enable_domain_if_auth_provided_but_not_configured, 99: rest_cannot_disable_domain_if_auth_provided_but_not_configured, 100: rest_cannot_select_domain_if_auth_provided_but_not_configured]; 101: rest_auth_cases(true) -> 102: %% basic auth, but wrong pass: 103: [rest_cannot_insert_domain_with_wrong_pass, 104: rest_cannot_delete_domain_with_wrong_pass, 105: rest_cannot_enable_domain_with_wrong_pass, 106: rest_cannot_disable_domain_with_wrong_pass, 107: rest_cannot_select_domain_with_wrong_pass, 108: %% no basic auth: 109: rest_cannot_insert_domain_without_auth, 110: rest_cannot_delete_domain_without_auth, 111: rest_cannot_enable_domain_without_auth, 112: rest_cannot_disable_domain_without_auth, 113: rest_cannot_select_domain_without_auth]. 114: rest_cases() -> 115: [rest_can_insert_domain, 116: rest_can_disable_domain, 117: rest_can_delete_domain, 118: rest_request_can_delete_domain, 119: rest_cannot_delete_domain_without_correct_type, 120: rest_cannot_delete_missing_domain, 121: rest_cannot_insert_domain_twice_with_another_host_type, 122: rest_cannot_insert_domain_with_unknown_host_type, 123: rest_cannot_delete_domain_with_unknown_host_type, 124: rest_cannot_enable_missing_domain, 125: rest_cannot_disable_missing_domain, 126: rest_can_enable_domain, 127: rest_can_select_domain, 128: rest_cannot_select_domain_if_domain_not_found, 129: rest_cannot_select_domain_when_it_is_static, 130: rest_cannot_put_domain_without_host_type, 131: rest_cannot_put_domain_without_body, 132: rest_cannot_put_domain_with_invalid_json, 133: rest_cannot_put_domain_with_invalid_name, 134: rest_cannot_put_domain_when_it_is_static, 135: rest_cannot_delete_domain_without_host_type, 136: rest_cannot_delete_domain_without_body, 137: rest_cannot_delete_domain_with_invalid_json, 138: rest_cannot_delete_domain_when_it_is_static, 139: rest_cannot_patch_domain_without_enabled_field, 140: rest_cannot_patch_domain_without_body, 141: rest_cannot_patch_domain_with_invalid_json, 142: rest_cannot_enable_domain_when_it_is_static, 143: rest_insert_domain_fails_if_db_fails, 144: rest_insert_domain_fails_if_service_disabled, 145: rest_delete_domain_fails_if_db_fails, 146: rest_delete_domain_fails_if_service_disabled, 147: rest_enable_domain_fails_if_db_fails, 148: rest_enable_domain_fails_if_service_disabled, 149: rest_delete_domain_cleans_data_from_mam]. 150: 151: %%-------------------------------------------------------------------- 152: %% Suite configuration 153: %%-------------------------------------------------------------------- 154: init_per_suite(Config) -> 155: Config0 = dynamic_services:save_services(all_nodes(), Config), 156: Config1 = dynamic_modules:save_modules(dummy_auth_host_type(), Config0), 157: ensure_nodes_know_each_other(), 158: service_disabled(mim()), 159: service_disabled(mim2()), 160: service_disabled(mim3()), 161: prepare_test_queries(mim()), 162: prepare_test_queries(mim2()), 163: erase_database(mim()), 164: Config2 = ejabberd_node_utils:init(mim(), Config1), 165: mongoose_helper:inject_module(?MODULE), 166: escalus:init_per_suite([{service_setup, per_testcase} | Config2]). 167: 168: end_per_suite(Config) -> 169: [restart_domain_core(Node) || Node <- all_nodes()], 170: dynamic_services:restore_services(Config), 171: domain_helper:insert_configured_domains(), 172: dynamic_modules:restore_modules(Config), 173: escalus_fresh:clean(), 174: escalus:end_per_suite(Config). 175: 176: all_nodes() -> 177: [mim(), mim2(), mim3()]. 178: 179: %%-------------------------------------------------------------------- 180: %% Init & teardown 181: %%-------------------------------------------------------------------- 182: init_per_group(db, Config) -> 183: case mongoose_helper:is_rdbms_enabled(dummy_auth_host_type()) of 184: true -> [{service, true}|Config]; 185: false -> {skip, require_rdbms} 186: end; 187: init_per_group(rest_with_auth, Config) -> 188: rest_helper:change_admin_creds({<<"admin">>, <<"secret">>}), 189: [{auth_creds, valid}|Config]; 190: init_per_group(GroupName, Config) -> 191: Config1 = save_service_setup_option(GroupName, Config), 192: case ?config(service_setup, Config) of 193: per_group -> setup_service(#{}, Config1); 194: per_testcase -> ok 195: end, 196: Config1. 197: 198: end_per_group(rest_with_auth, _Config) -> 199: rest_helper:change_admin_creds(any); 200: end_per_group(_GroupName, Config) -> 201: case ?config(service_setup, Config) of 202: per_group -> teardown_service(); 203: per_testcase -> ok 204: end. 205: 206: init_per_testcase(rest_cannot_enable_deleting, Config) -> 207: HostType = <<"type1">>, 208: Server = start_domain_removal_hook(HostType), 209: init_per_testcase(generic, [{server, Server}, {host_type, HostType} | Config]); 210: init_per_testcase(db_crash_on_initial_load_restarts_service, Config) -> 211: maybe_setup_meck(db_crash_on_initial_load_restarts_service), 212: restart_domain_core(mim(), [], []), 213: Config; 214: init_per_testcase(TestcaseName, Config) -> 215: maybe_setup_meck(TestcaseName), 216: case ?config(service_setup, Config) of 217: per_group -> ok; 218: per_testcase -> setup_service(service_opts(TestcaseName), Config) 219: end, 220: init_per_testcase2(TestcaseName, Config). 221: 222: service_opts(db_events_table_gets_truncated) -> 223: #{event_cleaning_interval => 1, event_max_age => 3}; 224: service_opts(_) -> 225: #{}. 226: 227: end_per_testcase(rest_cannot_enable_deleting, Config) -> 228: Server = ?config(server, Config), 229: HostType = ?config(host_type, Config), 230: stop_domain_removal_hook(HostType, Server), 231: exit(Server, normal); 232: end_per_testcase(TestcaseName, Config) -> 233: end_per_testcase2(TestcaseName, Config), 234: case TestcaseName of 235: db_out_of_sync_restarts_service -> 236: rpc(mim(), sys, resume, [service_domain_db]); 237: _ -> ok 238: end, 239: maybe_teardown_meck(TestcaseName), 240: case ?config(service_setup, Config) of 241: per_group -> ok; 242: per_testcase -> teardown_service() 243: end. 244: 245: init_per_testcase2(TestcaseName, Config) 246: when TestcaseName =:= rest_delete_domain_cleans_data_from_mam -> 247: HostType = dummy_auth_host_type(), 248: Mods = [{mod_mam, mam_helper:config_opts(#{pm => #{}})}], 249: dynamic_modules:ensure_modules(HostType, Mods), 250: escalus:init_per_testcase(TestcaseName, Config); 251: init_per_testcase2(db_keeps_syncing_after_cluster_join, Config) -> 252: graphql_helper:init_admin_cli(Config); 253: init_per_testcase2(_, Config) -> 254: Config. 255: 256: end_per_testcase2(TestcaseName, Config) 257: when TestcaseName =:= rest_delete_domain_cleans_data_from_mam -> 258: escalus:end_per_testcase(TestcaseName, Config); 259: end_per_testcase2(db_keeps_syncing_after_cluster_join, _Config) -> 260: graphql_helper:clean(); 261: end_per_testcase2(_, Config) -> 262: Config. 263: 264: setup_service(Opts, Config) -> 265: ServiceEnabled = proplists:get_value(service, Config, false), 266: Pairs1 = [{<<"example.cfg">>, <<"type1">>}, 267: {<<"erlang-solutions.com">>, <<"type2">>}, 268: {<<"erlang-solutions.local">>, <<"type2">>}], 269: restart_domain_core(mim(), Pairs1, host_types_for_mim()), 270: restart_domain_core(mim2(), [], host_types_for_mim2()), 271: case ServiceEnabled of 272: true -> 273: service_enabled(mim(), Opts), 274: service_enabled(mim2(), #{}); 275: false -> 276: ok 277: end. 278: 279: host_types_for_mim() -> 280: [<<"type1">>, <<"type2">>, dummy_auth_host_type(), 281: <<"dbgroup">>, <<"dbgroup2">>, <<"cfggroup">>]. 282: 283: host_types_for_mim2() -> 284: [<<"mim2only">> | host_types_for_mim()]. 285: 286: teardown_service() -> 287: service_disabled(mim()), 288: service_disabled(mim2()), 289: erase_database(mim()). 290: 291: save_service_setup_option(GroupName, Config) -> 292: Value = case is_parallel_group(GroupName) of 293: true -> per_group; 294: false -> per_testcase 295: end, 296: lists:keystore(service_setup, 1, Config, {service_setup, Value}). 297: 298: is_parallel_group(GroupName) -> 299: case lists:keyfind(GroupName, 1, groups()) of 300: {_, Opts, _Cases} -> lists:member(parallel, Opts); 301: _ -> false 302: end. 303: 304: %%-------------------------------------------------------------------- 305: %% Tests 306: %%-------------------------------------------------------------------- 307: 308: api_lookup_works(_) -> 309: {ok, <<"type1">>} = get_host_type(mim(), <<"example.cfg">>). 310: 311: api_lookup_not_found(_) -> 312: {error, not_found} = get_host_type(mim(), <<"example.missing">>). 313: 314: api_cannot_insert_static(_) -> 315: {static, <<"Domain is static">>} = insert_domain(mim(), <<"example.cfg">>, <<"type1">>). 316: 317: api_cannot_disable_static(_) -> 318: {static, <<"Domain is static">>} = disable_domain(mim(), <<"example.cfg">>). 319: 320: api_cannot_enable_static(_) -> 321: {static, <<"Domain is static">>} = enable_domain(mim(), <<"example.cfg">>). 322: 323: %% See also db_get_all_static 324: api_get_all_static(_) -> 325: %% Could be in any order 326: [{<<"erlang-solutions.com">>, <<"type2">>}, 327: {<<"erlang-solutions.local">>, <<"type2">>}, 328: {<<"example.cfg">>, <<"type1">>}] = 329: lists:sort(get_all_static(mim())). 330: 331: api_get_domains_by_host_type(_) -> 332: [<<"erlang-solutions.com">>, <<"erlang-solutions.local">>] = 333: lists:sort(get_domains_by_host_type(mim(), <<"type2">>)), 334: [<<"example.cfg">>] = get_domains_by_host_type(mim(), <<"type1">>), 335: [] = get_domains_by_host_type(mim(), <<"type6">>). 336: 337: %% Similar to as api_get_all_static, just with DB service enabled 338: db_get_all_static(_) -> 339: {ok, _} = insert_domain(mim(), <<"example.db">>, <<"type1">>), 340: sync(), 341: %% Could be in any order 342: [{<<"erlang-solutions.com">>, <<"type2">>}, 343: {<<"erlang-solutions.local">>, <<"type2">>}, 344: {<<"example.cfg">>, <<"type1">>}] = 345: lists:sort(get_all_static(mim())). 346: 347: db_get_all_dynamic(_) -> 348: {ok, _} = insert_domain(mim(), <<"example.db">>, <<"type1">>), 349: {ok, _} = insert_domain(mim(), <<"example2.db">>, <<"type1">>), 350: sync(), 351: [{<<"example.db">>, <<"type1">>}, 352: {<<"example2.db">>, <<"type1">>}] = 353: lists:sort(get_all_dynamic(mim())). 354: 355: db_inserted_domain_is_in_db(_) -> 356: {ok, _} = insert_domain(mim(), <<"example.db">>, <<"type1">>), 357: {ok, #{host_type := <<"type1">>, status := enabled}} = 358: select_domain(mim(), <<"example.db">>). 359: 360: db_inserted_domain_is_in_core(_) -> 361: {ok, _} = insert_domain(mim(), <<"example.db">>, <<"type1">>), 362: sync(), 363: {ok, <<"type1">>} = get_host_type(mim(), <<"example.db">>). 364: 365: rest_cannot_enable_deleting(Config) -> 366: HostType = ?config(host_type, Config), 367: Domain = <<"example.db">>, 368: {ok, _} = insert_domain(mim(), Domain, HostType), 369: {ok, #{status := enabled}} = select_domain(mim(), Domain), 370: {ok, _} = request_delete_domain(mim(), Domain, HostType), 371: {ok, #{status := deleting}} = select_domain(mim(), Domain), 372: {deleted, _} = enable_domain(mim(), Domain), 373: Server = ?config(server, Config), 374: Server ! continue, 375: F = fun () -> select_domain(mim(), <<"example.db">>) end, 376: mongoose_helper:wait_until(F, {error, not_found}, #{time_left => timer:seconds(15)}). 377: 378: db_deleted_domain_from_db(_) -> 379: {ok, _} = insert_domain(mim(), <<"example.db">>, <<"type1">>), 380: {ok, _} = delete_domain(mim(), <<"example.db">>, <<"type1">>), 381: {error, not_found} = select_domain(mim(), <<"example.db">>). 382: 383: db_deleted_domain_fails_with_wrong_host_type(_) -> 384: {ok, _} = insert_domain(mim(), <<"example.db">>, <<"type1">>), 385: {wrong_host_type, _} = 386: delete_domain(mim(), <<"example.db">>, <<"type2">>), 387: {ok, #{host_type := <<"type1">>, status := enabled}} = 388: select_domain(mim(), <<"example.db">>). 389: 390: db_deleted_domain_from_core(_) -> 391: {ok, _} = insert_domain(mim(), <<"example.db">>, <<"type1">>), 392: sync(), 393: {ok, _} = delete_domain(mim(), <<"example.db">>, <<"type1">>), 394: sync(), 395: {error, not_found} = get_host_type(mim(), <<"example.db">>). 396: 397: db_disabled_domain_is_in_db(_) -> 398: {ok, _} = insert_domain(mim(), <<"example.db">>, <<"type1">>), 399: {ok, _} = disable_domain(mim(), <<"example.db">>), 400: {ok, #{host_type := <<"type1">>, status := disabled}} = 401: select_domain(mim(), <<"example.db">>). 402: 403: db_disabled_domain_not_in_core(_) -> 404: {ok, _} = insert_domain(mim(), <<"example.db">>, <<"type1">>), 405: {ok, _} = disable_domain(mim(), <<"example.db">>), 406: sync(), 407: {error, not_found} = get_host_type(mim(), <<"example.db">>). 408: 409: db_reenabled_domain_is_in_db(_) -> 410: {ok, _} = insert_domain(mim(), <<"example.db">>, <<"type1">>), 411: {ok, _} = disable_domain(mim(), <<"example.db">>), 412: {ok, _} = enable_domain(mim(), <<"example.db">>), 413: {ok, #{host_type := <<"type1">>, status := enabled}} = 414: select_domain(mim(), <<"example.db">>). 415: 416: db_reenabled_domain_is_in_core(_) -> 417: {ok, _} = insert_domain(mim(), <<"example.db">>, <<"type1">>), 418: {ok, _} = disable_domain(mim(), <<"example.db">>), 419: {ok, _} = enable_domain(mim(), <<"example.db">>), 420: sync(), 421: {ok, <<"type1">>} = get_host_type(mim(), <<"example.db">>). 422: 423: db_cannot_insert_domain_twice_with_the_same_host_type(_) -> 424: {ok, _} = insert_domain(mim(), <<"example.db">>, <<"type1">>), 425: {duplicate, _} = insert_domain(mim(), <<"example.db">>, <<"type1">>). 426: 427: db_cannot_insert_domain_twice_with_another_host_type(_) -> 428: {ok, _} = insert_domain(mim(), <<"example.db">>, <<"type1">>), 429: {duplicate, _} = insert_domain(mim(), <<"example.db">>, <<"type2">>). 430: 431: db_cannot_insert_domain_with_unknown_host_type(_) -> 432: {unknown_host_type, _} = insert_domain(mim(), <<"example.db">>, <<"type6">>). 433: 434: db_cannot_delete_domain_with_unknown_host_type(_) -> 435: {ok, _} = insert_domain(mim2(), <<"example.db">>, <<"mim2only">>), 436: sync(), 437: {unknown_host_type, _} = delete_domain(mim(), <<"example.db">>, <<"mim2only">>). 438: 439: db_cannot_enable_domain_with_unknown_host_type(_) -> 440: {ok, _} = insert_domain(mim2(), <<"example.db">>, <<"mim2only">>), 441: {ok, _} = disable_domain(mim2(), <<"example.db">>), 442: sync(), 443: {unknown_host_type, _} = enable_domain(mim(), <<"example.db">>). 444: 445: db_cannot_disable_domain_with_unknown_host_type(_) -> 446: {ok, _} = insert_domain(mim2(), <<"example.db">>, <<"mim2only">>), 447: sync(), 448: {unknown_host_type, _} = disable_domain(mim(), <<"example.db">>). 449: 450: db_domains_with_unknown_host_type_are_ignored_by_core(_) -> 451: {ok, _} = insert_domain(mim2(), <<"example.com">>, <<"mim2only">>), 452: {ok, _} = insert_domain(mim2(), <<"example.org">>, <<"type1">>), 453: sync(), 454: {ok, <<"type1">>} = get_host_type(mim(), <<"example.org">>), %% Counter-case 455: {error, not_found} = get_host_type(mim(), <<"example.com">>). 456: 457: db_can_insert_update_delete_dynamic_domain_password(_) -> 458: Domain = <<"password-example.com">>, 459: {ok, _} = insert_domain(mim(), Domain, <<"type1">>), 460: sync(), 461: {ok, _} = set_domain_password(mim(), Domain, <<"rocky1">>), 462: ok = check_domain_password(mim(), Domain, <<"rocky1">>), 463: {ok, _} = set_domain_password(mim(), Domain, <<"rocky2">>), 464: ok = check_domain_password(mim(), Domain, <<"rocky2">>), 465: {ok, _} = delete_domain_password(mim(), Domain), 466: {error, not_found} = select_domain_admin(mim(), Domain). 467: 468: db_can_insert_update_delete_static_domain_password(_) -> 469: StaticDomain = <<"example.cfg">>, 470: {ok, _} = set_domain_password(mim(), StaticDomain, <<"rocky1">>), 471: ok = check_domain_password(mim(), StaticDomain, <<"rocky1">>), 472: {ok, _} = set_domain_password(mim(), StaticDomain, <<"rocky2">>), 473: ok = check_domain_password(mim(), StaticDomain, <<"rocky2">>), 474: {ok, _} = delete_domain_password(mim(), StaticDomain), 475: {error, not_found} = select_domain_admin(mim(), StaticDomain). 476: 477: db_cannot_set_password_for_unknown_domain(_) -> 478: {not_found, _} = set_domain_password(mim(), <<"unknown_domain">>, <<>>). 479: 480: db_can_check_domain_password(_) -> 481: StaticDomain = <<"example.cfg">>, 482: {ok, _} = set_domain_password(mim(), StaticDomain, <<"myrock">>), 483: ok = check_domain_password(mim(), StaticDomain, <<"myrock">>), 484: {error, wrong_password} = check_domain_password(mim(), StaticDomain, <<"wrongrock">>). 485: 486: db_cannot_check_password_for_unknown_domain(_) -> 487: {error, not_found} = check_domain_password(mim(), <<"unknown_domain">>, <<>>). 488: 489: db_deleting_domain_deletes_domain_admin(_) -> 490: Domain = <<"password-del-example.db">>, 491: {ok, _} = insert_domain(mim(), Domain, <<"type1">>), 492: sync(), 493: {ok, _} = set_domain_password(mim(), Domain, <<"deleteme">>), 494: {ok, _} = delete_domain(mim(), Domain, <<"type1">>), 495: {error, not_found} = select_domain_admin(mim(), Domain). 496: 497: sql_select_from(_) -> 498: {ok, _} = insert_domain(mim(), <<"example.db">>, <<"type1">>), 499: [{_, <<"example.db">>, <<"type1">>}] = 500: rpc(mim(), mongoose_domain_sql, select_from, [0, 100]). 501: 502: sql_find_gaps_between(_) -> 503: with_service_suspended(fun() -> 504: %% Check several ranges 505: check_gap_finder(20, 22), 506: check_gap_finder(10, 15), 507: check_gap_finder(123, 321), 508: check_gap_finder(1000, 1300) 509: end). 510: 511: check_gap_finder(From, To) -> 512: {updated, 1} = insert_full_event(mim(), From, <<"gap_start">>), 513: {updated, 1} = insert_full_event(mim(), To, <<"gap_end">>), 514: Expected = lists:seq(From + 1, To - 1), 515: Expected = find_gaps_between(From, To). 516: 517: find_gaps_between(From, To) -> 518: rpc(mim(), mongoose_domain_loader, find_gaps_between, [From, To]). 519: 520: db_records_are_restored_on_mim_restart(_) -> 521: {ok, _} = insert_domain(mim(), <<"example.com">>, <<"type1">>), 522: %% Simulate MIM restart 523: service_disabled(mim()), 524: restart_domain_core(mim(), [], [<<"type1">>]), 525: {error, not_found} = get_host_type(mim(), <<"example.com">>), 526: service_enabled(mim()), 527: %% DB still contains data 528: {ok, #{host_type := <<"type1">>, status := enabled}} = 529: select_domain(mim(), <<"example.com">>), 530: %% Restored 531: {ok, <<"type1">>} = get_host_type(mim(), <<"example.com">>). 532: 533: db_record_is_ignored_if_domain_static(_) -> 534: {ok, _} = insert_domain(mim(), <<"example.com">>, <<"dbgroup">>), 535: {ok, _} = insert_domain(mim(), <<"example.net">>, <<"dbgroup">>), 536: %% Simulate MIM restart 537: service_disabled(mim()), 538: %% Only one domain is static 539: restart_domain_core(mim(), [{<<"example.com">>, <<"cfggroup">>}], [<<"dbgroup">>, <<"cfggroup">>]), 540: service_enabled(mim()), 541: %% DB still contains data 542: {ok, #{host_type := <<"dbgroup">>, status := enabled}} = 543: select_domain(mim(), <<"example.com">>), 544: {ok, #{host_type := <<"dbgroup">>, status := enabled}} = 545: select_domain(mim(), <<"example.net">>), 546: %% Static DB records are ignored 547: {ok, <<"cfggroup">>} = get_host_type(mim(), <<"example.com">>), 548: {ok, <<"dbgroup">>} = get_host_type(mim(), <<"example.net">>). 549: 550: db_events_table_gets_truncated(_) -> 551: %% Configure service with a very short interval 552: {ok, _} = insert_domain(mim(), <<"example.com">>, <<"dbgroup">>), 553: {ok, _} = insert_domain(mim(), <<"example.net">>, <<"dbgroup">>), 554: {ok, _} = insert_domain(mim(), <<"example.org">>, <<"dbgroup">>), 555: {ok, _} = insert_domain(mim(), <<"example.beta">>, <<"dbgroup">>), 556: Max = get_max_event_id(mim()), 557: true = is_integer(Max), 558: true = Max > 0, 559: %% The events table is not empty and the size of 1, eventually. 560: F = fun() -> get_min_event_id(mim()) end, 561: mongoose_helper:wait_until(F, Max, #{time_left => timer:seconds(15)}). 562: 563: db_could_sync_between_nodes(_) -> 564: {ok, _} = insert_domain(mim(), <<"example.com">>, <<"dbgroup">>), 565: sync(), 566: {ok, <<"dbgroup">>} = get_host_type(mim2(), <<"example.com">>). 567: 568: db_deleted_from_one_node_while_service_disabled_on_another(_) -> 569: {ok, _} = insert_domain(mim(), <<"example.com">>, <<"dbgroup">>), 570: sync(), 571: {ok, <<"dbgroup">>} = get_host_type(mim2(), <<"example.com">>), 572: %% Service is disable on the second node 573: service_disabled(mim2()), 574: %% Removed from the first node 575: {ok, _} = delete_domain(mim(), <<"example.com">>, <<"dbgroup">>), 576: sync_local(mim()), 577: {error, not_found} = get_host_type(mim(), <<"example.com">>), 578: {ok, <<"dbgroup">>} = get_host_type(mim2(), <<"example.com">>), 579: %% Sync is working again 580: service_enabled(mim2()), 581: {error, not_found} = get_host_type(mim2(), <<"example.com">>). 582: 583: db_inserted_from_one_node_while_service_disabled_on_another(_) -> 584: %% Service is disable on the second node 585: service_disabled(mim2()), 586: {ok, _} = insert_domain(mim(), <<"example.com">>, <<"dbgroup">>), 587: %% Sync is working again 588: service_enabled(mim2()), 589: {ok, <<"dbgroup">>} = get_host_type(mim2(), <<"example.com">>). 590: 591: db_reinserted_from_one_node_while_service_disabled_on_another(_) -> 592: %% This test shows the behaviour when someone 593: %% reinserts a domain with a different host type. 594: {ok, _} = insert_domain(mim(), <<"example.com">>, <<"dbgroup">>), 595: sync(), 596: {ok, <<"dbgroup">>} = get_host_type(mim2(), <<"example.com">>), 597: %% Service is disable on the second node 598: service_disabled(mim2()), 599: %% Removed from the first node 600: {ok, _} = delete_domain(mim(), <<"example.com">>, <<"dbgroup">>), 601: sync_local(mim()), 602: {ok, _} = insert_domain(mim(), <<"example.com">>, <<"dbgroup2">>), 603: sync_local(mim()), 604: %% Sync is working again 605: service_enabled(mim2()), 606: sync(), 607: %% A corner case: domain name is reinserted with different host type 608: %% while service was down on mim2. check that mim2 is updated 609: {ok, <<"dbgroup2">>} = get_host_type(mim(), <<"example.com">>), 610: {ok, <<"dbgroup2">>} = get_host_type(mim2(), <<"example.com">>), 611: %% check deleting 612: {ok, _} = delete_domain(mim2(), <<"example.com">>, <<"dbgroup2">>), 613: sync(), 614: {error, not_found} = get_host_type(mim(), <<"example.com">>), 615: {error, not_found} = get_host_type(mim2(), <<"example.com">>). 616: 617: db_crash_on_initial_load_restarts_service(_) -> 618: service_enabled(mim()), 619: %% service is restarted 620: true = rpc(mim(), meck, wait, [service_domain_db, restart, 0, timer:seconds(1)]) > 0, 621: ok. 622: 623: db_out_of_sync_restarts_service(_) -> 624: {ok, _} = insert_domain(mim2(), <<"example1.com">>, <<"type1">>), 625: {ok, _} = insert_domain(mim2(), <<"example2.com">>, <<"type1">>), 626: sync(), 627: %% Pause processing events on one node 628: suspend_service(mim()), 629: {ok, _} = insert_domain(mim2(), <<"example3.com">>, <<"type1">>), 630: {ok, _} = insert_domain(mim2(), <<"example4.com">>, <<"type1">>), 631: sync_local(mim2()), 632: %% Truncate events table, keep only one event 633: MaxId = get_max_event_id(mim2()), 634: {updated, _} = delete_events_older_than(mim2(), MaxId), 635: {error, not_found} = get_host_type(mim(), <<"example3.com">>), 636: %% The size of the table is 1 637: MaxId = get_min_event_id(mim2()), 638: %% Resume processing events on one node 639: resume_service(mim()), 640: sync(), 641: %% Out of sync detected and service is restarted 642: true = rpc(mim(), meck, num_calls, [service_domain_db, restart, 0]) > 0, 643: ok. 644: 645: db_restarts_properly(_) -> 646: PID = rpc(mim(), erlang, whereis, [service_domain_db]), 647: ok = rpc(mim(), service_domain_db, restart, []), 648: F = fun() -> 649: PID2 = rpc(mim(), erlang, whereis, [service_domain_db]), 650: PID2 =/= PID 651: end, 652: mongoose_helper:wait_until(F, true, #{time_left => timer:seconds(15)}). 653: 654: db_keeps_syncing_after_cluster_join(Config) -> 655: HostType = dummy_auth_host_type(), 656: %% GIVING mim1 and mim2 are not clustered. 657: %% Ask mim1 to join mim2's cluster 658: %% (and mongooseim application gets restarted on mim1) 659: leave_cluster(Config), 660: service_enabled(mim()), 661: {ok, _} = insert_domain(mim(), <<"example1.com">>, HostType), 662: {ok, _} = insert_domain(mim2(), <<"example2.com">>, HostType), 663: sync(), 664: %% Nodes don't have to be clustered to sync the domains. 665: assert_domains_are_equal(HostType), 666: %% WHEN Adding mim1 joins into a cluster 667: %% (and mongooseim application gets restarted on mim1) 668: join_cluster(Config), 669: service_enabled(mim()), 670: %% THEN Sync is successful 671: {ok, _} = insert_domain(mim(), <<"example3.com">>, HostType), 672: {ok, _} = insert_domain(mim2(), <<"example4.com">>, HostType), 673: sync(), 674: assert_domains_are_equal(HostType). 675: 676: db_gaps_are_getting_filled_automatically(_Config) -> 677: {ok, _} = insert_domain(mim(), <<"example.com">>, <<"type1">>), 678: sync(), 679: Max = get_max_event_id(mim()), 680: %% Create a gap in events by manually adding an event 681: GapSize = 10, 682: {updated, 1} = insert_full_event(mim(), Max + GapSize, <<"something.else">>), 683: force_check_for_updates(mim()), 684: sync_local(mim()), 685: F = fun() -> get_event_ids_between(mim(), Max, Max + GapSize) end, 686: mongoose_helper:wait_until(F, lists:seq(Max, Max + GapSize), 687: #{time_left => timer:seconds(15)}). 688: 689: db_event_could_appear_with_lower_id(_Config) -> 690: %% We use 40 and 50 as event ids 691: %% We check two things: 692: %% - that "lazydom" actually gets loaded 693: %% - that gaps get filled 694: %% Starting with an empty DB 695: null = get_max_event_id(mim()), 696: {updated, 1} = insert_domain_settings_without_event(mim(), <<"fastdom">>, <<"type1">>), 697: {updated, 1} = insert_full_event(mim(), 50, <<"fastdom">>), 698: force_check_for_updates(mim()), 699: sync_local(mim()), 700: {ok, <<"type1">>} = get_host_type(mim(), <<"fastdom">>), 701: %% At this point we've completed the initial load and the DB sync 702: %% Now create an event before the first known event 703: {updated, 1} = insert_domain_settings_without_event(mim(), <<"lazydom">>, <<"type1">>), 704: {updated, 1} = insert_full_event(mim(), 40, <<"lazydom">>), 705: force_check_for_updates(mim()), 706: sync_local(mim()), 707: 40 = get_min_event_id(mim()), 708: 50 = get_max_event_id(mim()), 709: %% lazydom gets loaded 710: {ok, <<"type1">>} = get_host_type(mim(), <<"lazydom">>), 711: %% Check gaps 712: F = fun() -> get_event_ids_between(mim(), 40, 50) end, 713: mongoose_helper:wait_until(F, lists:seq(40, 50), 714: #{time_left => timer:seconds(15)}). 715: 716: rest_can_insert_domain(Config) -> 717: {{<<"204">>, _}, _} = 718: rest_put_domain(Config, <<"example.db">>, <<"type1">>), 719: {ok, #{host_type := <<"type1">>, status := enabled}} = 720: select_domain(mim(), <<"example.db">>). 721: 722: rest_can_disable_domain(Config) -> 723: rest_put_domain(Config, <<"example.db">>, <<"type1">>), 724: rest_patch_enabled(Config, <<"example.db">>, false), 725: {ok, #{host_type := <<"type1">>, status := disabled}} = 726: select_domain(mim(), <<"example.db">>). 727: 728: rest_request_can_delete_domain(Config) -> 729: %% Put a new domain to delete later 730: rest_put_domain(Config, <<"example.db">>, <<"type1">>), 731: %% Request delete domain 732: {{<<"202">>, _}, _} = domain_rest_helper:request_delete_domain(Config, <<"example.db">>, <<"type1">>), 733: %% Wait until it is not found anymore 734: Return = {{<<"404">>, <<"Not Found">>}, <<"Given domain does not exist">>}, 735: F1 = fun() -> rest_select_domain(Config, <<"example.db">>) end, 736: mongoose_helper:wait_until(F1, Return, #{time_left => timer:seconds(15)}), 737: %% Double-check 738: F2 = fun() -> select_domain(mim(), <<"example.db">>) end, 739: mongoose_helper:wait_until(F2, {error, not_found}, #{time_left => timer:seconds(5)}). 740: 741: rest_can_delete_domain(Config) -> 742: rest_put_domain(Config, <<"example.db">>, <<"type1">>), 743: {{<<"204">>, _}, _} = 744: rest_delete_domain(Config, <<"example.db">>, <<"type1">>), 745: {error, not_found} = select_domain(mim(), <<"example.db">>). 746: 747: rest_cannot_delete_domain_without_correct_type(Config) -> 748: rest_put_domain(Config, <<"example.db">>, <<"type1">>), 749: {{<<"403">>, <<"Forbidden">>}, <<"Wrong host type was provided">>} = 750: rest_delete_domain(Config, <<"example.db">>, <<"type2">>), 751: {ok, _} = select_domain(mim(), <<"example.db">>). 752: 753: rest_cannot_delete_missing_domain(Config) -> 754: {{<<"404">>, <<"Not Found">>}, <<"Given domain does not exist">>} = 755: rest_delete_domain(Config, <<"example.db">>, <<"type1">>), 756: {{<<"404">>, <<"Not Found">>}, <<"Given domain does not exist">>} = 757: domain_rest_helper:request_delete_domain(Config, <<"example.db">>, <<"type1">>). 758: 759: rest_cannot_enable_missing_domain(Config) -> 760: {{<<"404">>, <<"Not Found">>}, <<"Given domain does not exist">>} = 761: rest_patch_enabled(Config, <<"example.db">>, true). 762: 763: rest_cannot_insert_domain_twice_with_another_host_type(Config) -> 764: rest_put_domain(Config, <<"example.db">>, <<"type1">>), 765: {{<<"409">>, <<"Conflict">>}, <<"Domain already exists">>} = 766: rest_put_domain(Config, <<"example.db">>, <<"type2">>). 767: 768: rest_cannot_insert_domain_with_unknown_host_type(Config) -> 769: {{<<"403">>,<<"Forbidden">>}, <<"Unknown host type">>} = 770: rest_put_domain(Config, <<"example.db">>, <<"type6">>). 771: 772: rest_cannot_delete_domain_with_unknown_host_type(Config) -> 773: {{<<"403">>,<<"Forbidden">>}, <<"Unknown host type">>} = 774: rest_delete_domain(Config, <<"example.db">>, <<"type6">>). 775: 776: %% auth provided, but not configured: 777: rest_cannot_insert_domain_if_auth_provided_but_not_configured(Config) -> 778: {{<<"401">>, <<"Unauthorized">>}, _} = 779: rest_put_domain(set_valid_creds(Config), <<"example.db">>, <<"type1">>). 780: 781: rest_cannot_delete_domain_if_auth_provided_but_not_configured(Config) -> 782: {{<<"401">>, <<"Unauthorized">>}, _} = 783: rest_delete_domain(set_valid_creds(Config), <<"example.db">>, <<"type1">>). 784: 785: rest_cannot_enable_domain_if_auth_provided_but_not_configured(Config) -> 786: {{<<"401">>, <<"Unauthorized">>}, _} = 787: rest_patch_enabled(set_valid_creds(Config), <<"example.db">>, false). 788: 789: rest_cannot_disable_domain_if_auth_provided_but_not_configured(Config) -> 790: {{<<"401">>, <<"Unauthorized">>}, _} = 791: rest_patch_enabled(set_valid_creds(Config), <<"example.db">>, false). 792: 793: rest_cannot_select_domain_if_auth_provided_but_not_configured(Config) -> 794: {{<<"401">>, <<"Unauthorized">>}, _} = 795: rest_select_domain(set_valid_creds(Config), <<"example.db">>). 796: 797: %% with wrong pass: 798: rest_cannot_insert_domain_with_wrong_pass(Config) -> 799: {{<<"401">>, <<"Unauthorized">>}, _} = 800: rest_put_domain(set_invalid_creds(Config), <<"example.db">>, <<"type1">>). 801: 802: rest_cannot_delete_domain_with_wrong_pass(Config) -> 803: {{<<"401">>, <<"Unauthorized">>}, _} = 804: rest_delete_domain(set_invalid_creds(Config), <<"example.db">>, <<"type1">>). 805: 806: rest_cannot_enable_domain_with_wrong_pass(Config) -> 807: {{<<"401">>, <<"Unauthorized">>}, _} = 808: rest_patch_enabled(set_invalid_creds(Config), <<"example.db">>, true). 809: 810: rest_cannot_disable_domain_with_wrong_pass(Config) -> 811: {{<<"401">>, <<"Unauthorized">>}, _} = 812: rest_patch_enabled(set_invalid_creds(Config), <<"example.db">>, false). 813: 814: rest_cannot_select_domain_with_wrong_pass(Config) -> 815: {{<<"401">>, <<"Unauthorized">>}, _} = 816: rest_select_domain(set_invalid_creds(Config), <<"example.db">>). 817: 818: %% without auth: 819: rest_cannot_insert_domain_without_auth(Config) -> 820: {{<<"401">>, <<"Unauthorized">>}, _} = 821: rest_put_domain(set_no_creds(Config), <<"example.db">>, <<"type1">>). 822: 823: rest_cannot_delete_domain_without_auth(Config) -> 824: {{<<"401">>, <<"Unauthorized">>}, _} = 825: rest_delete_domain(set_no_creds(Config), <<"example.db">>, <<"type1">>). 826: 827: rest_cannot_enable_domain_without_auth(Config) -> 828: {{<<"401">>, <<"Unauthorized">>}, _} = 829: rest_patch_enabled(set_no_creds(Config), <<"example.db">>, true). 830: 831: rest_cannot_disable_domain_without_auth(Config) -> 832: {{<<"401">>, <<"Unauthorized">>}, _} = 833: rest_patch_enabled(set_no_creds(Config), <<"example.db">>, false). 834: 835: rest_cannot_select_domain_without_auth(Config) -> 836: {{<<"401">>, <<"Unauthorized">>}, _} = 837: rest_select_domain(set_no_creds(Config), <<"example.db">>). 838: 839: rest_cannot_disable_missing_domain(Config) -> 840: {{<<"404">>, <<"Not Found">>}, <<"Given domain does not exist">>} = 841: rest_patch_enabled(Config, <<"example.db">>, false). 842: 843: rest_can_enable_domain(Config) -> 844: rest_put_domain(Config, <<"example.db">>, <<"type1">>), 845: rest_patch_enabled(Config, <<"example.db">>, false), 846: rest_patch_enabled(Config, <<"example.db">>, true), 847: {ok, #{host_type := <<"type1">>, status := enabled}} = 848: select_domain(mim(), <<"example.db">>). 849: 850: rest_can_select_domain(Config) -> 851: rest_put_domain(Config, <<"example.db">>, <<"type1">>), 852: {HttpStatus, {Info}} = rest_select_domain(Config, <<"example.db">>), 853: SortedResult = {HttpStatus, {lists:sort(Info)}}, 854: {{<<"200">>, <<"OK">>}, 855: {[ {<<"host_type">>, <<"type1">>}, {<<"status">>, <<"enabled">>} ]}} = 856: SortedResult. 857: 858: rest_cannot_select_domain_if_domain_not_found(Config) -> 859: {{<<"404">>, <<"Not Found">>}, <<"Given domain does not exist">>} = 860: rest_select_domain(Config, <<"example.db">>). 861: 862: rest_cannot_select_domain_when_it_is_static(Config) -> 863: {{<<"403">>, <<"Forbidden">>}, <<"Domain is static">>} = 864: rest_select_domain(Config, <<"example.cfg">>). 865: 866: rest_cannot_put_domain_without_host_type(Config) -> 867: {{<<"400">>, <<"Bad Request">>}, <<"'host_type' field is missing">>} = 868: putt_domain_with_custom_body(Config, #{}). 869: 870: rest_cannot_put_domain_without_body(Config) -> 871: {{<<"400">>, <<"Bad Request">>}, <<"Invalid request body">>} = 872: putt_domain_with_custom_body(Config, <<>>). 873: 874: rest_cannot_put_domain_with_invalid_json(Config) -> 875: {{<<"400">>, <<"Bad Request">>}, <<"Invalid request body">>} = 876: putt_domain_with_custom_body(Config, <<"{kek">>). 877: 878: rest_cannot_put_domain_with_invalid_name(Config) -> 879: {{<<"400">>, <<"Bad Request">>}, <<"Invalid domain name">>} = 880: rest_put_domain(Config, <<"%f3">>, <<"type1">>). % nameprep fails for ASCII code 243 881: 882: rest_cannot_put_domain_when_it_is_static(Config) -> 883: {{<<"403">>, <<"Forbidden">>}, <<"Domain is static">>} = 884: rest_put_domain(Config, <<"example.cfg">>, <<"type1">>). 885: 886: rest_cannot_delete_domain_without_host_type(Config) -> 887: {{<<"400">>, <<"Bad Request">>}, <<"'host_type' field is missing">>} = 888: delete_custom(Config, admin, <<"/domains/example.db">>, #{}). 889: 890: rest_cannot_delete_domain_without_body(Config) -> 891: {{<<"400">>, <<"Bad Request">>}, <<"Invalid request body">>} = 892: delete_custom(Config, admin, <<"/domains/example.db">>, <<>>). 893: 894: rest_cannot_delete_domain_with_invalid_json(Config) -> 895: {{<<"400">>, <<"Bad Request">>}, <<"Invalid request body">>} = 896: delete_custom(Config, admin, <<"/domains/example.db">>, <<"{kek">>). 897: 898: rest_cannot_delete_domain_when_it_is_static(Config) -> 899: {{<<"403">>, <<"Forbidden">>}, <<"Domain is static">>} = 900: rest_delete_domain(Config, <<"example.cfg">>, <<"type1">>), 901: {{<<"403">>, <<"Forbidden">>}, <<"Domain is static">>} = 902: domain_rest_helper:request_delete_domain(Config, <<"example.cfg">>, <<"type1">>). 903: 904: rest_cannot_patch_domain_without_enabled_field(Config) -> 905: {{<<"400">>, <<"Bad Request">>}, <<"'enabled' field is missing">>} = 906: patch_custom(Config, admin, <<"/domains/example.db">>, #{}). 907: 908: rest_cannot_patch_domain_without_body(Config) -> 909: {{<<"400">>,<<"Bad Request">>}, <<"Invalid request body">>} = 910: patch_custom(Config, admin, <<"/domains/example.db">>, <<>>). 911: 912: rest_cannot_patch_domain_with_invalid_json(Config) -> 913: {{<<"400">>,<<"Bad Request">>}, <<"Invalid request body">>} = 914: patch_custom(Config, admin, <<"/domains/example.db">>, <<"{kek">>). 915: 916: %% SQL query is mocked to fail 917: rest_insert_domain_fails_if_db_fails(Config) -> 918: assert_rest_db_error(rest_put_domain(Config, <<"example.db">>, <<"type1">>)). 919: 920: rest_insert_domain_fails_if_service_disabled(Config) -> 921: service_disabled(mim()), 922: {{<<"403">>, <<"Forbidden">>}, <<"Dynamic domains service is disabled">>} = 923: rest_put_domain(Config, <<"example.db">>, <<"type1">>). 924: 925: %% SQL query is mocked to fail 926: rest_delete_domain_fails_if_db_fails(Config) -> 927: {ok, _} = insert_domain(mim(), <<"example.db">>, <<"type1">>), 928: assert_rest_db_error(rest_delete_domain(Config, <<"example.db">>, <<"type1">>)). 929: 930: rest_delete_domain_fails_if_service_disabled(Config) -> 931: service_disabled(mim()), 932: {{<<"403">>, <<"Forbidden">>}, <<"Dynamic domains service is disabled">>} = 933: rest_delete_domain(Config, <<"example.db">>, <<"type1">>). 934: 935: %% SQL query is mocked to fail 936: rest_enable_domain_fails_if_db_fails(Config) -> 937: assert_rest_db_error(rest_patch_enabled(Config, <<"example.db">>, true)). 938: 939: rest_enable_domain_fails_if_service_disabled(Config) -> 940: service_disabled(mim()), 941: {{<<"403">>, <<"Forbidden">>}, <<"Dynamic domains service is disabled">>} = 942: rest_patch_enabled(Config, <<"example.db">>, true). 943: 944: rest_cannot_enable_domain_when_it_is_static(Config) -> 945: {{<<"403">>, <<"Forbidden">>}, <<"Domain is static">>} = 946: rest_patch_enabled(Config, <<"example.cfg">>, true). 947: 948: rest_delete_domain_cleans_data_from_mam(Config) -> 949: HostType = dummy_auth_host_type(), 950: rest_put_domain(Config, <<"example.com">>, HostType), %% alice3 951: rest_put_domain(Config, <<"example.org">>, HostType), %% bob3 952: sync(), 953: %% Alice and Bob use example.com 954: F = fun(FreshConfig, Alice, Bob) -> 955: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"OH, HAI!">>)), 956: escalus:wait_for_stanza(Bob), 957: mam_helper:wait_for_archive_size_with_host_type(HostType, Alice, 1), 958: mam_helper:wait_for_archive_size_with_host_type(HostType, Bob, 1), 959: {{<<"204">>, _}, _} = 960: rest_delete_domain(Config, <<"example.com">>, HostType), 961: {{<<"204">>, _}, _} = 962: rest_delete_domain(Config, <<"example.org">>, HostType), 963: sync(), 964: %% At this point MIM cannot resolve a domain to a host type, 965: %% so we have to pass it 966: mam_helper:wait_for_archive_size_with_host_type(HostType, Alice, 0), 967: mam_helper:wait_for_archive_size_with_host_type(HostType, Bob, 0), 968: %% Already cleaned at this point 969: escalus_cleaner:remove_client(FreshConfig, Alice), 970: escalus_cleaner:remove_client(FreshConfig, Bob) 971: end, 972: escalus:fresh_story_with_config(Config, [{alice3, 1}, {bob3, 1}], F). 973: 974: %%-------------------------------------------------------------------- 975: %% Helpers 976: %%-------------------------------------------------------------------- 977: 978: service_enabled(Node) -> 979: service_enabled(Node, #{}), 980: sync_local(Node). 981: 982: service_enabled(Node, ExtraOpts) -> 983: Opts = config([services, service_domain_db], ExtraOpts), 984: dynamic_services:ensure_started(Node, service_domain_db, Opts), 985: true = rpc(Node, service_domain_db, enabled, []). 986: 987: service_disabled(Node) -> 988: dynamic_services:ensure_stopped(Node, service_domain_db), 989: false = rpc(Node, service_domain_db, enabled, []). 990: 991: restart_domain_core(Node, Pairs, AllowedHostTypes) -> 992: domain_helper:restart_domain_core(Node, Pairs, AllowedHostTypes). 993: 994: restart_domain_core(Node) -> 995: domain_helper:restart_domain_core(Node). 996: 997: insert_domain(Node, Domain, HostType) -> 998: rpc(Node, mongoose_domain_api, insert_domain, [Domain, HostType]). 999: 1000: delete_domain(Node, Domain, HostType) -> 1001: rpc(Node, mongoose_domain_api, delete_domain, [Domain, HostType]). 1002: 1003: request_delete_domain(Node, Domain, HostType) -> 1004: rpc(Node, mongoose_domain_api, request_delete_domain, [Domain, HostType]). 1005: 1006: select_domain(Node, Domain) -> 1007: rpc(Node, mongoose_domain_sql, select_domain, [Domain]). 1008: 1009: check_domain_password(Node, Domain, Password) -> 1010: rpc(Node, mongoose_domain_api, check_domain_password, [Domain, Password]). 1011: 1012: set_domain_password(Node, Domain, Password) -> 1013: rpc(Node, mongoose_domain_api, set_domain_password, [Domain, Password]). 1014: 1015: delete_domain_password(Node, Domain) -> 1016: rpc(Node, mongoose_domain_api, delete_domain_password, [Domain]). 1017: 1018: select_domain_admin(Node, Domain) -> 1019: rpc(Node, mongoose_domain_sql, select_domain_admin, [Domain]). 1020: 1021: insert_full_event(Node, EventId, Domain) -> 1022: rpc(Node, mongoose_domain_sql, insert_full_event, [EventId, Domain]). 1023: 1024: insert_domain_settings_without_event(Node, Domain, HostType) -> 1025: rpc(Node, mongoose_domain_sql, insert_domain_settings_without_event, 1026: [Domain, HostType]). 1027: 1028: get_event_ids_between(Node, Min, Max) -> 1029: rpc(Node, mongoose_domain_sql, get_event_ids_between, [Min, Max]). 1030: 1031: erase_database(Node) -> 1032: case mongoose_helper:is_rdbms_enabled(domain()) of 1033: true -> 1034: prepare_test_queries(Node), 1035: rpc(Node, mongoose_domain_sql, erase_database, [global]); 1036: false -> ok 1037: end. 1038: 1039: prepare_test_queries(Node) -> 1040: case mongoose_helper:is_rdbms_enabled(domain()) of 1041: true -> rpc(Node, mongoose_domain_sql, prepare_test_queries, []); 1042: false -> ok 1043: end. 1044: 1045: get_min_event_id(Node) -> 1046: {Min, _} = rpc(Node, mongoose_domain_sql, get_minmax_event_id, []), 1047: Min. 1048: 1049: get_max_event_id(Node) -> 1050: {_, Max} = rpc(Node, mongoose_domain_sql, get_minmax_event_id, []), 1051: Max. 1052: 1053: delete_events_older_than(Node, Id) -> 1054: rpc(Node, mongoose_domain_sql, delete_events_older_than, [Id]). 1055: 1056: get_host_type(Node, Domain) -> 1057: rpc(Node, mongoose_domain_api, get_host_type, [Domain]). 1058: 1059: get_domains_by_host_type(Node, HostType) -> 1060: rpc(Node, mongoose_domain_api, get_domains_by_host_type, [HostType]). 1061: 1062: get_all_static(Node) -> 1063: rpc(Node, mongoose_domain_api, get_all_static, []). 1064: 1065: get_all_dynamic(Node) -> 1066: rpc(Node, mongoose_domain_api, get_all_dynamic, []). 1067: 1068: disable_domain(Node, Domain) -> 1069: rpc(Node, mongoose_domain_api, disable_domain, [Domain]). 1070: 1071: enable_domain(Node, Domain) -> 1072: rpc(Node, mongoose_domain_api, enable_domain, [Domain]). 1073: 1074: start_domain_removal_hook(HostType) -> 1075: Server = spawn(fun stopper/0), 1076: rpc(mim(), gen_hook, add_handler, 1077: [ remove_domain, HostType, fun ?MODULE:domain_removal_hook_fn/3, 1078: #{server => Server}, 30]), %% Priority is so that it comes before muclight and mam 1079: Server. 1080: 1081: stop_domain_removal_hook(HostType, Server) -> 1082: rpc(mim(), gen_hook, delete_handler, 1083: [ remove_domain, HostType, fun ?MODULE:domain_removal_hook_fn/3, 1084: #{server => Server}, 30]). 1085: 1086: domain_removal_hook_fn(Acc, _Params, #{server := Server}) -> 1087: Server ! {wait, self()}, 1088: receive continue -> ok end, 1089: {ok, Acc}. 1090: 1091: stopper() -> 1092: receive 1093: {wait, From} -> 1094: receive continue -> ok end, 1095: From ! continue 1096: end. 1097: 1098: %% force_check_for_updates is already sent by insert or delete commands. 1099: %% But it is async. 1100: %% So, the only thing is left to sync is to call ping to the gen_server 1101: %% to ensure we've finished the check. 1102: sync() -> 1103: sync_local(mim()), 1104: sync_local(mim2()), 1105: ok. 1106: 1107: with_service_suspended(F) -> 1108: suspend_service(mim()), 1109: suspend_service(mim2()), 1110: try 1111: F() 1112: after 1113: resume_service(mim()), 1114: resume_service(mim2()) 1115: end. 1116: 1117: suspend_service(Node) -> 1118: ok = rpc(Node, sys, suspend, [service_domain_db]). 1119: 1120: resume_service(Node) -> 1121: ok = rpc(Node, sys, resume, [service_domain_db]). 1122: 1123: sync_local(Node) -> 1124: pong = rpc(Node, service_domain_db, sync_local, []). 1125: 1126: force_check_for_updates(Node) -> 1127: ok = rpc(Node, service_domain_db, force_check_for_updates, []). 1128: 1129: %% Needed for pg2 group to work 1130: %% So, multiple node tests work 1131: ensure_nodes_know_each_other() -> 1132: pong = rpc(mim2(), net_adm, ping, [maps:get(node, mim())]). 1133: 1134: maybe_setup_meck(rest_insert_domain_fails_if_db_fails) -> 1135: ok = rpc(mim(), meck, new, [mongoose_domain_sql, [passthrough, no_link]]), 1136: ok = rpc(mim(), meck, expect, [mongoose_domain_sql, insert_domain, 2, 1137: {error, {db_error, simulated_db_error}}]); 1138: maybe_setup_meck(rest_delete_domain_fails_if_db_fails) -> 1139: ok = rpc(mim(), meck, new, [mongoose_domain_sql, [passthrough, no_link]]), 1140: ok = rpc(mim(), meck, expect, [mongoose_domain_sql, delete_domain, 2, 1141: {error, {db_error, simulated_db_error}}]); 1142: maybe_setup_meck(rest_enable_domain_fails_if_db_fails) -> 1143: ok = rpc(mim(), meck, new, [mongoose_domain_sql, [passthrough, no_link]]), 1144: ok = rpc(mim(), meck, expect, [mongoose_domain_sql, set_status, 2, 1145: {error, {db_error, simulated_db_error}}]); 1146: maybe_setup_meck(db_crash_on_initial_load_restarts_service) -> 1147: ok = rpc(mim(), meck, new, [mongoose_domain_sql, [passthrough, no_link]]), 1148: ok = rpc(mim(), meck, expect, [mongoose_domain_sql, select_from, 2, something_strange]), 1149: ok = rpc(mim(), meck, new, [service_domain_db, [passthrough, no_link]]), 1150: ok = rpc(mim(), meck, expect, [service_domain_db, restart, 0, ok]); 1151: maybe_setup_meck(db_out_of_sync_restarts_service) -> 1152: ok = rpc(mim(), meck, new, [service_domain_db, [passthrough, no_link]]), 1153: ok = rpc(mim(), meck, expect, [service_domain_db, restart, 0, ok]); 1154: maybe_setup_meck(_TestCase) -> 1155: ok. 1156: 1157: maybe_teardown_meck(_) -> 1158: %% running unload meck makes no harm even if nothing is mocked 1159: rpc(mim(), meck, unload, []). 1160: 1161: leave_cluster(Config) -> 1162: execute_command(<<"server">>, <<"leaveCluster">>, #{}, Config). 1163: 1164: join_cluster(Config) -> 1165: #{node := Node2} = distributed_helper:mim2(), 1166: execute_command(<<"server">>, <<"joinCluster">>, #{<<"node">> => Node2}, Config). 1167: 1168: assert_domains_are_equal(HostType) -> 1169: Domains1 = lists:sort(get_domains_by_host_type(mim(), HostType)), 1170: Domains2 = lists:sort(get_domains_by_host_type(mim2(), HostType)), 1171: case Domains1 == Domains2 of 1172: true -> ok; 1173: false -> ct:fail({Domains1, Domains2}) 1174: end. 1175: 1176: assert_rest_db_error({Result, Msg}) -> 1177: ?assertEqual({<<"500">>, <<"Internal Server Error">>}, Result), 1178: ?assertEqual(<<>>, Msg). % shouldn't leak out the DB error, it's in the logs anyway 1179: 1180: dummy_auth_host_type() -> 1181: <<"dummy auth">>. %% specified in the TOML config file