%% ------------------------------------------------------------------- %% %% rebar: Erlang Build Tools %% %% Copyright (c) 2009 Dave Smith (dizzyd@dizzyd.com) %% %% Permission is hereby granted, free of charge, to any person obtaining a copy %% of this software and associated documentation files (the "Software"), to deal %% in the Software without restriction, including without limitation the rights %% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell %% copies of the Software, and to permit persons to whom the Software is %% furnished to do so, subject to the following conditions: %% %% The above copyright notice and this permission notice shall be included in %% all copies or substantial portions of the Software. %% %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR %% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, %% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE %% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER %% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, %% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN %% THE SOFTWARE. %% ------------------------------------------------------------------- %% %% Targets: %% test - runs common test suites in ./test %% int_test - runs suites in ./int_test %% perf_test - runs suites inm ./perf_test %% %% Global options: %% verbose=1 - show output from the common_test run as it goes %% suite="foo"" - runs /foo_SUITE %% case="mycase" - runs individual test case foo_SUITE:mycase %% ------------------------------------------------------------------- -module(rebar_ct). -export([test/2, int_test/2, perf_test/2]). -compile([export_all]). -include("rebar.hrl"). %% =================================================================== %% Public API %% =================================================================== test(Config, File) -> run_test_if_present("test", Config, File). int_test(Config, File) -> run_test_if_present("int_test", Config, File). perf_test(Config, File) -> run_test_if_present("perf_test", Config, File). %% =================================================================== %% Internal functions %% =================================================================== run_test_if_present(TestDir, Config, File) -> case filelib:is_dir(TestDir) of false -> ?WARN("~s directory not present - skipping\n", [TestDir]), ok; true -> run_test(TestDir, Config, File) end. run_test(TestDir, Config, _File) -> {Cmd, RawLog} = make_cmd(TestDir, Config), clear_log(RawLog), case rebar_config:is_verbose() of true -> Output = " >> " ++ RawLog ++ " 2>&1"; _ -> Output = " 2>&1 | tee -a " ++ RawLog end, case rebar_utils:sh(Cmd ++ Output, [{"TESTDIR", TestDir}]) of ok -> check_log(RawLog); {error, _Rc} -> show_log(RawLog), ?ERROR("Executing tests failed.\n", []), ?FAIL end. clear_log(RawLog) -> case filelib:ensure_dir("logs/index.html") of ok -> NowStr = rebar_utils:now_str(), LogHeader = "--- Test run on " ++ NowStr ++ " ---\n", ok = file:write_file(RawLog, LogHeader); {error, Reason} -> ?ERROR("Could not create log dir - ~p\n", [Reason]), ?FAIL end. %% calling ct with erl does not return non-zero on failure - have to check %% log results check_log(RawLog) -> Msg = os:cmd("grep -e 'TEST COMPLETE' -e '{error,make_failed}' " ++ RawLog), MakeFailed = string:str(Msg, "{error,make_failed}") =/= 0, RunFailed = string:str(Msg, ", 0 failed") =:= 0, if MakeFailed -> show_log(RawLog), ?ERROR("Building tests failed\n",[]), ?FAIL; RunFailed -> show_log(RawLog), ?ERROR("One or more tests failed\n",[]), ?FAIL; true -> ?CONSOLE("DONE. ~s\n", [Msg]) end. %% Show the log if it hasn't already been shown because verbose was on show_log(RawLog) -> ?CONSOLE("Showing log\n", []), case rebar_config:is_verbose() of true -> {ok, Contents} = file:read_file(RawLog), ?CONSOLE("~s", [Contents]); _ -> ok end. make_cmd(TestDir, _Config) -> {ok, Cwd} = file:get_cwd(), LogDir = filename:join(Cwd, "logs"), Ebin = filename:join(Cwd, "ebin"), IncludeDir = filename:join(Cwd, "include"), case filelib:is_dir(IncludeDir) of true -> Include = " -I \"" ++ IncludeDir ++ "\""; false -> Include = "" end, Cmd = lists:flatten(io_lib:format("erl " % should we expand ERL_PATH? " -noshell -pa \"~s\" ~s" " -s ct_run script_start -s erlang halt" " -name test@~s" " -logdir \"~s\"" " -env TEST_DIR \"~s\"", [Ebin, Include, net_adm:localhost(), LogDir, filename:join(Cwd, TestDir)])) ++ get_ct_config_file(TestDir) ++ get_config_file(TestDir) ++ get_suite(TestDir) ++ get_case(), RawLog = filename:join(LogDir, "raw.log"), {Cmd, RawLog}. get_ct_config_file(TestDir) -> Config = filename:join(TestDir, "test.config"), case filelib:is_regular(Config) of false -> " "; true -> " -ct_config " ++ Config end. get_config_file(TestDir) -> Config = filename:join(TestDir, "app.config"), case filelib:is_regular(Config) of false -> " "; true -> " -config " ++ Config end. get_suite(TestDir) -> case rebar_config:get_global(suite, undefined) of undefined -> " -dir " ++ TestDir; Suite -> Filename = filename:join(TestDir, Suite ++ "_SUITE.erl"), case filelib:is_regular(Filename) of false -> ?ERROR("Suite ~s not found\n", [Suite]), ?FAIL; true -> " -suite " ++ Filename end end. get_case() -> case rebar_config:get_global('case', undefined) of undefined -> ""; Case -> " -case " ++ Case end.