1: -module(mongoose_service_SUITE). 2: 3: -compile([export_all, nowarn_export_all]). 4: 5: -include_lib("eunit/include/eunit.hrl"). 6: 7: all() -> 8: [starts_and_stops_services, 9: ensures_service, 10: reverts_config_when_service_fails_to_start, 11: does_not_change_config_when_service_fails_to_stop, 12: replaces_services, 13: replaces_services_with_new_deps, 14: replaces_services_with_old_deps, 15: replaces_services_with_same_deps]. 16: 17: init_per_suite(C) -> 18: C. 19: 20: end_per_suite(_C) -> 21: ok. 22: 23: init_per_testcase(_TC, C) -> 24: [mock_service(Service) || Service <- test_services()], 25: C. 26: 27: end_per_testcase(_, _C) -> 28: mongoose_config:erase_opts(), 29: meck:unload(test_services()). 30: 31: %% Test cases 32: 33: starts_and_stops_services(_Config) -> 34: set_services(Services = #{service_a => #{}, service_b => [{opt, val}]}), 35: ok = mongoose_service:start(), 36: check_started(maps:to_list(Services)), 37: 38: ok = mongoose_service:stop(), 39: check_stopped([service_a, service_b]). 40: 41: ensures_service(_Config) -> 42: set_services(#{}), 43: ?assertEqual({started, start_result}, mongoose_service:ensure_started(service_a, #{})), 44: ?assertEqual(#{service_a => #{}}, get_services()), 45: 46: ?assertEqual(already_started, mongoose_service:ensure_started(service_a, #{})), 47: ?assertEqual(#{service_a => #{}}, get_services()), 48: 49: ?assertEqual({restarted, #{}, start_result}, 50: mongoose_service:ensure_started(service_a, #{opt => val})), 51: ?assertEqual(#{service_a => #{opt => val}}, get_services()), 52: 53: ?assertEqual({stopped, #{opt => val}}, mongoose_service:ensure_stopped(service_a)), 54: ?assertEqual(#{}, get_services()), 55: 56: ?assertEqual(already_stopped, mongoose_service:ensure_stopped(service_a)), 57: ?assertEqual(#{}, get_services()). 58: 59: reverts_config_when_service_fails_to_start(_Config) -> 60: set_services(#{}), 61: meck:expect(service_a, start, fun(_) -> error(something_awful) end), 62: ?assertError(something_awful, mongoose_service:ensure_started(service_a, #{})), 63: ?assertEqual(#{}, get_services()). 64: 65: does_not_change_config_when_service_fails_to_stop(_Config) -> 66: set_services(#{service_a => #{}}), 67: meck:expect(service_a, stop, fun() -> error(something_awful) end), 68: ?assertError(something_awful, mongoose_service:ensure_stopped(service_a)), 69: ?assertEqual(#{service_a => #{}}, get_services()). 70: 71: replaces_services(_Config) -> 72: set_services(Services = #{service_a => #{}, service_b => #{opt => val}, service_c => #{}}), 73: ok = mongoose_service:start(), 74: check_started(maps:to_list(Services)), 75: 76: %% Stop service_a, change opts for service_b, do not change service_c, start service_d 77: NewServices = #{service_b => #{new_opt => new_val}, service_c => #{}, service_d => #{}}, 78: ok = mongoose_service:replace_services([service_a], NewServices), 79: check_stopped([service_a, service_b]), 80: check_not_stopped([service_c]), 81: check_started([{service_b, #{new_opt => new_val}}, {service_d, #{}}]), 82: ?assertEqual(NewServices, get_services()), 83: 84: ok = mongoose_service:stop(), 85: check_stopped([service_b, service_c, service_d]). 86: 87: replaces_services_with_new_deps(_Config) -> 88: set_deps(#{service_b => [service_c]}), 89: set_services(Services = #{service_a => #{}}), 90: ok = mongoose_service:start(), 91: check_started(maps:to_list(Services)), 92: 93: %% Start service_b, which depends on service_c 94: ok = mongoose_service:replace_services([], #{service_b => #{}}), 95: check_not_stopped([service_a]), 96: check_started([{service_b, #{}}, {service_c, #{}}]), 97: ?assertEqual(Services#{service_b => #{}, service_c => #{}}, get_services()), 98: 99: ok = mongoose_service:stop(), 100: check_stopped([service_a, service_b, service_c]). 101: 102: replaces_services_with_old_deps(_Config) -> 103: set_deps(#{service_a => [service_c]}), 104: set_services(Services = #{service_a => #{}, service_c => #{}}), 105: ok = mongoose_service:start(), 106: check_started(maps:to_list(Services)), 107: 108: %% Stop service_a, which depends on service_c, and start service_b 109: ok = mongoose_service:replace_services([service_a], #{service_b => #{}}), 110: check_stopped([service_a, service_c]), 111: check_started([{service_b, #{}}]), 112: ?assertEqual(#{service_b => #{}}, get_services()), 113: 114: ok = mongoose_service:stop(), 115: check_stopped([service_b]). 116: 117: replaces_services_with_same_deps(_Config) -> 118: set_deps(#{service_a => [service_c], service_b => [service_c]}), 119: set_services(Services = #{service_a => #{}, service_c => #{}}), 120: ok = mongoose_service:start(), 121: check_started(maps:to_list(Services)), 122: 123: %% Stop service_a, and start service_b, both depending on service_c 124: ok = mongoose_service:replace_services([service_a], #{service_b => #{}}), 125: check_stopped([service_a]), 126: check_not_stopped([service_c]), 127: check_started([{service_b, #{}}]), 128: ?assertEqual(#{service_b => #{}, service_c => #{}}, get_services()), 129: 130: ok = mongoose_service:stop(), 131: check_stopped([service_b]). 132: 133: %% Helpers 134: 135: set_services(Services) -> 136: mongoose_config:set_opts(#{services => Services}). 137: 138: get_services() -> 139: mongoose_config:get_opt(services). 140: 141: check_started(ServicesWithOpts) -> 142: lists:foreach(fun({Service, Opts}) -> 143: ?assert(meck:called(Service, start, [Opts])) 144: end, ServicesWithOpts). 145: 146: check_stopped(Services) -> 147: lists:foreach(fun(Service) -> 148: ?assert(meck:called(Service, stop, [])) 149: end, Services). 150: 151: check_not_stopped(Services) -> 152: lists:foreach(fun(Service) -> 153: ?assertNot(meck:called(Service, stop, [])) 154: end, Services). 155: 156: mock_service(Service) -> 157: meck:new(Service, [non_strict]), 158: meck:expect(Service, start, fun(_) -> start_result end), 159: meck:expect(Service, stop, fun() -> ok end). 160: 161: set_deps(DepsMap) -> 162: maps:fold(fun(Service, Deps, _) -> meck:expect(Service, deps, fun() -> Deps end) end, 163: undefined, DepsMap). 164: 165: test_services() -> 166: [service_a, service_b, service_c, service_d].