Skip to content

Commit 97a3905

Browse files
committed
Merge pull request #579 from basho/adt-per-test-coverage
Allow cover_modules and cover_apps to be per test module
2 parents 79a0434 + 334dc40 commit 97a3905

File tree

3 files changed

+58
-30
lines changed

3 files changed

+58
-30
lines changed

README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,14 +171,19 @@ You can generate a coverage report for a test run through [Erlang Cover](http://
171171
Coverage information for all **current** code run on any Riak node started by any of the tests in the run will be output as HTML in the coverage directory.
172172
That is, legacy and previous nodes used in the test will not be included, as the tool can only work on one version of the code at a time.
173173
Also, cover starts running in the Riak nodes after the node is up, so it will not report coverage of application initialization or other early code paths.
174-
You can specify a list of modules for which you want coverage generated like this:
174+
Each test module, via a module attribute, can specify what modules it wishes to cover compile:
175175
```erlang
176-
{cover_modules, [riak_kv_bitcask_backend, riak_core_ring]}
176+
-cover_modules([riak_kv_bitcask_backend, riak_core_ring]).
177177
```
178178
Or entire applications by using:
179179
```erlang
180-
{cover_apps, [riak_kv, riak_core]}
180+
-cover_apps([riak_kv, riak_core]).
181181
```
182+
To enable this, you need to turn coverage in in your riak_test.config:
183+
```erlang
184+
{cover_enabled, true}
185+
```
186+
Tests that do not include coverage annotations will, if cover is enabled, honor {cover_modules, [..]} and {cover_apps, [..]} from the riak_test config file.
182187

183188
#### Web hooks
184189
When reporting is enabled, each test result is posted to [Giddy Up](http://giddyup.basho.com). You can specify

src/riak_test_escript.erl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,6 @@ main(Args) ->
173173
[] = os:cmd("epmd -daemon"),
174174
net_kernel:start([ENode]),
175175
erlang:set_cookie(node(), Cookie),
176-
rt_cover:maybe_start(),
177176

178177
TestResults = lists:filter(fun results_filter/1, [ run_test(Test, Outdir, TestMetaData, Report, HarnessArgs, length(Tests)) || {Test, TestMetaData} <- Tests]),
179178
[rt_cover:maybe_import_coverage(proplists:get_value(coverdata, R)) || R <- TestResults],
@@ -287,7 +286,7 @@ is_runnable_test({TestModule, _}) ->
287286
erlang:function_exported(Mod, Fun, 0).
288287

289288
run_test(Test, Outdir, TestMetaData, Report, _HarnessArgs, NumTests) ->
290-
rt_cover:maybe_reset(),
289+
rt_cover:maybe_start(Test),
291290
SingleTestResult = riak_test_runner:confirm(Test, Outdir, TestMetaData),
292291
CoverDir = rt_config:get(cover_output, "coverage"),
293292
case NumTests of
@@ -311,6 +310,7 @@ run_test(Test, Outdir, TestMetaData, Report, _HarnessArgs, NumTests) ->
311310
[ rt:post_result(ResultPlusGiddyUp, WebHook) || WebHook <- get_webhooks() ]
312311
end
313312
end,
313+
rt_cover:stop(),
314314
[{coverdata, CoverageFile} | SingleTestResult].
315315

316316
get_webhooks() ->

src/rt_cover.erl

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626
%% Here we do it as html files for easy browsing.
2727
-module(rt_cover).
2828
-export([
29-
maybe_start/0,
30-
start/0,
29+
maybe_start/1,
30+
start/1,
3131
maybe_start_on_node/2,
3232
maybe_write_coverage/2,
3333
maybe_export_coverage/3,
@@ -47,27 +47,41 @@
4747
output_file :: undefined | string()}).
4848

4949
if_coverage(Fun) ->
50-
case rt_config:get(cover_enabled, true) of
50+
case rt_config:get(cover_enabled, false) of
5151
false ->
5252
cover_disabled;
5353
true ->
5454
Fun()
5555
end.
5656

57-
maybe_start() ->
58-
if_coverage(fun start/0).
57+
maybe_start(Test) ->
58+
if_coverage(fun() -> start(Test) end).
5959

6060
mod_src(Mod) ->
61-
proplists:get_value(source, Mod:module_info(compile), Mod).
61+
try Mod:module_info(compile) of
62+
CompileInfo ->
63+
Src = proplists:get_value(source, CompileInfo, Mod),
64+
case filelib:is_regular(Src) of
65+
true -> Src;
66+
false -> undefined
67+
end
68+
catch
69+
_:_ -> undefined
70+
end.
6271

63-
start() ->
64-
start(find_cover_modules()).
72+
has_src(Mod) ->
73+
case mod_src(Mod) of
74+
undefined -> false;
75+
_ -> true
76+
end.
6577

66-
start([]) ->
78+
start(Test) ->
79+
start2(find_cover_modules(Test)).
80+
81+
start2([]) ->
6782
lager:info("Skipping cover, no modules included"),
68-
rt_config:set(cover_enabled, false),
6983
ok;
70-
start(CoverMods) ->
84+
start2(CoverMods) ->
7185
lager:info("Starting cover"),
7286
stop_on_nodes(),
7387
ok = cover:stop(),
@@ -90,7 +104,7 @@ start(CoverMods) ->
90104
[Mod, CErr]),
91105
{error, CErr}
92106
end
93-
end || Mod <- CoverMods],
107+
end || Mod <- CoverMods, has_src(Mod)],
94108
SrcDict = dict:from_list([ModSrc || {ok, ModSrc} <- CMods]),
95109
rt_config:set(cover_mod_src, SrcDict),
96110
ok;
@@ -101,15 +115,29 @@ start(CoverMods) ->
101115
end.
102116

