./ct_report/coverage/mongoose_modules.COVER.html

1 -module(mongoose_modules).
2
3 -include("mongoose.hrl").
4
5 %% API
6 -export([start/0, stop/0, unfold_opts/1]).
7
8 %% Module management utilities for tests
9 -export([replace_modules/3, ensure_stopped/2, ensure_started/3]).
10 -ignore_xref([replace_modules/3, ensure_stopped/2, ensure_started/3]).
11
12 -type module_opts() :: gen_mod:module_opts().
13 -type module_map() :: gen_mod_deps:module_map().
14 -type module_list() :: gen_mod_deps:module_list().
15
16 %% @doc Start all configured modules in the dependency order.
17 -spec start() -> 'ok'.
18 start() ->
19 82 [gen_mod:start_module(HostType, Mod, Opts) || HostType <- ?ALL_HOST_TYPES,
20 421 {Mod, Opts} <- sorted_modules(HostType)],
21 82 ok.
22
23 %% @doc Stop all configured modules in the reverse dependency order
24 %% to avoid stopping modules which have other modules dependent on them.
25 -spec stop() -> 'ok'.
26 stop() ->
27 82 [gen_mod:stop_module(HostType, Mod) || HostType <- ?ALL_HOST_TYPES,
28 421 {Mod, _} <- lists:reverse(sorted_modules(HostType))],
29 82 ok.
30
31 %% @doc Replace modules at runtime - only for testing and debugging.
32 %% Running modules from ToStop are stopped and modules from ToEnsure are (re)started when needed.
33 %% Unused dependencies are stopped if no running modules depend on them anymore.
34 %% To prevent an unused dependency from being stopped, you need to include it in ToEnsure.
35 -spec replace_modules(mongooseim:host_type(), [module()], module_map()) -> ok.
36 replace_modules(HostType, ToStop, ToEnsure) ->
37 365 Current = get_modules(HostType),
38 365 Old = maps:with(ToStop ++ maps:keys(ToEnsure), Current),
39 365 OldWithDeps = gen_mod_deps:resolve_deps(HostType, Old),
40 365 SortedOldWithDeps = gen_mod_deps:sort_deps(HostType, OldWithDeps),
41 365 WithoutOld = maps:without(maps:keys(OldWithDeps), Current),
42 365 WithNew = maps:merge(WithoutOld, ToEnsure),
43 365 Target = gen_mod_deps:resolve_deps(HostType, WithNew),
44
45 %% Stop each affected module if it is not in Target (stop deps first)
46 365 [ensure_stopped(HostType, Module) || {Module, _} <- lists:reverse(SortedOldWithDeps),
47 2418 not maps:is_key(Module, Target)],
48
49 %% Ensure each module from Target
50 365 [ensure_started(HostType, Module, Opts) ||
51 365 {Module, Opts} <- gen_mod_deps:sort_deps(HostType, Target)],
52 364 ok.
53
54 %% @doc Make sure the module is stopped.
55 -spec ensure_stopped(mongooseim:host_type(), module()) ->
56 already_stopped | {stopped, module_opts()}.
57 ensure_stopped(HostType, Module) ->
58 583 Modules = get_modules(HostType),
59 583 case maps:find(Module, Modules) of
60 error ->
61 144 already_stopped;
62 {_, Opts} ->
63 439 stop_module(HostType, Module, Modules),
64 439 {stopped, Opts}
65 end.
66
67 %% @doc Make sure the module is running with the provided options.
68 -spec ensure_started(mongooseim:host_type(), module(), module_opts()) ->
69 already_started | {started, term()} | {restarted, module_opts(), term()}.
70 ensure_started(HostType, Module, RawOpts) ->
71 5642 Opts = unfold_opts(RawOpts),
72 5642 Modules = get_modules(HostType),
73 5642 case maps:find(Module, Modules) of
74 error ->
75 446 {ok, Result} = start_module(HostType, Module, Opts, Modules),
76 445 {started, Result};
77 {_, Opts} ->
78 5111 already_started;
79 {_, PrevOpts} ->
80 85 stop_module(HostType, Module, Modules),
81 85 {ok, Result} = start_module(HostType, Module, Opts, Modules),
82 85 {restarted, PrevOpts, Result}
83 end.
84
85 -spec unfold_opts(gen_mod:module_opts()) -> gen_mod:module_opts().
86 5646 unfold_opts(Opts) when is_map(Opts) -> Opts;
87 4046 unfold_opts(Opts) -> proplists:unfold(Opts).
88
89 %% Helpers
90
91 -spec start_module(mongooseim:host_type(), module(), module_opts(), module_map()) -> {ok, term()}.
92 start_module(HostType, Module, Opts, Modules) ->
93 531 set_modules(HostType, Modules#{Module => Opts}),
94 531 try
95 531 gen_mod:start_module(HostType, Module, Opts)
96 catch
97 C:R:S ->
98 1 set_modules(HostType, Modules),
99 1 erlang:raise(C, R, S)
100 end.
101
102 -spec stop_module(mongooseim:host_type(), module(), module_map()) -> ok.
103 stop_module(HostType, Module, Modules) ->
104 524 gen_mod:stop_module(HostType, Module),
105 524 set_modules(HostType, maps:remove(Module, Modules)).
106
107 -spec sorted_modules(mongooseim:host_type()) -> module_list().
108 sorted_modules(HostType) ->
109 842 gen_mod_deps:sort_deps(HostType, get_modules(HostType)).
110
111 -spec get_modules(mongooseim:host_type()) -> module_map().
112 get_modules(HostType) ->
113 7432 mongoose_config:get_opt({modules, HostType}).
114
115 -spec set_modules(mongooseim:host_type(), module_map()) -> ok.
116 set_modules(HostType, Modules) ->
117 1056 mongoose_config:set_opt({modules, HostType}, Modules).
Line Hits Source