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