./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]).
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() :: #{module() => gen_mod:module_opts()}.
14 -type module_list() :: [{module(), gen_mod:module_opts()}].
15
16 %% @doc Start all configured modules in the dependency order.
17 -spec start() -> 'ok'.
18 start() ->
19 80 [gen_mod:start_module(HostType, Mod, Opts) || HostType <- ?ALL_HOST_TYPES,
20 409 {Mod, Opts} <- sorted_modules(HostType)],
21 80 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 80 [gen_mod:stop_module(HostType, Mod) || HostType <- ?ALL_HOST_TYPES,
28 409 {Mod, _} <- lists:reverse(sorted_modules(HostType))],
29 80 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 358 Current = get_modules(HostType),
38 358 Old = maps:with(ToStop ++ maps:keys(ToEnsure), Current),
39 358 OldWithDeps = gen_mod_deps:resolve_deps(HostType, Old),
40 358 SortedOldWithDeps = gen_mod_deps:sort_deps(HostType, OldWithDeps),
41 358 WithoutOld = maps:without(maps:keys(OldWithDeps), Current),
42 358 WithNew = maps:merge(WithoutOld, ToEnsure),
43 358 Target = gen_mod_deps:resolve_deps(HostType, WithNew),
44
45 %% Stop each affected module if it is not in Target (stop deps first)
46 358 [ensure_stopped(HostType, Module) || {Module, _} <- lists:reverse(SortedOldWithDeps),
47 2310 not maps:is_key(Module, Target)],
48
49 %% Ensure each module from Target
50 358 [ensure_started(HostType, Module, Opts) ||
51 358 {Module, Opts} <- gen_mod_deps:sort_deps(HostType, Target)],
52 358 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 590 Modules = get_modules(HostType),
59 590 case maps:find(Module, Modules) of
60 error ->
61 146 already_stopped;
62 {_, Opts} ->
63 444 stop_module(HostType, Module, Modules),
64 444 {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 5562 Opts = proplists:unfold(RawOpts),
72 5562 Modules = get_modules(HostType),
73 5562 case maps:find(Module, Modules) of
74 error ->
75 451 {ok, Result} = start_module(HostType, Module, Opts, Modules),
76 450 {started, Result};
77 {_, Opts} ->
78 5024 already_started;
79 {_, PrevOpts} ->
80 87 stop_module(HostType, Module, Modules),
81 87 {ok, Result} = start_module(HostType, Module, Opts, Modules),
82 87 {restarted, PrevOpts, Result}
83 end.
84
85 %% Helpers
86
87 -spec start_module(mongooseim:host_type(), module(), module_opts(), module_map()) -> {ok, term()}.
88 start_module(HostType, Module, Opts, Modules) ->
89 538 set_modules(HostType, Modules#{Module => Opts}),
90 538 try
91 538 gen_mod:start_module(HostType, Module, Opts)
92 catch
93 C:R:S ->
94 1 set_modules(HostType, Modules),
95 1 erlang:raise(C, R, S)
96 end.
97
98 -spec stop_module(mongooseim:host_type(), module(), module_map()) -> ok.
99 stop_module(HostType, Module, Modules) ->
100 531 gen_mod:stop_module(HostType, Module),
101 531 set_modules(HostType, maps:remove(Module, Modules)).
102
103 -spec sorted_modules(mongooseim:host_type()) -> module_list().
104 sorted_modules(HostType) ->
105 818 gen_mod_deps:sort_deps(HostType, get_modules(HostType)).
106
107 -spec get_modules(mongooseim:host_type()) -> module_map().
108 get_modules(HostType) ->
109 7328 mongoose_config:get_opt({modules, HostType}).
110
111 -spec set_modules(mongooseim:host_type(), module_map()) -> ok.
112 set_modules(HostType, Modules) ->
113 1070 mongoose_config:set_opt({modules, HostType}, Modules).
Line Hits Source