1: -module(gen_mod_deps_SUITE). 2: -compile([export_all, nowarn_export_all]). 3: 4: -include_lib("common_test/include/ct.hrl"). 5: -include_lib("eunit/include/eunit.hrl"). 6: 7: -define(MODS, [mod_a, mod_b, mod_c, mod_d]). 8: 9: all() -> 10: [ 11: starts_modules, 12: starts_dependencies, 13: starts_dependency_chain, 14: starts_dependency_dag, 15: fails_on_dependency_cycle, 16: succeeds_on_cycle_with_soft_dep_in_path, 17: succeeds_on_adding_soft_dependency_cycle_edge, 18: forces_dependency_args, 19: appends_dependencies_args, 20: optional_dependencies_are_not_started_by_themselves, 21: optional_dependencies_add_arguments, 22: overrides_dependency_args, 23: merges_dependency_args, 24: replaces_modules, 25: reloads_modules_with_changed_args 26: ]. 27: 28: %% Fixtures 29: 30: init_per_testcase(_, C) -> 31: meck:new(gen_mod, [passthrough]), 32: meck:new(?MODS, [non_strict]), 33: meck:expect(gen_mod, start_module, fun(_, _, _) -> ok end), 34: meck:expect(gen_mod, stop_module, fun(_, _) -> ok end), 35: meck:expect(gen_mod, reload_module, fun(_, _, _) -> ok end), 36: meck:expect(gen_mod, get_deps, fun(Host, Mod, Opts) -> meck:passthrough([Host, Mod, Opts]) end), 37: C. 38: 39: end_per_testcase(_, C) -> 40: meck:unload(gen_mod), 41: meck:unload(?MODS), 42: C. 43: 44: %% Tests 45: 46: starts_modules(_Config) -> 47: gen_mod_deps:start_modules(<<"host">>, [{mod_a, []}, {mod_b, []}]), 48: check_started([mod_a, mod_b]). 49: 50: 51: starts_dependencies(_Config) -> 52: set_deps(#{mod_a => [{mod_b, hard}, {mod_c, hard}]}), 53: gen_mod_deps:start_modules(<<"host">>, [{mod_a, []}]), 54: check_started([mod_a, mod_b, mod_c]). 55: 56: 57: starts_dependency_chain(_Config) -> 58: set_deps(#{mod_a => [{mod_b, hard}], mod_b => [{mod_c, hard}]}), 59: gen_mod_deps:start_modules(<<"host">>, [{mod_a, []}]), 60: 61: check_started([mod_a, mod_b, mod_c]), 62: 63: StartOrder = [Mod || {_, {_, start_module, [_, Mod, _]}, _} <- meck:history(gen_mod)], 64: ?assertEqual([mod_c, mod_b, mod_a], StartOrder). 65: 66: 67: starts_dependency_dag(_Config) -> 68: set_deps(#{mod_a => [{mod_b, hard}, {mod_c, hard}], 69: mod_b => [{mod_c, hard}]}), 70: gen_mod_deps:start_modules(<<"host">>, [{mod_a, []}]), 71: check_started([mod_a, mod_b, mod_c]). 72: 73: 74: fails_on_dependency_cycle(_Config) -> 75: set_deps(#{mod_a => [{mod_b, hard}], 76: mod_b => [{mod_c, hard}], 77: mod_c => [{mod_a, hard}]}), 78: ?assertError(_, gen_mod_deps:start_modules(<<"host">>, [{mod_a, []}])). 79: 80: 81: succeeds_on_cycle_with_soft_dep_in_path(_Config) -> 82: set_deps(#{mod_a => [{mod_b, hard}], 83: mod_b => [{mod_c, soft}], 84: mod_c => [{mod_a, hard}]}), 85: gen_mod_deps:start_modules(<<"host">>, [{mod_a, []}]), 86: check_started([mod_a, mod_b, mod_c]). 87: 88: 89: succeeds_on_adding_soft_dependency_cycle_edge(_Config) -> 90: set_deps(#{mod_a => [{mod_b, hard}], mod_b => [{mod_a, soft}]}), 91: gen_mod_deps:start_modules(<<"host">>, [{mod_a, []}]), 92: check_started([mod_a, mod_b]). 93: 94: 95: forces_dependency_args(_Config) -> 96: set_deps(#{mod_a => [{mod_b, [arg1, arg2], hard}]}), 97: gen_mod_deps:start_modules(<<"host">>, [{mod_a, []}]), 98: check_started({mod_b, [arg1, arg2]}). 99: 100: 101: appends_dependencies_args(_Config) -> 102: set_deps(#{mod_a => [{mod_b, hard}, {mod_c, [arg1], hard}], 103: mod_b => [{mod_c, [arg2], hard}]}), 104: gen_mod_deps:start_modules(<<"host">>, [{mod_a, []}]), 105: check_started({mod_c, [arg1, arg2]}). 106: 107: 108: optional_dependencies_are_not_started_by_themselves(_Config) -> 109: set_deps(#{mod_a => [{mod_b, optional}]}), 110: gen_mod_deps:start_modules(<<"host">>, [{mod_a, []}]), 111: ?assertNot(started(mod_b)). 112: 113: 114: optional_dependencies_add_arguments(_Config) -> 115: set_deps(#{mod_a => [{mod_b, [arg1], optional}], mod_c => [{mod_b, hard}]}), 116: gen_mod_deps:start_modules(<<"host">>, [{mod_a, []}, {mod_c, []}]), 117: check_started({mod_b, [arg1]}). 118: 119: 120: overrides_dependency_args(_Config) -> 121: set_deps(#{mod_a => [{mod_b, hard}, {mod_c, [{arg, a}], hard}], 122: mod_b => [{mod_c, [{arg, b}], hard}]}), 123: gen_mod_deps:start_modules(<<"host">>, [{mod_a, []}]), 124: 125: ?assert(meck:called(gen_mod, start_module, ['_', mod_c, [{arg, a}]]) orelse 126: meck:called(gen_mod, start_module, ['_', mod_c, [{arg, b}]])). 127: 128: 129: merges_dependency_args(_Config) -> 130: set_deps(#{mod_a => [{mod_b, hard}, {mod_c, [{arg, a}], hard}], 131: mod_b => [{mod_c, [{arg, a}, arg2], hard}]}), 132: gen_mod_deps:start_modules(<<"host">>, [{mod_a, []}]), 133: 134: check_started({mod_c, [{arg, a}, arg2]}). 135: 136: 137: replaces_modules(_Config) -> 138: set_deps(#{mod_a => [{mod_b, hard}, {mod_c, hard}]}), 139: gen_mod_deps:start_modules(<<"host">>, [{mod_a, []}]), 140: 141: meck:reset(gen_mod), 142: 143: gen_mod_deps:replace_modules(<<"host">>, [{mod_a, []}], [{mod_d, []}, {mod_b, []}]), 144: 145: check_stopped(mod_a), 146: ?assertNot(meck:called(gen_mod, replace_module, '_')), 147: check_started(mod_d). 148: 149: 150: reloads_modules_with_changed_args(_Config) -> 151: set_deps(#{mod_a => [{mod_b, hard}]}), 152: gen_mod_deps:start_modules(<<"host">>, [{mod_a, []}]), 153: gen_mod_deps:replace_modules(<<"host">>, [{mod_a, []}], [{mod_b, [arg]}]), 154: check_reloaded({mod_b, [arg]}). 155: 156: %% Helpers 157: 158: set_deps(DepsMap) -> 159: maps:fold(fun(Mod, Deps, _) -> meck:expect(Mod, deps, fun(_, _) -> Deps end) end, 160: undefined, DepsMap). 161: 162: 163: check_started([]) -> ok; 164: check_started([ModNArgs | Mods]) -> 165: ?assert(started(ModNArgs)), 166: check_started(Mods); 167: check_started(Mod) -> 168: check_started([Mod]). 169: 170: started({Mod, Args}) -> 171: meck:called(gen_mod, start_module, ['_', Mod, Args]); 172: started(Mod) -> 173: meck:called(gen_mod, start_module, ['_', Mod, '_']). 174: 175: check_stopped([]) -> ok; 176: check_stopped([Mod | Mods]) -> 177: ?assert(meck:called(gen_mod, stop_module, ['_', Mod])), 178: check_stopped(Mods); 179: check_stopped(Mod) -> 180: check_stopped([Mod]). 181: 182: 183: check_reloaded([]) -> ok; 184: check_reloaded([{Mod, Args} | Mods]) -> 185: ?assert(meck:called(gen_mod, reload_module, ['_', Mod, Args])), 186: check_reloaded(Mods); 187: check_reloaded([Mod | Mods]) -> 188: ?assert(meck:called(gen_mod, reload_module, ['_', Mod, '_'])), 189: check_reloaded(Mods); 190: check_reloaded(Mod) -> 191: check_reloaded([Mod]).