./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 73 [gen_mod:start_module(HostType, Mod, Opts) || HostType <- ?ALL_HOST_TYPES,
20 382 {Mod, Opts} <- sorted_modules(HostType)],
21 73 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 73 [gen_mod:stop_module(HostType, Mod) || HostType <- ?ALL_HOST_TYPES,
28 382 {Mod, _} <- lists:reverse(sorted_modules(HostType))],
29 73 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 707 Current = get_modules(HostType),
38 707 Old = maps:with(ToStop ++ maps:keys(ToEnsure), Current),
39 707 OldWithDeps = gen_mod_deps:resolve_deps(HostType, Old),
40 707 SortedOldWithDeps = gen_mod_deps:sort_deps(HostType, OldWithDeps),
41 707 WithoutOld = maps:without(maps:keys(OldWithDeps), Current),
42 707 WithNew = maps:merge(WithoutOld, ToEnsure),
43 707 Target = gen_mod_deps:resolve_deps(HostType, WithNew),
44
45 %% Stop each affected module if it is not in Target (stop deps first)
46 707 [ensure_stopped(HostType, Module) || {Module, _} <- lists:reverse(SortedOldWithDeps),
47 2918 not maps:is_key(Module, Target)],
48
49 %% Ensure each module from Target
50 707 [ensure_started(HostType, Module, Opts) ||
51 707 {Module, Opts} <- gen_mod_deps:sort_deps(HostType, Target)],
52 707 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 1152 Modules = get_modules(HostType),
59 1152 case maps:find(Module, Modules) of
60 error ->
61 609 already_stopped;
62 {_, Opts} ->
63 543 stop_module(HostType, Module, Modules),
64 543 {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 13462 Opts = proplists:unfold(RawOpts),
72 13462 Modules = get_modules(HostType),
73 13462 case maps:find(Module, Modules) of
74 error ->
75 543 {ok, Result} = start_module(HostType, Module, Opts, Modules),
76 543 {started, Result};
77 {_, Opts} ->
78 12723 already_started;
79 {_, PrevOpts} ->
80 196 stop_module(HostType, Module, Modules),
81 196 {ok, Result} = start_module(HostType, Module, Opts, Modules),
82 196 {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 739 set_modules(HostType, Modules#{Module => Opts}),
90 739 try
91 739 gen_mod:start_module(HostType, Module, Opts)
92 catch
93 C:R:S ->
94
:-(
set_modules(HostType, Modules),
95
:-(
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 739 gen_mod:stop_module(HostType, Module),
101 739 set_modules(HostType, maps:remove(Module, Modules)).
102
103 -spec sorted_modules(mongooseim:host_type()) -> module_list().
104 sorted_modules(HostType) ->
105 764 gen_mod_deps:sort_deps(HostType, get_modules(HostType)).
106
107 -spec get_modules(mongooseim:host_type()) -> module_map().
108 get_modules(HostType) ->
109 16085 mongoose_config:get_opt({modules, HostType}).
110
111 -spec set_modules(mongooseim:host_type(), module_map()) -> ok.
112 set_modules(HostType, Modules) ->
113 1478 mongoose_config:set_opt({modules, HostType}, Modules).
Line Hits Source