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