103117
%% @doc Figure out which modules to include.
104-
%% You can use a list of specific modules in the application
105-
%% variable `cover_modules', or application names in `cover_apps',
106-
%% which may be the special token `all'.
107-
find_cover_modules() ->
118+
%% These are read, per test, from the test module attributes
119+
%% `cover_modules' or `cover_apps'.
120+
find_cover_modules(Test) ->
121+
{Mod, _Fun} = riak_test_runner:function_name(Test),
122+
case proplists:get_value(cover_modules, Mod:module_info(attributes), []) of
123+
[] ->
124+
case proplists:get_value(cover_apps, Mod:module_info(attributes), []) of
125+
[] ->
126+
%% fallback to what is in the config file
127+
read_cover_modules_from_config();
128+
Apps ->
129+
AppMods = find_app_modules(Apps),
130+
AppMods
131+
end;
132+
ConfMods ->
133+
ConfMods
134+
end.
135+
136+
read_cover_modules_from_config() ->
108137
case rt_config:get(cover_modules, []) of
109138
[] ->
110139
Apps = rt_config:get(cover_apps, []),
111140
AppMods = find_app_modules(Apps),
112-
rt_config:set(cover_modules, AppMods),
113141
AppMods;
114142
ConfMods ->
115143
ConfMods
@@ -153,7 +181,7 @@ maybe_start_on_node(Node, Version) ->
153181
_ -> false
154182
end,
155183
ShouldStart = IsCurrent andalso
156-
rt_config:get(cover_enabled, true) andalso
184+
cover:modules() /= [] andalso
157185
erlang:whereis(?COVER_SERVER) /= undefined,
158186
case ShouldStart of
159187
false ->
@@ -291,8 +319,9 @@ process_module(Mod, OutDir) ->
291319
#cover_info{module=Mod, output_file=OutFile, coverage=Coverage}.
292320

293321
write_coverage(all, Dir) ->
294-
write_coverage(rt_config:get(cover_modules, []), Dir);
322+
write_coverage(cover:imported_modules(), Dir);
295323
write_coverage(CoverModules, CoverDir) ->
324+
lager:info("analyzing modules ~p", [CoverModules]),
296325
% temporarily reassign the group leader, to suppress annoying io:format output
297326
{group_leader, GL} = erlang:process_info(whereis(cover_server), group_leader),
298327
%% tiny recursive fun that pretends to be a group leader$
@@ -383,19 +412,13 @@ write_module_coverage(CoverMod, CoverDir) ->
383412
{ok, Src} ->
384413
case filelib:is_regular(Src) andalso filename:extension(Src) == ".erl" of
385414
true ->
386-
% Cover only finds source if alongside beam or in ../src from beam
387-
% so had to temporarily copy source next to each beam.
388-
{file, BeamFile} = cover:is_compiled(CoverMod),
389-
TmpSrc = filename:rootname(BeamFile) ++ ".erl",
390-
file:copy(Src, TmpSrc),
391415
case cover:analyse_to_file(CoverMod, CoverFile, [html]) of
392416
{ok, _Mod} -> ok;
393417
{error, Err} ->
394418
lager:warning("Failed to write coverage analysis" ++
395419
" for module ~p (source ~s): ~p",
396420
[CoverMod, Src, Err])
397421
end,
398-
file:delete(TmpSrc),
399422
{ok, CoverFile};
400423
false ->
401424
lager:warning("Source for module ~p is not an erl file : ~s",

0 commit comments

Comments
 (0)