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