mirror of
https://github.com/valitydev/riak_test.git
synced 2024-11-06 00:25:22 +00:00
Add a simple 'smoke test' tool to run eunit/dialyzer on riak source trees
This commit is contained in:
parent
d983476f59
commit
1ec8bda21c
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,6 +2,7 @@ deps
|
|||||||
ebin
|
ebin
|
||||||
log
|
log
|
||||||
riak_test
|
riak_test
|
||||||
|
smoke_test
|
||||||
.eunit
|
.eunit
|
||||||
.DS_Store
|
.DS_Store
|
||||||
out
|
out
|
||||||
|
1
Makefile
1
Makefile
@ -7,6 +7,7 @@ PLT = $(HOME)/.riak-test_dialyzer_plt
|
|||||||
|
|
||||||
all: deps compile
|
all: deps compile
|
||||||
./rebar skip_deps=true escriptize
|
./rebar skip_deps=true escriptize
|
||||||
|
SMOKE_TEST=1 ./rebar skip_deps=true escriptize
|
||||||
|
|
||||||
deps:
|
deps:
|
||||||
./rebar get-deps
|
./rebar get-deps
|
||||||
|
8
rebar.config.script
Normal file
8
rebar.config.script
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
case os:getenv("SMOKE_TEST") of
|
||||||
|
false -> CONFIG;
|
||||||
|
[] -> CONFIG;
|
||||||
|
_ ->
|
||||||
|
C1 = lists:keystore(escript_emu_args, 1, CONFIG,
|
||||||
|
{escript_emu_args, "%%! -escript main smoke_test_escript +K true +P 10000 -env ERL_MAX_PORTS 10000\n"}),
|
||||||
|
lists:keystore(escript_name, 1, C1, {escript_name, smoke_test})
|
||||||
|
end.
|
214
src/smoke_test_escript.erl
Executable file
214
src/smoke_test_escript.erl
Executable file
@ -0,0 +1,214 @@
|
|||||||
|
-module(smoke_test_escript).
|
||||||
|
-include_lib("kernel/include/file.hrl").
|
||||||
|
|
||||||
|
-export([main/1, get_version/0, worker/3]).
|
||||||
|
|
||||||
|
get_version() ->
|
||||||
|
list_to_binary(string:strip(os:cmd("git describe"), right, $\n)).
|
||||||
|
|
||||||
|
cli_options() ->
|
||||||
|
%% Option Name, Short Code, Long Code, Argument Spec, Help Message
|
||||||
|
[
|
||||||
|
{project, $p, "project", string, "specifices which project"},
|
||||||
|
{debug, $v, "debug", undefined, "debug?"},
|
||||||
|
{directory, $d, "directory", string, "source tree directory"},
|
||||||
|
{jobs, $j, "jobs", integer, "jobs?"}
|
||||||
|
].
|
||||||
|
|
||||||
|
|
||||||
|
main(Args) ->
|
||||||
|
{ok, {Parsed, _Other}} = getopt:parse(cli_options(), Args),
|
||||||
|
application:start(ibrowse),
|
||||||
|
lager:start(),
|
||||||
|
rt_config:load("default", filename:join([os:getenv("HOME"), ".smoke_test.config"])),
|
||||||
|
case lists:keyfind(project, 1, Parsed) of
|
||||||
|
false ->
|
||||||
|
lager:error("Must specify project!"),
|
||||||
|
application:stop(lager),
|
||||||
|
halt(1);
|
||||||
|
{project, Project} ->
|
||||||
|
rt_config:set(rt_project, Project)
|
||||||
|
end,
|
||||||
|
case lists:keyfind(directory, 1, Parsed) of
|
||||||
|
false ->
|
||||||
|
%% run in current working directory
|
||||||
|
ok;
|
||||||
|
{directory, Dir} ->
|
||||||
|
lager:info("Changing working dir to ~s", [Dir]),
|
||||||
|
ok = file:set_cwd(filename:absname(Dir))
|
||||||
|
end,
|
||||||
|
case lists:member(debug, Parsed) of
|
||||||
|
true ->
|
||||||
|
lager:set_loglevel(lager_console_backend, debug);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
rt_config:set(rt_harness, ?MODULE),
|
||||||
|
lager:debug("ParsedArgs ~p", [Parsed]),
|
||||||
|
Suites = giddyup:get_suite(rt_config:get(platform)),
|
||||||
|
Jobs = case lists:keyfind(jobs, 1, Parsed) of
|
||||||
|
false ->
|
||||||
|
1;
|
||||||
|
{jobs, J} ->
|
||||||
|
J
|
||||||
|
end,
|
||||||
|
|
||||||
|
{ok, PWD} = file:get_cwd(),
|
||||||
|
Rebar = filename:join(PWD, "rebar"),
|
||||||
|
|
||||||
|
|
||||||
|
setup_deps(Rebar, PWD, [filename:join([PWD, "deps", F])
|
||||||
|
|| F <- element(2, file:list_dir(filename:join(PWD, "deps"))),
|
||||||
|
filelib:is_dir(filename:join([PWD, "deps", F]))]),
|
||||||
|
|
||||||
|
case Jobs > 1 of
|
||||||
|
true ->
|
||||||
|
%% partiton the suite list by the number of jobs
|
||||||
|
SplitSuites = dict:to_list(element(2, lists:foldl(fun(S, {Counter, Dict}) ->
|
||||||
|
{Counter + 1, dict:append(Counter rem Jobs, S, Dict)}
|
||||||
|
end, {0, dict:new()}, Suites))),
|
||||||
|
lager:debug("Split into ~p lists", [length(SplitSuites)]),
|
||||||
|
Workers = [spawn_monitor(?MODULE, worker, [Rebar, PWD, SS]) || {_, SS} <- SplitSuites],
|
||||||
|
wait_for_workers(Workers);
|
||||||
|
_ ->
|
||||||
|
worker(Rebar, PWD, Suites)
|
||||||
|
end.
|
||||||
|
|
||||||
|
worker(Rebar, PWD, Suites) ->
|
||||||
|
lists:foreach(fun({Suite, Config}) ->
|
||||||
|
lager:info("Suite ~p config ~p", [Suite, Config]),
|
||||||
|
[Dep, Task] = string:tokens(atom_to_list(Suite), ":"),
|
||||||
|
FDep = filename:join([PWD, deps, Dep]),
|
||||||
|
case filelib:is_dir(FDep) of
|
||||||
|
true ->
|
||||||
|
case Task of
|
||||||
|
"eunit" ->
|
||||||
|
%% set up a symlink so that each dep has deps
|
||||||
|
P = erlang:open_port({spawn_executable, Rebar},
|
||||||
|
[{args, ["eunit", "skip_deps=true"]},
|
||||||
|
{cd, FDep}, exit_status,
|
||||||
|
{line, 1024}, stderr_to_stdout, binary]),
|
||||||
|
{Res, Log} = accumulate(P, []),
|
||||||
|
CleanedLog = cleanup_logs(Log),
|
||||||
|
giddyup:post_result([{test, Suite}, {status, get_status(Res)},
|
||||||
|
{log, CleanedLog} | Config]),
|
||||||
|
Res;
|
||||||
|
"dialyzer" ->
|
||||||
|
P = erlang:open_port({spawn_executable, "/usr/bin/make"},
|
||||||
|
[{args, ["dialyzer"]},
|
||||||
|
{cd, FDep}, exit_status,
|
||||||
|
{line, 1024}, stderr_to_stdout, binary]),
|
||||||
|
{Res, Log} = accumulate(P, []),
|
||||||
|
%% TODO split the logs so that the PLT stuff is elided
|
||||||
|
CleanedLog = cleanup_logs(Log),
|
||||||
|
giddyup:post_result([{test, Suite}, {status, get_status(Res)},
|
||||||
|
{log, CleanedLog} | Config]),
|
||||||
|
Res;
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
|
||||||
|
end;
|
||||||
|
false ->
|
||||||
|
lager:debug("Not a dep: ~p", [FDep])
|
||||||
|
end
|
||||||
|
end, Suites).
|
||||||
|
|
||||||
|
setup_deps(_, _, []) -> ok;
|
||||||
|
setup_deps(Rebar, PWD, [Dep|Deps]) ->
|
||||||
|
%% clean up an old deps dir, if present
|
||||||
|
remove_deps_dir(Dep),
|
||||||
|
%% symlink ALL the deps in
|
||||||
|
file:make_symlink(filename:join(PWD, "deps"), filename:join(Dep, "deps")),
|
||||||
|
lager:debug("ln -sf ~s ~s", [filename:join(PWD, "deps"),
|
||||||
|
filename:join(Dep, "deps")]),
|
||||||
|
%% run rebar list deps, to find out which ones to keep
|
||||||
|
P = erlang:open_port({spawn_executable, Rebar},
|
||||||
|
[{args, ["list-deps"]},
|
||||||
|
{cd, Dep}, exit_status,
|
||||||
|
{line, 1024}, stderr_to_stdout, binary]),
|
||||||
|
{0, Log} = accumulate(P, []),
|
||||||
|
%% find all the deps, amongst the noise
|
||||||
|
case re:run(Log, "([a-zA-Z0-9_]+) (?:BRANCH|TAG|REV)",
|
||||||
|
[global, {capture, all_but_first, list}]) of
|
||||||
|
{match, Matches} ->
|
||||||
|
lager:info("Deps for ~p are ~p", [Dep, Matches]),
|
||||||
|
ok = file:delete(filename:join(Dep, "deps")),
|
||||||
|
ok = filelib:ensure_dir(filename:join(Dep, "deps")++"/"),
|
||||||
|
[file:make_symlink(filename:join([PWD, "deps", M]),
|
||||||
|
filename:join([Dep, "deps", M]))
|
||||||
|
|| M <- Matches];
|
||||||
|
nomatch ->
|
||||||
|
%% remove the symlink
|
||||||
|
file:delete(filename:join(Dep, "deps")),
|
||||||
|
lager:info("~p has no deps", [Dep])
|
||||||
|
end,
|
||||||
|
setup_deps(Rebar, PWD, Deps).
|
||||||
|
|
||||||
|
remove_deps_dir(Dep) ->
|
||||||
|
case filelib:is_dir(filename:join(Dep, "deps")) of
|
||||||
|
true ->
|
||||||
|
%% there should ONLY be a deps dir leftover from a previous run,
|
||||||
|
%% so it should be a directory filled with symlinks
|
||||||
|
{ok, Files} = file:list_dir(filename:join(Dep, "deps")),
|
||||||
|
lists:foreach(fun(F) ->
|
||||||
|
File = filename:join([Dep, "deps", F]),
|
||||||
|
{ok, FI} = file:read_link_info(File),
|
||||||
|
case FI#file_info.type of
|
||||||
|
symlink ->
|
||||||
|
ok = file:delete(File);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end
|
||||||
|
end, Files),
|
||||||
|
%% this will fail if the directory is not now empty
|
||||||
|
ok = file:del_dir(filename:join(Dep, "deps")),
|
||||||
|
ok;
|
||||||
|
false ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
|
wait_for_workers([]) ->
|
||||||
|
ok;
|
||||||
|
wait_for_workers(Workers) ->
|
||||||
|
receive
|
||||||
|
{'DOWN', _, _, Pid, normal} ->
|
||||||
|
lager:info("Worker exited normally"),
|
||||||
|
wait_for_workers(Workers -- [Pid]);
|
||||||
|
{'DOWN', _, _, Pid, Reason} ->
|
||||||
|
lager:info("Worker exited abnormally: ~p", [Reason]),
|
||||||
|
wait_for_workers(Workers -- [Pid])
|
||||||
|
end.
|
||||||
|
|
||||||
|
cleanup_logs(Logs) ->
|
||||||
|
case unicode:characters_to_binary(Logs, latin1, unicode) of
|
||||||
|
{error, Bin, Rest} ->
|
||||||
|
lager:error("Bad binary ~p", [Rest]),
|
||||||
|
Bin;
|
||||||
|
{incomplete, Bin, Rest} ->
|
||||||
|
lager:error("Bad binary ~p", [Rest]),
|
||||||
|
Bin;
|
||||||
|
Bin ->
|
||||||
|
Bin
|
||||||
|
end.
|
||||||
|
|
||||||
|
maybe_eol(eol) ->
|
||||||
|
"\n";
|
||||||
|
maybe_eol(noeol) ->
|
||||||
|
"".
|
||||||
|
|
||||||
|
get_status(0) ->
|
||||||
|
pass;
|
||||||
|
get_status(_) ->
|
||||||
|
fail.
|
||||||
|
|
||||||
|
accumulate(P, Acc) ->
|
||||||
|
receive
|
||||||
|
{P, {data, {EOL, Data}}} ->
|
||||||
|
accumulate(P, [[Data,maybe_eol(EOL)]|Acc]);
|
||||||
|
{P, {exit_status, Status}} ->
|
||||||
|
lager:debug("Exited with status ~b", [Status]),
|
||||||
|
{Status, list_to_binary(lists:reverse(Acc))};
|
||||||
|
{P, Other} ->
|
||||||
|
lager:warning("Unexpected return from port: ~p", [Other]),
|
||||||
|
accumulate(P, Acc)
|
||||||
|
end.
|
Loading…
Reference in New Issue
Block a user