1: -module(graphql_mnesia_SUITE). 2: -include_lib("eunit/include/eunit.hrl"). 3: 4: -compile([export_all, nowarn_export_all]). 5: 6: -import(distributed_helper, [require_rpc_nodes/1, mim/0, mim2/0, rpc/4]). 7: -import(domain_helper, [host_type/1]). 8: -import(mongooseimctl_helper, [rpc_call/3]). 9: -import(graphql_helper, [execute_command/4, execute_user_command/5, user_to_bin/1, 10: get_ok_value/2, get_err_code/1, get_err_value/2, get_unauthorized/1, 11: get_coercion_err_msg/1]). 12: 13: -record(mnesia_table_test, {key :: integer(), name :: binary()}). 14: -record(vcard, {us, vcard}). 15: 16: all() -> 17: [{group, admin_mnesia_cli}, 18: {group, admin_mnesia_http}, 19: {group, domain_admin_mnesia}]. 20: 21: groups() -> 22: [{admin_mnesia_http, [sequence], admin_mnesia_tests()}, 23: {admin_mnesia_cli, [sequence], admin_mnesia_tests()}, 24: {domain_admin_mnesia, [], domain_admin_tests()}]. 25: 26: admin_mnesia_tests() -> 27: [dump_mnesia_table_test, 28: dump_mnesia_table_file_error_test, 29: dump_mnesia_table_no_table_error_test, 30: dump_mnesia_test, 31: dump_mnesia_file_error_test, 32: backup_and_restore_test, 33: backup_wrong_filename_test, 34: backup_wrong_path_test, 35: restore_no_file_test, 36: restore_wrong_file_format_test, 37: restore_bad_file_test, 38: restore_bad_path_test, 39: load_mnesia_test, 40: load_mnesia_no_file_test, 41: load_mnesia_bad_file_test, 42: load_mnesia_bad_file2_test, 43: change_nodename_test, 44: change_nodename_bad_name, 45: change_nodename_empty_name, 46: change_nodename_no_file_error_test, 47: change_nodename_bad_file_error_test, 48: get_info_test, 49: get_all_info_test, 50: install_fallback_error_test, 51: set_master_test, 52: set_master_self_test, 53: set_master_bad_name_test, 54: set_master_empty_name_test]. 55: 56: domain_admin_tests() -> 57: [domain_admin_dump_mnesia_table_test, 58: domain_admin_dump_mnesia_test, 59: domain_admin_backup_test, 60: domain_admin_restore_test, 61: domain_admin_load_mnesia_test, 62: domain_admin_change_nodename_test, 63: domain_admin_install_fallback_test, 64: domain_admin_set_master_test, 65: domain_admin_get_info_test]. 66: 67: init_per_suite(Config) -> 68: application:ensure_all_started(jid), 69: ok = mnesia:create_schema([node()]), 70: ok = mnesia:start(), 71: Config1 = escalus:init_per_suite(Config), 72: ejabberd_node_utils:init(mim(), Config1). 73: 74: end_per_suite(_C) -> 75: mnesia:stop(), 76: mnesia:delete_schema([node()]). 77: 78: init_per_group(admin_mnesia_http, Config) -> 79: graphql_helper:init_admin_handler(Config); 80: init_per_group(admin_mnesia_cli, Config) -> 81: graphql_helper:init_admin_cli(Config); 82: init_per_group(domain_admin_mnesia, Config) -> 83: graphql_helper:init_domain_admin_handler(Config). 84: 85: end_per_group(_, _Config) -> 86: graphql_helper:clean(), 87: escalus_fresh:clean(). 88: 89: % Admin tests 90: 91: dump_mnesia_table_test(Config) -> 92: Filename = <<"dump_mnesia_table_test">>, 93: create_mnesia_table_and_write([{attributes, record_info(fields, mnesia_table_test)}]), 94: Res = dump_mnesia_table(Filename, <<"mnesia_table_test">>, Config), 95: ParsedRes = get_ok_value([data, mnesia, dumpTable], Res), 96: ?assertEqual(<<"Mnesia table successfully dumped">>, ParsedRes), 97: delete_mnesia_table(), 98: check_created_file(create_full_filename(Filename), <<"{mnesia_table_test,1,<<\"TEST\">>}">>). 99: 100: dump_mnesia_table_file_error_test(Config) -> 101: Res = dump_mnesia_table(<<>>, <<"vcard">>, Config), 102: ?assertEqual(<<"file_error">>, get_err_code(Res)). 103: 104: dump_mnesia_table_no_table_error_test(Config) -> 105: Res = dump_mnesia_table(<<"AA">>, <<"NON_EXISTING">>, Config), 106: ?assertEqual(<<"table_does_not_exist">>, get_err_code(Res)). 107: 108: dump_mnesia_test(Config) -> 109: Filename = <<"dump_mnesia_test">>, 110: create_mnesia_table_and_write([{disc_copies, [maps:get(node, mim())]}, 111: {attributes, record_info(fields, mnesia_table_test)}]), 112: Res = dump_mnesia(Filename, Config), 113: ParsedRes = get_ok_value([data, mnesia, dump], Res), 114: ?assertEqual(<<"Mnesia successfully dumped">>, ParsedRes), 115: delete_mnesia_table(), 116: check_created_file(create_full_filename(Filename), <<"{mnesia_table_test,1,<<\"TEST\">>}">>). 117: 118: dump_mnesia_file_error_test(Config) -> 119: Res = dump_mnesia(<<>>, Config), 120: ?assertEqual(<<"file_error">>, get_err_code(Res)). 121: 122: backup_and_restore_test(Config) -> 123: Filename = <<"backup_restore_mnesia_test">>, 124: create_vcard_table(), 125: write_to_vcard(), 126: ?assert(is_record_in_vcard_table()), 127: Res = backup_mnesia(Filename, Config), 128: ParsedRes = get_ok_value([data, mnesia, backup], Res), 129: ?assertEqual(<<"Mnesia backup was successfully created">>, ParsedRes), 130: delete_record_from_table(), 131: ?assertEqual(false, is_record_in_vcard_table()), 132: Res2 = restore_mnesia(Filename, Config), 133: ParsedRes2 = get_ok_value([data, mnesia, restore], Res2), 134: ?assertEqual(<<"Mnesia was successfully restored">>, ParsedRes2), 135: ?assert(is_record_in_vcard_table()), 136: delete_record_from_table(), 137: delete_file(create_full_filename(Filename)). 138: 139: backup_wrong_filename_test(Config) -> 140: Res = backup_mnesia(<<>>, Config), 141: ?assertEqual(<<"wrong_filename">>, get_err_code(Res)). 142: 143: backup_wrong_path_test(Config) -> 144: Res = backup_mnesia(<<"/etc/">>, Config), 145: ?assertEqual(<<"cannot_backup">>, get_err_code(Res)). 146: 147: restore_no_file_test(Config) -> 148: Res = restore_mnesia(<<>>, Config), 149: ?assertEqual(<<"file_not_found">>, get_err_code(Res)). 150: 151: restore_bad_file_test(Config) -> 152: Res = restore_mnesia(<<"NON_EXISTING">>, Config), 153: ?assertEqual(<<"file_not_found">>, get_err_code(Res)). 154: 155: restore_bad_path_test(Config) -> 156: Res = restore_mnesia(<<"/etc/">>, Config), 157: ?assertEqual(<<"cannot_restore">>, get_err_code(Res)). 158: 159: restore_wrong_file_format_test(Config) -> 160: Filename = <<"restore_error">>, 161: FileFullPath = create_full_filename(Filename), 162: create_file(FileFullPath), 163: Res = restore_mnesia(Filename, Config), 164: delete_file(Filename), 165: ?assertEqual(<<"not_a_log_file_error">>, get_err_code(Res)). 166: 167: load_mnesia_test(Config) -> 168: Filename = <<"load_mnesia_test">>, 169: create_mnesia_table_and_write([{disc_copies, [maps:get(node, mim())]}, 170: {attributes, record_info(fields, mnesia_table_test)}]), 171: Res = dump_mnesia(Filename, Config), 172: ParsedRes = get_ok_value([data, mnesia, dump], Res), 173: ?assertEqual(<<"Mnesia successfully dumped">>, ParsedRes), 174: delete_mnesia_table(), 175: check_if_response_contains(load_mnesia(Filename, Config), <<"Mnesia was successfully loaded">>), 176: ?assert(is_record_in_table()), 177: delete_mnesia_table(). 178: 179: load_mnesia_bad_file_test(Config) -> 180: Filename = <<"EXISTING_BUT_EMPTY">>, 181: create_file(create_full_filename(Filename)), 182: check_if_response_contains(load_mnesia(Filename, Config), <<"bad_file_format">>). 183: 184: load_mnesia_bad_file2_test(Config) -> 185: Filename = <<"EXISTING_FILE">>, 186: create_and_write_file(create_full_filename(Filename)), 187: check_if_response_contains(load_mnesia(Filename, Config), <<"bad_file_format">>). 188: 189: load_mnesia_no_file_test(Config) -> 190: Filename = <<"NON_EXISTING">>, 191: check_if_response_contains(load_mnesia(Filename, Config), <<"file_not_found">>). 192: 193: change_nodename_test(Config) -> 194: Filename1 = <<"change_nodename_mnesia_test">>, 195: Filename2 = <<"change_nodename2_mnesia_test">>, 196: create_vcard_table(), 197: write_to_vcard(), 198: ?assert(is_record_in_vcard_table()), 199: Res = backup_mnesia(Filename1, Config), 200: ParsedRes = get_ok_value([data, mnesia, backup], Res), 201: ?assertEqual(<<"Mnesia backup was successfully created">>, ParsedRes), 202: ChangeFrom = <<"mongooseim@localhost">>, 203: ChangeTo = <<"change_nodename_test@localhost">>, 204: Value = change_nodename(ChangeFrom, ChangeTo, Filename1, Filename2, Config), 205: check_if_response_contains(Value, 206: <<"Name of the node in the backup was successfully changed">>). 207: 208: change_nodename_bad_name(Config) -> 209: Filename1 = <<"change_incorrect_nodename_mnesia_test">>, 210: Filename2 = <<"change_incorrect_nodename2_mnesia_test">>, 211: ChangeFrom = <<"mongooseim@localhost">>, 212: ChangeTo = <<"incorrect_format">>, 213: Value = change_nodename(ChangeFrom, ChangeTo, Filename1, Filename2, Config), 214: get_coercion_err_msg(Value). 215: 216: change_nodename_empty_name(Config) -> 217: Filename1 = <<"change_incorrect_nodename_mnesia_test">>, 218: Filename2 = <<"change_incorrect_nodename2_mnesia_test">>, 219: ChangeFrom = <<"mongooseim@localhost">>, 220: ChangeTo = <<>>, 221: Value = change_nodename(ChangeFrom, ChangeTo, Filename1, Filename2, Config), 222: get_coercion_err_msg(Value). 223: 224: change_nodename_no_file_error_test(Config) -> 225: Filename1 = <<"non_existing">>, 226: Filename2 = <<"change_nodename2_mnesia_test">>, 227: ChangeFrom = <<"mongooseim@localhost">>, 228: ChangeTo = <<"change_nodename_test@localhost">>, 229: Value = change_nodename(ChangeFrom, ChangeTo, Filename1, Filename2, Config), 230: ?assertEqual(<<"file_not_found">>, get_err_code(Value)). 231: 232: change_nodename_bad_file_error_test(Config) -> 233: Filename1 = <<"existing_but_having_wrong_structure">>, 234: Filename2 = <<"change_nodename2_mnesia_test">>, 235: create_and_write_file(create_full_filename(Filename1)), 236: ChangeFrom = <<"mongooseim@localhost">>, 237: ChangeTo = <<"change_nodename_test@localhost">>, 238: Value = change_nodename(ChangeFrom, ChangeTo, Filename1, Filename2, Config), 239: ?assertEqual(<<"bad_file_format">>, get_err_code(Value)). 240: 241: get_info_test(Config) -> 242: Res = get_info(maps:keys(mnesia_info_check()) ++ [<<"AAA">>], Config), 243: ?assertEqual(<<"bad_key_error">>, get_err_code(Res)), 244: ParsedRes = get_err_value([data, mnesia, systemInfo], Res), 245: Map = mnesia_info_check(), 246: lists:foreach(fun 247: (#{<<"result">> := Element, <<"key">> := Key}) -> 248: Fun = maps:get(Key, Map), 249: ?assertEqual({true, Element, Key, Fun}, {?MODULE:Fun(Element), Element, Key, Fun}); 250: (null) -> 251: ok 252: end, ParsedRes). 253: 254: get_all_info_test(Config) -> 255: Res = get_info(null, Config), 256: ParsedRes = get_ok_value([data, mnesia, systemInfo], Res), 257: Map = mnesia_info_check(), 258: lists:foreach(fun (#{<<"result">> := Element, <<"key">> := Key}) -> 259: Fun = maps:get(Key, Map), 260: ?assertEqual({true, Element, Key, Fun}, {?MODULE:Fun(Element), Element, Key, Fun}) 261: end, ParsedRes). 262: 263: install_fallback_error_test(Config) -> 264: Res = install_fallback(<<"AAAA">>, Config), 265: ?assertEqual(<<"cannot_fallback">>, get_err_code(Res)). 266: 267: set_master_test(Config) -> 268: ParsedRes = get_ok_value([data, mnesia, setMaster], set_master(mim(), Config)), 269: ?assertEqual(<<"Master node set">>, ParsedRes). 270: 271: set_master_self_test(Config) -> 272: ParsedRes = get_ok_value([data, mnesia, setMaster], set_master(#{node => self}, Config)), 273: ?assertEqual(<<"Master node set">>, ParsedRes). 274: 275: set_master_bad_name_test(Config) -> 276: Res = set_master(#{node => incorrect_name}, Config), 277: get_coercion_err_msg(Res). 278: 279: set_master_empty_name_test(Config) -> 280: Res = set_master(#{node => ''}, Config), 281: get_coercion_err_msg(Res). 282: 283: % Domain admin tests 284: 285: domain_admin_dump_mnesia_table_test(Config) -> 286: get_unauthorized(dump_mnesia_table(<<"File">>, <<"mnesia_table_test">>, Config)). 287: 288: domain_admin_dump_mnesia_test(Config) -> 289: get_unauthorized(dump_mnesia(<<"File">>, Config)). 290: 291: domain_admin_backup_test(Config) -> 292: get_unauthorized(backup_mnesia(<<"Path">>, Config)). 293: 294: domain_admin_restore_test(Config) -> 295: get_unauthorized(restore_mnesia(<<"Path">>, Config)). 296: 297: domain_admin_load_mnesia_test(Config) -> 298: get_unauthorized(load_mnesia(<<"Path">>, Config)). 299: 300: domain_admin_change_nodename_test(Config) -> 301: Filename1 = <<"change_nodename_mnesia_test">>, 302: Filename2 = <<"change_nodename2_mnesia_test">>, 303: ChangeFrom = <<"mongooseim@localhost">>, 304: ChangeTo = <<"change_nodename_test@localhost">>, 305: get_unauthorized(change_nodename(ChangeFrom, ChangeTo, Filename1, Filename2, Config)). 306: 307: domain_admin_install_fallback_test(Config) -> 308: get_unauthorized(install_fallback(<<"Path">>, Config)). 309: 310: domain_admin_set_master_test(Config) -> 311: get_unauthorized(set_master(mim(), Config)). 312: 313: domain_admin_get_info_test(Config) -> 314: get_unauthorized(get_info([<<"running_db_nodes">>], Config)). 315: 316: %-------------------------------------------------------------------------------------------------- 317: % Helpers 318: %-------------------------------------------------------------------------------------------------- 319: 320: create_mnesia_table_and_write(Attrs) -> 321: rpc_call(mnesia, delete_table, [mnesia_table_test]), 322: {atomic, ok} = rpc_call(mnesia, create_table, [mnesia_table_test, Attrs]), 323: rpc_call(mnesia, dirty_write, 324: [mnesia_table_test, #mnesia_table_test{key = 1, name = <<"TEST">>}]). 325: 326: create_vcard_table() -> 327: rpc_call(mnesia, delete_table, [vcard]), 328: rpc_call(mnesia, create_table, [vcard, [{disc_copies, [maps:get(node, mim())]}, 329: {attributes, record_info(fields, vcard)}]]). 330: 331: write_to_vcard() -> 332: rpc_call(mnesia, dirty_write, [vcard, #vcard{us = 1, vcard = <<"TEST">>}]). 333: 334: is_record_in_table() -> 335: Expected = [#mnesia_table_test{key = 1, name = <<"TEST">>}], 336: Record = rpc_call(mnesia, dirty_read, [mnesia_table_test, 1]), 337: Expected == Record. 338: 339: is_record_in_vcard_table() -> 340: Expected = [#vcard{us = 1, vcard = <<"TEST">>}], 341: Record = rpc_call(mnesia, dirty_read, [vcard, 1]), 342: Expected == Record. 343: 344: delete_record_from_table() -> 345: ok = rpc_call(mnesia, dirty_delete, [vcard, 1]). 346: 347: create_full_filename(Filename) -> 348: Path = list_to_binary(get_mim_cwd() ++ "/"), 349: <<Path/binary, Filename/binary>>. 350: 351: delete_mnesia_table() -> 352: {atomic, ok} = rpc_call(mnesia, delete_table, [mnesia_table_test]). 353: 354: check_created_file(FullPath, ExpectedContent) -> 355: {ok, FileInsides} = file:read_file(FullPath), 356: ?assertMatch({_,_}, binary:match(FileInsides, ExpectedContent)), 357: delete_file(FullPath). 358: 359: create_file(FullPath) -> 360: file:open(FullPath, [write]), 361: file:close(FullPath). 362: 363: create_and_write_file(FullPath) -> 364: {ok, File} = file:open(FullPath, [write]), 365: io:format(File, "~s~n", ["TEST"]), 366: file:close(FullPath). 367: 368: check_if_response_contains(Response, String) -> 369: ParsedLoadRes = io_lib:format("~p", [Response]), 370: ?assertMatch({_,_}, binary:match(list_to_binary(ParsedLoadRes), String)). 371: 372: delete_file(FullPath) -> 373: file:delete(FullPath). 374: 375: get_info(null, Config) -> 376: execute_command(<<"mnesia">>, <<"systemInfo">>, #{}, Config); 377: get_info(Keys, Config) -> 378: execute_command(<<"mnesia">>, <<"systemInfo">>, #{keys => Keys}, Config). 379: 380: install_fallback(Path, Config) -> 381: execute_command(<<"mnesia">>, <<"installFallback">>, #{path => Path}, Config). 382: 383: dump_mnesia(Path, Config) -> 384: execute_command(<<"mnesia">>, <<"dump">>, #{path => Path}, Config). 385: 386: backup_mnesia(Path, Config) -> 387: execute_command(<<"mnesia">>, <<"backup">>, #{path => Path}, Config). 388: 389: restore_mnesia(Path, Config) -> 390: execute_command(<<"mnesia">>, <<"restore">>, #{path => Path}, Config). 391: 392: dump_mnesia_table(Path, Table, Config) -> 393: execute_command(<<"mnesia">>, <<"dumpTable">>, #{path => Path, table => Table}, Config). 394: 395: load_mnesia(Path, Config) -> 396: execute_command(<<"mnesia">>, <<"load">>, #{path => Path}, Config). 397: 398: change_nodename(ChangeFrom, ChangeTo, Source, Target, Config) -> 399: Vars = #{<<"fromString">> => ChangeFrom, <<"toString">> => ChangeTo, 400: <<"source">> => Source, <<"target">> => Target}, 401: execute_command(<<"mnesia">>, <<"changeNodename">>, Vars, Config). 402: 403: set_master(Node, Config) -> 404: execute_command(<<"mnesia">>, <<"setMaster">>, Node, Config). 405: 406: mnesia_info_check() -> 407: #{<<"access_module">> => check_binary, 408: <<"auto_repair">> => check_binary, 409: <<"backend_types">> => check_list, 410: <<"backup_module">> => check_binary, 411: <<"checkpoints">> => check_list, 412: <<"db_nodes">> => check_list, 413: <<"debug">> => check_binary, 414: <<"directory">> => check_binary, 415: <<"dump_log_load_regulation">> => check_binary, 416: <<"dump_log_time_threshold">> => check_integer, 417: <<"dump_log_update_in_place">> => check_binary, 418: <<"dump_log_write_threshold">> => check_integer, 419: <<"event_module">> => check_binary, 420: <<"extra_db_nodes">> => check_list, 421: <<"fallback_activated">> => check_binary, 422: <<"held_locks">> => check_list, 423: <<"ignore_fallback_at_startup">> => check_binary, 424: <<"fallback_error_function">> => check_binary, 425: <<"is_running">> => check_binary, 426: <<"local_tables">> => check_list, 427: <<"lock_queue">> => check_list, 428: <<"log_version">> => check_binary, 429: <<"master_node_tables">> => check_list, 430: <<"max_wait_for_decision">> => check_binary, 431: <<"protocol_version">> => check_binary, 432: <<"running_db_nodes">> => check_list, 433: <<"schema_location">> => check_binary, 434: <<"schema_version">> => check_binary, 435: <<"subscribers">> => check_list, 436: <<"tables">> => check_list, 437: <<"transaction_commits">> => check_integer, 438: <<"transaction_failures">> => check_integer, 439: <<"transaction_log_writes">> => check_integer, 440: <<"transaction_restarts">> => check_integer, 441: <<"transactions">> => check_list, 442: <<"use_dir">> => check_binary, 443: <<"core_dir">> => check_binary, 444: <<"no_table_loaders">> => check_integer, 445: <<"dc_dump_limit">> => check_integer, 446: <<"send_compressed">> => check_integer, 447: <<"max_transfer_size">> => check_integer, 448: <<"version">> => check_binary, 449: <<"db_nodes">> => check_list, 450: <<"running_db_nodes">> => check_list}. 451: 452: check_list(L) -> 453: lists:all(fun(Item) -> is_binary(Item) end, L). 454: 455: check_binary(Value) -> is_binary(Value). 456: 457: check_integer(Value) -> is_integer(Value). 458: 459: get_mim_cwd() -> 460: {ok, Cwd} = rpc(mim(), file, get_cwd, []), 461: Cwd.