From 54cac445e94fb1de5047feb4f5e1b1f216362848 Mon Sep 17 00:00:00 2001 From: Tino Breddin Date: Fri, 5 Jun 2020 11:00:08 +0200 Subject: [PATCH 1/3] Fix use of `ct` on projects without CT suites and configuration Before, running `rebar3 ct` on such an empty project would crash with an internal badmatch since no directory to run CT on could be found. Now this case will terminate with a sensible error message and won't try to run any further. --- src/rebar_prv_common_test.erl | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/rebar_prv_common_test.erl b/src/rebar_prv_common_test.erl index cfbf0840..caa60dfe 100644 --- a/src/rebar_prv_common_test.erl +++ b/src/rebar_prv_common_test.erl @@ -46,6 +46,7 @@ do(State) -> %% successfully compiled apps {ok, S} -> {RawOpts, _} = rebar_state:command_parsed_args(S), + ?DEBUG("CT OPTS: ~p~n", [RawOpts]), case proplists:get_value(compile_only, RawOpts, false) of true -> {ok, S}; @@ -77,6 +78,7 @@ do(State, Tests) -> symlink_to_last_ct_logs(State), {ok, State}; Error -> + ?DEBUG("ERR: ~p", [Error]), rebar_paths:set_paths([plugins, deps], State), symlink_to_last_ct_logs(State), Error @@ -147,6 +149,7 @@ setup_name(State) -> prepare_tests(State) -> %% command line test options CmdOpts = cmdopts(State), + ?DEBUG("CMDOPTS: ~p", [CmdOpts]), %% rebar.config test options CfgOpts = cfgopts(State), ProjectApps = rebar_state:project_apps(State), @@ -286,6 +289,7 @@ select_tests(State, ProjectApps, CmdOpts, CfgOpts) -> rebar_utils:reread_config(Configs, [update_logger]), Opts = merge_opts(CmdOpts,CfgOpts), + ?DEBUG("OPTS AFTER SELECT: ~p", [Opts]), discover_tests(State, ProjectApps, Opts). %% Merge the option lists from command line and rebar.config: @@ -335,7 +339,7 @@ sys_config_list(CmdOpts, CfgOpts) -> discover_tests(State, ProjectApps, Opts) -> case is_any_defined([spec,dir,suite],Opts) of %% no tests defined, try using `$APP/test` and `$ROOT/test` as dirs - false -> {ok, [default_tests(State, ProjectApps)|Opts]}; + false -> {ok, default_tests(State, ProjectApps) ++ Opts}; true -> {ok, Opts} end. @@ -346,9 +350,18 @@ default_tests(State, ProjectApps) -> case filelib:is_dir(BareTest) andalso not lists:any(F, ProjectApps) of %% `test` dir at root of project is already scheduled to be %% included or `test` does not exist - false -> {dir, AppTests}; + false -> + %% The rest of the call-chain expects the list of tests to no be + %% empty, thus we drop the parameter in that case entirely. + case AppTests of + [] -> + []; + _ -> + [{dir, AppTests}] + end; %% need to add `test` dir at root to dirs to be included - true -> {dir, AppTests ++ [BareTest]} + true -> + [{dir, AppTests ++ [BareTest]}] end. application_dirs([], []) -> []; @@ -484,6 +497,7 @@ test_dirs(State, Apps, Opts) -> case proplists:get_value(spec, Opts) of undefined -> case {proplists:get_value(suite, Opts), proplists:get_value(dir, Opts)} of + {undefined, undefined} -> {error, "One of the common_test parameters suite and dir must be set"}; {Suites, undefined} -> set_compile_dirs(State, Apps, {suite, Suites}); {undefined, Dirs} -> set_compile_dirs(State, Apps, {dir, Dirs}); {Suites, Dir} when is_integer(hd(Dir)) -> From 6fa9a7d478d24d7a9f167e1d6f7447c21d5cacdb Mon Sep 17 00:00:00 2001 From: Tino Breddin Date: Tue, 9 Jun 2020 09:59:51 +0200 Subject: [PATCH 2/3] Let CT succeed when no suite is configured --- src/rebar_prv_common_test.erl | 37 +++++++++++++++++++---------------- test/rebar_ct_SUITE.erl | 14 ++++++++++++- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/rebar_prv_common_test.erl b/src/rebar_prv_common_test.erl index caa60dfe..6f4050ae 100644 --- a/src/rebar_prv_common_test.erl +++ b/src/rebar_prv_common_test.erl @@ -46,7 +46,6 @@ do(State) -> %% successfully compiled apps {ok, S} -> {RawOpts, _} = rebar_state:command_parsed_args(S), - ?DEBUG("CT OPTS: ~p~n", [RawOpts]), case proplists:get_value(compile_only, RawOpts, false) of true -> {ok, S}; @@ -78,7 +77,6 @@ do(State, Tests) -> symlink_to_last_ct_logs(State), {ok, State}; Error -> - ?DEBUG("ERR: ~p", [Error]), rebar_paths:set_paths([plugins, deps], State), symlink_to_last_ct_logs(State), Error @@ -129,17 +127,23 @@ symlink_to_last_ct_logs(State) -> LogDir = filename:join([rebar_dir:base_dir(State), "logs"]), {ok, Filenames} = file:list_dir(LogDir), CtRunDirs = lists:filter(fun(S) -> re:run(S, "ct_run", [unicode]) /= nomatch end, Filenames), - NewestDir = lists:last(lists:sort(CtRunDirs)), - Target = filename:join([LogDir, "last"]), - Existing = filename:join([LogDir, NewestDir]), - case rebar_file_utils:symlink_or_copy(Existing, Target) of - ok -> ok; - exists -> - %% in case the symlink already exists we remove it - %% and make a new updated one - rebar_file_utils:rm_rf(Target), - rebar_file_utils:symlink_or_copy(Existing, Target); - Reason -> ?DEBUG("Warning, couldn't make a symlink to ~ts, reason: ~p.", [Target, Reason]) + case CtRunDirs of + [] -> + % If for some reason there are no such directories, we should not try to set up a link either. + ok; + _ -> + NewestDir = lists:last(lists:sort(CtRunDirs)), + Target = filename:join([LogDir, "last"]), + Existing = filename:join([LogDir, NewestDir]), + case rebar_file_utils:symlink_or_copy(Existing, Target) of + ok -> ok; + exists -> + %% in case the symlink already exists we remove it + %% and make a new updated one + rebar_file_utils:rm_rf(Target), + rebar_file_utils:symlink_or_copy(Existing, Target); + Reason -> ?DEBUG("Warning, couldn't make a symlink to ~ts, reason: ~p.", [Target, Reason]) + end end. setup_name(State) -> @@ -149,7 +153,6 @@ setup_name(State) -> prepare_tests(State) -> %% command line test options CmdOpts = cmdopts(State), - ?DEBUG("CMDOPTS: ~p", [CmdOpts]), %% rebar.config test options CfgOpts = cfgopts(State), ProjectApps = rebar_state:project_apps(State), @@ -289,7 +292,6 @@ select_tests(State, ProjectApps, CmdOpts, CfgOpts) -> rebar_utils:reread_config(Configs, [update_logger]), Opts = merge_opts(CmdOpts,CfgOpts), - ?DEBUG("OPTS AFTER SELECT: ~p", [Opts]), discover_tests(State, ProjectApps, Opts). %% Merge the option lists from command line and rebar.config: @@ -351,7 +353,7 @@ default_tests(State, ProjectApps) -> %% `test` dir at root of project is already scheduled to be %% included or `test` does not exist false -> - %% The rest of the call-chain expects the list of tests to no be + %% The rest of the call-chain expects the list of tests to not be %% empty, thus we drop the parameter in that case entirely. case AppTests of [] -> @@ -497,7 +499,8 @@ test_dirs(State, Apps, Opts) -> case proplists:get_value(spec, Opts) of undefined -> case {proplists:get_value(suite, Opts), proplists:get_value(dir, Opts)} of - {undefined, undefined} -> {error, "One of the common_test parameters suite and dir must be set"}; + {undefined, undefined} -> + {ok, rebar_state:project_apps(State, Apps)}; {Suites, undefined} -> set_compile_dirs(State, Apps, {suite, Suites}); {undefined, Dirs} -> set_compile_dirs(State, Apps, {dir, Dirs}); {Suites, Dir} when is_integer(hd(Dir)) -> diff --git a/test/rebar_ct_SUITE.erl b/test/rebar_ct_SUITE.erl index 15dc63ed..be89ebdf 100644 --- a/test/rebar_ct_SUITE.erl +++ b/test/rebar_ct_SUITE.erl @@ -10,6 +10,7 @@ multi_app_default_dirs/1, multi_app_default_beams/1, multi_app_ct_macro/1, + no_ct_suite/1, single_app_dir/1, single_extra_dir/1, single_unmanaged_dir/1, @@ -80,7 +81,8 @@ all() -> [{group, basic_app}, testspec_parse_error, cmd_vs_cfg_opts, single_testspec_in_ct_opts, - compile_only]. + compile_only, + no_ct_suite]. groups() -> [{basic_app, [], [basic_app_default_dirs, basic_app_default_beams, @@ -339,6 +341,16 @@ multi_app_ct_macro(Config) -> true = lists:member({d, 'COMMON_TEST'}, ErlOpts) end, Apps). +no_ct_suite(Config0) -> + Config = rebar_test_utils:init_rebar_state(Config0), + AppDir = ?config(apps, Config), + + Name = rebar_test_utils:create_random_name("no_ct_suite_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + rebar_test_utils:run_and_check(Config, [], ["ct"], {ok, [{app, Name, valid}]}). + single_app_dir(Config) -> AppDir = ?config(apps, Config), [Name1, _Name2] = ?config(appnames, Config), From a515a748c3deba4c0e0fe1be35255565a9744646 Mon Sep 17 00:00:00 2001 From: Tino Breddin Date: Wed, 10 Jun 2020 09:16:01 +0200 Subject: [PATCH 3/3] Fix test to only check proper options are set up --- test/rebar_ct_SUITE.erl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/rebar_ct_SUITE.erl b/test/rebar_ct_SUITE.erl index be89ebdf..7ced0978 100644 --- a/test/rebar_ct_SUITE.erl +++ b/test/rebar_ct_SUITE.erl @@ -349,7 +349,14 @@ no_ct_suite(Config0) -> Vsn = rebar_test_utils:create_random_vsn(), rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), - rebar_test_utils:run_and_check(Config, [], ["ct"], {ok, [{app, Name, valid}]}). + {ok, State} = rebar_test_utils:run_and_check(Config, [], ["as", "test", "lock"], return), + + {ok, Opts} = rebar_prv_common_test:prepare_tests(State), + + undefined = proplists:get_value(dir, Opts), + undefined = proplists:get_value(suite, Opts), + undefined = proplists:get_value(spec, Opts), + ok. single_app_dir(Config) -> AppDir = ?config(apps, Config),