From efbdfbe117939cd50d0252a210b9b7634de42bb4 Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 9 May 2013 17:04:18 -0700 Subject: Basic file rename from rcl to rlx --- test/rcl_depsolver_tester.erl | 474 ------------------------ test/rcl_depsolver_tests.erl | 495 ------------------------- test/rclt_command_SUITE.erl | 97 ----- test/rclt_discover_SUITE.erl | 193 ---------- test/rclt_goal.erl | 63 ---- test/rclt_release_SUITE.erl | 837 ------------------------------------------ test/rlx_command_SUITE.erl | 97 +++++ test/rlx_depsolver_tester.erl | 474 ++++++++++++++++++++++++ test/rlx_depsolver_tests.erl | 495 +++++++++++++++++++++++++ test/rlx_discover_SUITE.erl | 193 ++++++++++ test/rlx_goal_tests.erl | 63 ++++ test/rlx_release_SUITE.erl | 837 ++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 2159 insertions(+), 2159 deletions(-) delete mode 100644 test/rcl_depsolver_tester.erl delete mode 100644 test/rcl_depsolver_tests.erl delete mode 100644 test/rclt_command_SUITE.erl delete mode 100644 test/rclt_discover_SUITE.erl delete mode 100644 test/rclt_goal.erl delete mode 100644 test/rclt_release_SUITE.erl create mode 100644 test/rlx_command_SUITE.erl create mode 100644 test/rlx_depsolver_tester.erl create mode 100644 test/rlx_depsolver_tests.erl create mode 100644 test/rlx_discover_SUITE.erl create mode 100644 test/rlx_goal_tests.erl create mode 100644 test/rlx_release_SUITE.erl (limited to 'test') diff --git a/test/rcl_depsolver_tester.erl b/test/rcl_depsolver_tester.erl deleted file mode 100644 index 53f5ac0..0000000 --- a/test/rcl_depsolver_tester.erl +++ /dev/null @@ -1,474 +0,0 @@ -%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 92 -*- -%% ex: ts=4 sx=4 et -%%------------------------------------------------------------------- -%% -%% Copyright 2012 Opscode, Inc. All Rights Reserved. -%% -%% This file is provided to you under the Apache License, -%% Version 2.0 (the "License"); you may not use this file -%% except in compliance with the License. You may obtain -%% a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, -%% software distributed under the License is distributed on an -%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -%% KIND, either express or implied. See the License for the -%% specific language governing permissions and limitations -%% under the License. -%% -%% @author Eric Merritt -%% @doc -%% Additional testing for depsolver -%% @end -%%------------------------------------------------------------------- --module(rcl_depsolver_tester). - --export([run_data/1, run_log/1]). --include_lib("eunit/include/eunit.hrl"). - --define(ADD_PKG, "^DepSelector\\sinst#\\s(\\d+)\\s-\\s" - "Adding\\spackage\\sid\\s(\\d+)\\/(\\d+):\\smin\\s=\\s-1," - "\\smax\\s=\\s(\\d+),\\scurrent\\sversion\\s0$"). --define(ADD_VC, "^DepSelector\\sinst#\\s(\\d+)\\s-\\sAdding\\sVC\\s" - "for\\s(\\d+)\\s@\\s(\\d+)\\sdepPkg\\s(\\d+)\\s\\[\\s(\\d+)" - "\\s(\\d+)\\s\\]$"). --define(ADD_GOAL, "^DepSelector\\sinst#\\s(\\d+)\\s-\\s" - "Marking\\sPackage\\sRequired\\s(\\d+)$"). - -%%============================================================================ -%% Public Api -%%============================================================================ -run_data(FileName) -> - {ok, Device} = file:open(FileName, [read]), - run_data_file(Device). - -run_log(FileName) -> - {ok, Device} = file:open(FileName, [read]), - run_log_file(Device). - -data1_test() -> - ExpectedResult = versionify([{"app6","0.0.1"}, - {"dep_pkg13","0.0.2"}, - {"app13","0.0.1"}, - {"dep_pkg2","0.0.5"}, - {"dep_pkg1","0.0.2"}, - {"dep_pkg7","0.1.2"}, - {"app9","0.0.1"}]), - ?assertMatch({ok, ExpectedResult}, - run_data(fix_rebar_brokenness("data1.txt"))). - -data2_test() -> - ExpectedResult = versionify([{"app18","0.0.1"}, - {"app4","0.0.1"}, - {"app1","0.0.1"}, - {"app6","0.0.1"}, - {"dep_pkg13","0.0.2"}, - {"app13","0.0.1"}, - {"dep_pkg5","0.0.2"}, - {"dep_pkg1","0.0.2"}, - {"dep_pkg2","0.0.5"}, - {"dep_pkg7","0.1.2"}, - {"app9","0.0.1"}, - {"dep_pkg16","1.0.2"}]), - ?assertMatch({ok, ExpectedResult}, - run_data(fix_rebar_brokenness("data2.txt"))). - -data3_test() -> - ExpectedResult = versionify([{"app68","0.0.1"}, - {"app58","0.0.1"}, - {"app48","0.0.7"}, - {"app38","0.0.1"}, - {"app28","0.0.1"}, - {"app18","0.0.1"}, - {"app4","0.0.1"}, - {"app1","0.0.1"}, - {"app6","0.0.1"}, - {"dep_pkg13","0.0.2"}, - {"app13","0.0.1"}, - {"dep_pkg5","0.0.2"}, - {"dep_pkg1","0.0.2"}, - {"dep_pkg2","0.0.5"}, - {"dep_pkg7","0.1.2"}, - {"app9","0.0.1"}, - {"dep_pkg16","1.0.2"}]), - ?assertMatch({ok,ExpectedResult}, run_data(fix_rebar_brokenness("data3.txt"))). - -data4_test() -> - ExpectedResult = versionify([{"dep_pkg20","0.0.2"}, - {"app78","0.0.1"}, - {"app68","0.0.1"}, - {"app58","0.0.1"}, - {"app48","0.0.7"}, - {"app38","0.0.1"}, - {"app28","0.0.1"}, - {"app18","0.0.1"}, - {"app4","0.0.1"}, - {"app1","0.0.1"}, - {"app6","0.0.1"}, - {"dep_pkg13","0.0.2"}, - {"app13","0.0.1"}, - {"dep_pkg5","0.0.2"}, - {"dep_pkg1","0.0.2"}, - {"dep_pkg2","0.0.5"}, - {"dep_pkg7","0.1.2"}, - {"app9","0.0.1"}, - {"dep_pkg16","1.0.2"}]), - ?assertMatch({ok, ExpectedResult}, - run_data(fix_rebar_brokenness("data4.txt"))). - -data5_test() -> - ExpectedResult = versionify([{"dep_pkg14","0.0.2"}, - {"dep_pkg22","0.0.2"}, - {"dep_pkg20","0.0.2"}, - {"app78","0.0.1"}, - {"app68","0.0.1"}, - {"app58","0.0.1"}, - {"app48","0.0.7"}, - {"app38","0.0.1"}, - {"app28","0.0.1"}, - {"app18","0.0.1"}, - {"app4","0.0.1"}, - {"app1","0.0.1"}, - {"app6","0.0.1"}, - {"dep_pkg13","0.0.2"}, - {"app13","0.0.1"}, - {"dep_pkg5","0.0.2"}, - {"dep_pkg1","0.0.2"}, - {"dep_pkg2","0.0.5"}, - {"dep_pkg7","0.1.2"}, - {"app9","0.0.1"}, - {"dep_pkg16","1.0.2"}]), - ?assertMatch({ok, ExpectedResult}, - run_data(fix_rebar_brokenness("data5.txt"))). - -data6_test() -> - ExpectedResult = versionify([{"app108","0.0.1"}, - {"app98","0.0.1"}, - {"app88","0.0.1"}, - {"dep_pkg14","0.0.2"}, - {"dep_pkg22","0.0.2"}, - {"dep_pkg20","0.0.2"}, - {"app78","0.0.1"}, - {"app68","0.0.1"}, - {"app58","0.0.1"}, - {"app48","0.0.7"}, - {"app38","0.0.1"}, - {"app28","0.0.1"}, - {"app18","0.0.1"}, - {"app4","0.0.1"}, - {"app1","0.0.1"}, - {"app6","0.0.1"}, - {"dep_pkg13","0.0.2"}, - {"app13","0.0.1"}, - {"dep_pkg5","0.0.2"}, - {"dep_pkg1","0.0.2"}, - {"dep_pkg2","0.0.5"}, - {"dep_pkg7","0.1.2"}, - {"app9","0.0.1"}, - {"dep_pkg16","1.0.2"}]), - ?assertMatch({ok, ExpectedResult}, - run_data(fix_rebar_brokenness("data6.txt"))). - -log_07be9e47_test() -> - Data = run_log(fix_rebar_brokenness("log-07be9e47-6f42-4a5d-b8b5-1d2eae1ad83b.txt")), - ExpectedResult = versionify([{"0","0"}, - {"1","0"}, - {"3","0"}, - {"4","0"}, - {"5","0"}, - {"6","0"}, - {"7","0"}, - {"8","0"}, - {"9","0"}, - {"10","0"}, - {"11","0"}, - {"12","0"}, - {"13","0"}, - {"14","0"}, - {"15","0"}, - {"16","0"}, - {"18","0"}, - {"19","0"}, - {"21","0"}, - {"22","0"}, - {"23","0"}, - {"24","0"}, - {"25","0"}]), - ?assertMatch({ok, ExpectedResult}, - Data). - -log_183998c1_test() -> - ?assertMatch({error, {unreachable_package,<<"9">>}}, - run_log(fix_rebar_brokenness("log-183998c1-2ada-4214-b308-e480345c42f2.txt"))). - - -log_311a15e7_test() -> - {ok, Data} = run_log(fix_rebar_brokenness("log-311a15e7-3378-4c5b-beb7-86a1b9cf0ea9.txt")), - ExpectedResult = lists:sort(versionify([{"45", "22"}, - {"40","1"}, - {"3","5"}, - {"9","0"}, - {"8","0"}, - {"7","0"}, - {"6","2"}, - {"1","5"}, - {"0","2"}, - {"61","1"}, - {"60","0"}, - {"35","4"}, - {"39","0"}, - {"38","2"}, - {"37","2"}, - {"36","3"}, - {"32","24"}, - {"30","0"}, - {"19","1"}, - {"18","0"}, - {"17","2"}, - {"16","0"}, - {"15","0"}, - {"14","1"}, - {"13","0"}, - {"12","1"}, - {"11","0"}, - {"10","1"}, - {"59","0"}, - {"58","1"}, - {"57","0"}, - {"56","0"}, - {"55","4"}, - {"29","2"}, - {"27","2"}, - {"26","0"}, - {"25","5"}, - {"24","3"}, - {"23","1"}, - {"22","3"}, - {"21","2"}, - {"20","0"}])), - ?assertMatch(ExpectedResult, lists:sort(Data)). - -log_382cfe5b_test() -> - {ok, Data} = - run_log(fix_rebar_brokenness("log-382cfe5b-0ac2-48b8-83d1-717cb4620990.txt")), - ExpectedResult = lists:sort(versionify([{"18","0"}, - {"17","0"}, - {"15","1"}, - {"14","0"}, - {"10","0"}, - {"7","0"}, - {"6","0"}, - {"5","0"}, - {"4","0"}, - {"3","0"}, - {"2","1"}, - {"1","0"}, - {"0","0"}])), - ?assertMatch(ExpectedResult, lists:sort(Data)). - -log_d3564ef6_test() -> - {ok, Data} = run_log(fix_rebar_brokenness("log-d3564ef6-6437-41e7-90b6-dbdb849551a6_mod.txt")), - ExpectedResult = lists:sort(versionify([{"57","5"}, - {"56","3"}, - {"55","4"}, - {"54","0"}, - {"53","1"}, - {"82","0"}, - {"81","0"}, - {"80","1"}, - {"29","0"}, - {"28","5"}, - {"27","3"}, - {"26","1"}, - {"25","3"}, - {"24","2"}, - {"23","0"}, - {"22","1"}, - {"21","0"}, - {"20","2"}, - {"75","32"}, - {"79","2"}, - {"78","4"}, - {"74","7"}, - {"73","11"}, - {"72","0"}, - {"70","1"}, - {"47","4"}, - {"45","1"}, - {"44","1"}, - {"43","7"}, - {"42","1"}, - {"41","2"}, - {"40","2"}, - {"19","0"}, - {"18","0"}, - {"17","1"}, - {"16","0"}, - {"15","1"}, - {"14","0"}, - {"13","1"}, - {"12","0"}, - {"11","0"}, - {"10","0"}, - {"9","2"}, - {"4","5"}, - {"3","2"}, - {"0","3"}, - {"69","0"}, - {"68","1"}, - {"67","7"}, - {"39","3"}, - {"35","24"}, - {"33","0"}, - {"32","2"}, - {"30","2"}])), - ?assertMatch(ExpectedResult, lists:sort(Data)). - -log_ea2d264b_test() -> - {ok, Data} = run_log(fix_rebar_brokenness("log-ea2d264b-003e-4611-94ed-14efc7732083.txt")), - ExpectedResult = lists:sort(versionify([{"18","1"}, - {"17","0"}, - {"16","0"}, - {"15","0"}, - {"14","0"}, - {"13","1"}, - {"10","1"}, - {"9","1"}, - {"8","2"}, - {"6","0"}, - {"5","0"}, - {"4","0"}, - {"3","0"}, - {"2","0"}, - {"1","0"}, - {"0","1"}])), - ?assertMatch(ExpectedResult, lists:sort(Data)). - -%%============================================================================ -%% Internal Functions -%%============================================================================ -versionify(X) when erlang:is_list(X) -> - lists:map(fun versionify/1, X); -versionify({K, V}) -> - {erlang:list_to_binary(K), rcl_depsolver:parse_version(V)}. - -fix_rebar_brokenness(Filename) -> - Alt1 = filename:join(["./test", "data", Filename]), - Alt2 = filename:join(["../test", "data", Filename]), - case filelib:is_regular(Alt1) of - true -> - Alt1; - false -> - case filelib:is_regular(Alt2) of - true -> - Alt2; - false -> - io:format("~p~n", [Alt2]), - erlang:throw(unable_to_find_data_files) - end - end. - -run_data_file(Device) -> - Constraints = get_constraints(io:get_line(Device, "")), - rcl_depsolver:solve(process_packages(read_packages(Device)), Constraints). - -goble_lines(_Device, eof, Acc) -> - lists:reverse(Acc); -goble_lines(_Device, {error, Err}, _Acc) -> - erlang:throw(Err); -goble_lines(Device, ValidVal, Acc) -> - goble_lines(Device, io:get_line(Device, ""), [ValidVal | Acc]). - -goble_lines(Device) -> - goble_lines(Device, io:get_line(Device, ""), []). - -run_log_file(Device) -> - State0 = rcl_depsolver:new_graph(), - {Goals, State2} = - lists:foldl(fun(Line, Data) -> - process_add_goal(Line, - process_add_constraint(Line, - process_add_package(Line, Data))) - end, {[], State0}, goble_lines(Device)), - rcl_depsolver:solve(State2, Goals). - -read_packages(Device) -> - process_line(Device, io:get_line(Device, ""), []). - -process_line(Device, eof, Acc) -> - file:close(Device), - Acc; -process_line(Device, [], Acc) -> - process_line(Device, io:get_line(Device, ""), - Acc); -process_line(Device, "\n", Acc) -> - process_line(Device, io:get_line(Device, ""), - Acc); -process_line(Device, [$\s | Rest], [{Pkg, Vsn, Deps} | Acc]) -> - [DepPackage, Type, DepVsn] = string:tokens(Rest, " \n"), - Dep = - case Type of - "=" -> - {DepPackage, DepVsn}; - ">=" -> - {DepPackage, DepVsn, gte} - end, - process_line(Device, io:get_line(Device, ""), - [{Pkg, Vsn, [Dep | Deps]} | Acc]); -process_line(Device, Pkg, Acc) -> - [Package, Vsn] = string:tokens(Pkg, " \n"), - process_line(Device, io:get_line(Device, ""), - [{Package, Vsn, []} | Acc]). - -process_packages(Pkgs) -> - lists:foldl(fun({Pkg, Vsn, Constraints}, Dom0) -> - rcl_depsolver:add_package_version(Dom0, Pkg, Vsn, Constraints) - end, rcl_depsolver:new_graph(), Pkgs). - -get_constraints(ConLine) -> - AppVsns = string:tokens(ConLine, " \n"), - lists:map(fun(AppCon) -> - parse_app(AppCon, []) - end, AppVsns). -parse_app([$= | Rest], Acc) -> - {lists:reverse(Acc), Rest}; -parse_app([$>, $= | Rest], Acc) -> - {lists:reverse(Acc), Rest, gte}; -parse_app([Else | Rest], Acc) -> - parse_app(Rest, [Else | Acc]); -parse_app([], Acc) -> - lists:reverse(Acc). - -process_add_package(Line, {Goals, State0}) -> - case re:run(Line, ?ADD_PKG, [{capture, all, list}]) of - {match, [_All, _InstNumber, PkgName, _PkgCount, VersionCount]} -> - {Goals, - lists:foldl(fun(PkgVsn, State1) -> - rcl_depsolver:add_package_version(State1, - PkgName, - erlang:integer_to_list(PkgVsn), - []) - end, State0, lists:seq(0, - erlang:list_to_integer(VersionCount)))}; - _ -> - {Goals, State0} - end. - -process_add_constraint(Line, {Goals, State0}) -> - case re:run(Line, ?ADD_VC, [{capture, all, list}]) of - {match, [_All, _InstNumber, Pkg, Vsn, Dep, _Ignore, DepVsn]} -> - {Goals, - rcl_depsolver:add_package_version(State0, Pkg, Vsn, [{Dep, DepVsn}])}; - _ -> - {Goals, State0} - end. - -process_add_goal(Line, {Goals, State0}) -> - case re:run(Line, ?ADD_GOAL, [{capture, all, list}]) of - {match,[_All, _InstNumber, NewGoal]} -> - {[NewGoal | Goals], State0}; - _ -> - {Goals, State0} - end. diff --git a/test/rcl_depsolver_tests.erl b/test/rcl_depsolver_tests.erl deleted file mode 100644 index eae31a4..0000000 --- a/test/rcl_depsolver_tests.erl +++ /dev/null @@ -1,495 +0,0 @@ -%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 80 -*- -%% ex: ts=4 sx=4 et -%% -%%------------------------------------------------------------------- -%% Copyright 2012 Opscode, Inc. All Rights Reserved. -%% -%% This file is provided to you under the Apache License, -%% Version 2.0 (the "License"); you may not use this file -%% except in compliance with the License. You may obtain -%% a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, -%% software distributed under the License is distributed on an -%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -%% KIND, either express or implied. See the License for the -%% specific language governing permissions and limitations -%% under the License. -%% -%% @author Eric Merritt -%%------------------------------------------------------------------- --module(rcl_depsolver_tests). - --include_lib("eunit/include/eunit.hrl"). - -%%============================================================================ -%% Tests -%%============================================================================ - -first_test() -> - Dom0 = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), [{app1, [{"0.1", [{app2, "0.2+build.33"}, - {app3, "0.2", '>='}]}, - {"0.2", []}, - {"0.3", []}]}, - {app2, [{"0.1", []}, - {"0.2+build.33",[{app3, "0.3"}]}, - {"0.3", []}]}, - {app3, [{"0.1", []}, - {"0.2", []}, - {"0.3", []}]}]), - - - case rcl_depsolver:solve(Dom0, [{app1, "0.1"}]) of - {ok,[{app3,{{0,3},{[],[]}}}, - {app2,{{0,2},{[],[<<"build">>,33]}}}, - {app1,{{0,1},{[],[]}}}]} -> - ok; - E -> - erlang:throw({invalid_result, E}) - end. - -second_test() -> - - Dom0 = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), [{app1, [{"0.1", [{app2, "0.1", '>='}, - {app4, "0.2"}, - {app3, "0.2", '>='}]}, - {"0.2", []}, - {"0.3", []}]}, - {app2, [{"0.1", [{app3, "0.2", gte}]}, - {"0.2", [{app3, "0.2", gte}]}, - {"0.3", [{app3, "0.2", '>='}]}]}, - {app3, [{"0.1", [{app4, "0.2", '>='}]}, - {"0.2", [{app4, "0.2"}]}, - {"0.3", []}]}, - {app4, [{"0.1", []}, - {"0.2", [{app2, "0.2", gte}, - {app3, "0.3"}]}, - {"0.3", []}]}]), - - X = rcl_depsolver:solve(Dom0, [{app1, "0.1"}, - {app2, "0.3"}]), - - ?assertMatch({ok, [{app3,{{0,3},{[],[]}}}, - {app2,{{0,3},{[],[]}}}, - {app4,{{0,2},{[],[]}}}, - {app1,{{0,1},{[],[]}}}]}, - X). - -third_test() -> - - Pkg1Deps = [{app2, "0.1.0", '>='}, - {app3, "0.1.1", "0.1.5", between}], - - Pkg2Deps = [{app4, "5.0.0", gte}], - Pkg3Deps = [{app5, "2.0.0", '>='}], - Pkg4Deps = [app5], - - Dom0 = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), [{app1, [{"0.1.0", Pkg1Deps}, - {"0.2", Pkg1Deps}, - {"3.0", Pkg1Deps}]}, - {app2, [{"0.0.1", Pkg2Deps}, - {"0.1", Pkg2Deps}, - {"1.0", Pkg2Deps}, - {"3.0", Pkg2Deps}]}, - {app3, [{"0.1.0", Pkg3Deps}, - {"0.1.3", Pkg3Deps}, - {"2.0.0", Pkg3Deps}, - {"3.0.0", Pkg3Deps}, - {"4.0.0", Pkg3Deps}]}, - {app4, [{"0.1.0", Pkg4Deps}, - {"0.3.0", Pkg4Deps}, - {"5.0.0", Pkg4Deps}, - {"6.0.0", Pkg4Deps}]}, - {app5, [{"0.1.0", []}, - {"0.3.0", []}, - {"2.0.0", []}, - {"6.0.0", []}]}]), - - ?assertMatch({ok, [{app5,{{6,0,0},{[],[]}}}, - {app3,{{0,1,3},{[],[]}}}, - {app4,{{6,0,0},{[],[]}}}, - {app2,{{3,0},{[],[]}}}, - {app1,{{3,0},{[],[]}}}]}, - rcl_depsolver:solve(Dom0, [{app1, "3.0"}])), - - - ?assertMatch({ok, [{app5,{{6,0,0},{[],[]}}}, - {app3,{{0,1,3},{[],[]}}}, - {app4,{{6,0,0},{[],[]}}}, - {app2,{{3,0},{[],[]}}}, - {app1,{{3,0},{[],[]}}}]}, - rcl_depsolver:solve(Dom0, [app1])). - -fail_test() -> - Dom0 = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), - [{app1, [{"0.1", [{app2, "0.2"}, - {app3, "0.2", gte}]}, - {"0.2", []}, - {"0.3", []}]}, - {app2, [{"0.1", []}, - {"0.2",[{app3, "0.1"}]}, - {"0.3", []}]}, - {app3, [{"0.1", []}, - {"0.2", []}, - {"0.3", []}]}]), - - Ret = rcl_depsolver:solve(Dom0, [{app1, "0.1"}]), - %% We do this to make sure all errors can be formated. - _ = rcl_depsolver:format_error(Ret), - ?assertMatch({error, - [{[{[{app1,{{0,1},{[],[]}}}], - [{app1,{{0,1},{[],[]}}},[[{app2,{{0,2},{[],[]}}}]]]}], - [{{app2,{{0,2},{[],[]}}},[{app3,{{0,1},{[],[]}}}]}, - {{app1,{{0,1},{[],[]}}},[{app3,{{0,2},{[],[]}},gte}]}]}]}, - Ret). - -conflicting_passing_test() -> - Pkg1Deps = [{app2, "0.1.0", '>='}, - {app5, "2.0.0"}, - {app4, "0.3.0", "5.0.0", between}, - {app3, "0.1.1", "0.1.5", between}], - - Pkg2Deps = [{app4, "3.0.0", gte}], - Pkg3Deps = [{app5, "2.0.0", '>='}], - - Dom0 = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), [{app1, [{"0.1.0", Pkg1Deps}, - {"0.1.0", Pkg1Deps}, - {"0.2", Pkg1Deps}, - {"3.0", Pkg1Deps}]}, - {app2, [{"0.0.1", Pkg2Deps}, - {"0.1", Pkg2Deps}, - {"1.0", Pkg2Deps}, - {"3.0", Pkg2Deps}]}, - {app3, [{"0.1.0", Pkg3Deps}, - {"0.1.3", Pkg3Deps}, - {"2.0.0", Pkg3Deps}, - {"3.0.0", Pkg3Deps}, - {"4.0.0", Pkg3Deps}]}, - {app4, [{"0.1.0", [{app5, "0.1.0"}]}, - {"0.3.0", [{app5, "0.3.0"}]}, - {"5.0.0", [{app5, "2.0.0"}]}, - {"6.0.0", [{app5, "6.0.0"}]}]}, - {app5, [{"0.1.0", []}, - {"0.3.0", []}, - {"2.0.0", []}, - {"6.0.0", []}]}]), - - ?assertMatch({ok, [{app5,{{2,0,0},{[],[]}}}, - {app3,{{0,1,3},{[],[]}}}, - {app4,{{5,0,0},{[],[]}}}, - {app2,{{3,0},{[],[]}}}, - {app1,{{3,0},{[],[]}}}]}, - rcl_depsolver:solve(Dom0, [{app1, "3.0"}])), - - ?assertMatch({ok, [{app5,{{2,0,0},{[],[]}}}, - {app3,{{0,1,3},{[],[]}}}, - {app4,{{5,0,0},{[],[]}}}, - {app2,{{3,0},{[],[]}}}, - {app1,{{3,0},{[],[]}}}]}, - rcl_depsolver:solve(Dom0, [app1, app2, app5])). - - - -circular_dependencies_test() -> - Dom0 = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), [{app1, [{"0.1.0", [app2]}]}, - {app2, [{"0.0.1", [app1]}]}]), - - ?assertMatch({ok, [{app1,{{0,1,0},{[],[]}}},{app2,{{0,0,1},{[],[]}}}]}, - rcl_depsolver:solve(Dom0, [{app1, "0.1.0"}])). - -conflicting_failing_test() -> - Pkg1Deps = [app2, - {app5, "2.0.0", '='}, - {app4, "0.3.0", "5.0.0", between}], - - Pkg2Deps = [{app4, "5.0.0", gte}], - Pkg3Deps = [{app5, "6.0.0"}], - - - Dom0 = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), [{app1, [{"3.0", Pkg1Deps}]}, - {app2, [{"0.0.1", Pkg2Deps}]}, - {app3, [{"0.1.0", Pkg3Deps}]}, - {app4, [{"5.0.0", [{app5, "2.0.0"}]}]}, - {app5, [{"2.0.0", []}, - {"6.0.0", []}]}]), - Ret = rcl_depsolver:solve(Dom0, [app1, app3]), - _ = rcl_depsolver:format_error(Ret), - ?assertMatch({error, - [{[{[app1], - [{app1,{{3,0},{[],[]}}}, - [[{app4,{{5,0,0},{[],[]}}}], - [{app2,{{0,0,1},{[],[]}}},[[{app4,{{5,0,0},{[],[]}}}]]]]]}, - {[app3], - [{app3,{{0,1,0},{[],[]}}},[[{app5,{{6,0,0},{[],[]}}}]]]}], - [{{app4,{{5,0,0},{[],[]}}},[{app5,{{2,0,0},{[],[]}}}]}, - {{app1,{{3,0},{[],[]}}},[{app5,{{2,0,0},{[],[]}},'='}]}]}]}, - Ret). - - -pessimistic_major_minor_patch_test() -> - - Pkg1Deps = [{app2, "2.1.1", '~>'}, - {app3, "0.1.1", "0.1.5", between}], - - Pkg2Deps = [{app4, "5.0.0", gte}], - Pkg3Deps = [{app5, "2.0.0", '>='}], - Pkg4Deps = [app5], - - Dom0 = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), [{app1, [{"0.1.0", Pkg1Deps}, - {"0.2", Pkg1Deps}, - {"3.0", Pkg1Deps}]}, - {app2, [{"0.0.1", Pkg2Deps}, - {"0.1", Pkg2Deps}, - {"1.0", Pkg2Deps}, - {"2.1.5", Pkg2Deps}, - {"2.2", Pkg2Deps}, - {"3.0", Pkg2Deps}]}, - {app3, [{"0.1.0", Pkg3Deps}, - {"0.1.3", Pkg3Deps}, - {"2.0.0", Pkg3Deps}, - {"3.0.0", Pkg3Deps}, - {"4.0.0", Pkg3Deps}]}, - {app4, [{"0.1.0", Pkg4Deps}, - {"0.3.0", Pkg4Deps}, - {"5.0.0", Pkg4Deps}, - {"6.0.0", Pkg4Deps}]}, - {app5, [{"0.1.0", []}, - {"0.3.0", []}, - {"2.0.0", []}, - {"6.0.0", []}]}]), - ?assertMatch({ok, [{app5,{{6,0,0},{[],[]}}}, - {app3,{{0,1,3},{[],[]}}}, - {app4,{{6,0,0},{[],[]}}}, - {app2,{{2,1,5},{[],[]}}}, - {app1,{{3,0},{[],[]}}}]}, - rcl_depsolver:solve(Dom0, [{app1, "3.0"}])). - -pessimistic_major_minor_test() -> - - Pkg1Deps = [{app2, "2.1", '~>'}, - {app3, "0.1.1", "0.1.5", between}], - - Pkg2Deps = [{app4, "5.0.0", gte}], - Pkg3Deps = [{app5, "2.0.0", '>='}], - Pkg4Deps = [app5], - - Dom0 = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), [{app1, [{"0.1.0", Pkg1Deps}, - {"0.2", Pkg1Deps}, - {"3.0", Pkg1Deps}]}, - {app2, [{"0.0.1", Pkg2Deps}, - {"0.1", Pkg2Deps}, - {"1.0", Pkg2Deps}, - {"2.1.5", Pkg2Deps}, - {"2.2", Pkg2Deps}, - {"3.0", Pkg2Deps}]}, - {app3, [{"0.1.0", Pkg3Deps}, - {"0.1.3", Pkg3Deps}, - {"2.0.0", Pkg3Deps}, - {"3.0.0", Pkg3Deps}, - {"4.0.0", Pkg3Deps}]}, - {app4, [{"0.1.0", Pkg4Deps}, - {"0.3.0", Pkg4Deps}, - {"5.0.0", Pkg4Deps}, - {"6.0.0", Pkg4Deps}]}, - {app5, [{"0.1.0", []}, - {"0.3.0", []}, - {"2.0.0", []}, - {"6.0.0", []}]}]), - ?assertMatch({ok, [{app5,{{6,0,0},{[],[]}}}, - {app3,{{0,1,3},{[],[]}}}, - {app4,{{6,0,0},{[],[]}}}, - {app2,{{2,2},{[],[]}}}, - {app1,{{3,0},{[],[]}}}]}, - rcl_depsolver:solve(Dom0, [{app1, "3.0"}])). - -filter_versions_test() -> - - Cons = [{app2, "2.1", '~>'}, - {app3, "0.1.1", "0.1.5", between}, - {app4, "5.0.0", gte}, - {app5, "2.0.0", '>='}, - app5], - - Packages = [{app1, "0.1.0"}, - {app1, "0.2"}, - {app1, "0.2"}, - {app1, "3.0"}, - {app2, "0.0.1"}, - {app2, "0.1"}, - {app2, "1.0"}, - {app2, "2.1.5"}, - {app2, "2.2"}, - {app2, "3.0"}, - {app3, "0.1.0"}, - {app3, "0.1.3"}, - {app3, "2.0.0"}, - {app3, "3.0.0"}, - {app3, "4.0.0"}, - {app4, "0.1.0"}, - {app4, "0.3.0"}, - {app4, "5.0.0"}, - {app4, "6.0.0"}, - {app5, "0.1.0"}, - {app5, "0.3.0"}, - {app5, "2.0.0"}, - {app5, "6.0.0"}], - - ?assertMatch({ok, [{app1,"0.1.0"}, - {app1,"0.2"}, - {app1,"0.2"}, - {app1,"3.0"}, - {app2,"2.1.5"}, - {app2,"2.2"}, - {app3,"0.1.3"}, - {app4,"5.0.0"}, - {app4,"6.0.0"}, - {app5,"2.0.0"}, - {app5,"6.0.0"}]}, - rcl_depsolver:filter_packages(Packages, Cons)), - - Ret = rcl_depsolver:filter_packages(Packages, - [{"foo", "1.0.0", '~~~~'} | Cons]), - _ = rcl_depsolver:format_error(Ret), - ?assertMatch({error, {invalid_constraints, [{<<"foo">>,{{1,0,0},{[],[]}},'~~~~'}]}}, Ret). - - --spec missing_test() -> ok. -missing_test() -> - - Dom0 = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), [{app1, [{"0.1", [{app2, "0.2"}, - {app3, "0.2", '>='}, - {app4, "0.2", '='}]}, - {"0.2", [{app4, "0.2"}]}, - {"0.3", [{app4, "0.2", '='}]}]}, - {app2, [{"0.1", []}, - {"0.2",[{app3, "0.3"}]}, - {"0.3", []}]}, - {app3, [{"0.1", []}, - {"0.2", []}, - {"0.3", []}]}]), - Ret1 = rcl_depsolver:solve(Dom0, [{app4, "0.1"}, {app3, "0.1"}]), - _ = rcl_depsolver:format_error(Ret1), - ?assertMatch({error,{unreachable_package,app4}}, Ret1), - - Ret2 = rcl_depsolver:solve(Dom0, [{app1, "0.1"}]), - _ = rcl_depsolver:format_error(Ret2), - ?assertMatch({error,{unreachable_package,app4}}, - Ret2). - - -binary_test() -> - - World = [{<<"foo">>, [{<<"1.2.3">>, [{<<"bar">>, <<"2.0.0">>, gt}]}]}, - {<<"bar">>, [{<<"2.0.0">>, [{<<"foo">>, <<"3.0.0">>, gt}]}]}], - Ret = rcl_depsolver:solve(rcl_depsolver:add_packages(rcl_depsolver:new_graph(), - World), - [<<"foo">>]), - - _ = rcl_depsolver:format_error(Ret), - ?assertMatch({error, - [{[{[<<"foo">>],[{<<"foo">>,{{1,2,3},{[],[]}}}]}], - [{{<<"foo">>,{{1,2,3},{[],[]}}}, - [{<<"bar">>,{{2,0,0},{[],[]}},gt}]}]}]}, Ret). - -%% -%% We don't have bar cookbook -%% -%% Ruby gives -%% "message":"Unable to satisfy constraints on cookbook bar, which does not -%% exist, due to run list item (foo >= 0.0.0). Run list items that may result -%% in a constraint on bar: [(foo = 1.2.3) -> (bar > 2.0.0)]", -%% "unsatisfiable_run_list_item":"(foo >= 0.0.0)", -%% "non_existent_cookbooks":["bar"]," -%% "most_constrained_cookbooks":[]}" -%% -doesnt_exist_test() -> - Constraints = [{<<"foo">>,[{<<"1.2.3">>, [{<<"bar">>, <<"2.0.0">>, gt}]}]}], - World = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), Constraints), - Ret = rcl_depsolver:solve(World, [<<"foo">>]), - _ = rcl_depsolver:format_error(Ret), - ?assertMatch({error,{unreachable_package,<<"bar">>}}, Ret). - -%% -%% We have v 2.0.0 of bar but want > 2.0.0 -%% -%% Ruby gives -%% "message":"Unable to satisfy constraints on cookbook bar due to run list item -%% (foo >= 0.0.0). Run list items that may result in a constraint on bar: [(foo -%% = 1.2.3) -> (bar > 2.0.0)]", -%% "unsatisfiable_run_list_item":"(foo >= 0.0.0)", -%% "non_existent_cookbooks":[], -%% "most_constrained_cookbooks":["bar 2.0.0 -> []"] -%% -not_new_enough_test() -> - - Constraints = [{<<"foo">>, [{<<"1.2.3">>, [{<<"bar">>, <<"2.0.0">>, gt}]}]}, - {<<"bar">>, [{<<"2.0.0">>, []}]}], - World = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), Constraints), - Ret = rcl_depsolver:solve(World, [<<"foo">>]), - _ = rcl_depsolver:format_error(Ret), - ?assertMatch({error, - [{[{[<<"foo">>],[{<<"foo">>,{{1,2,3},{[],[]}}}]}], - [{{<<"foo">>,{{1,2,3},{[],[]}}}, - [{<<"bar">>,{{2,0,0},{[],[]}},gt}]}]}]}, Ret). - -%% -%% circular deps are bad -%% -%% Ruby gives -%% "message":"Unable to satisfy constraints on cookbook bar due to run list item (foo >= 0.0.0). -%% Run list items that may result in a constraint on bar: [(foo = 1.2.3) -> (bar > 2.0.0)]", -%% "unsatisfiable_run_list_item":"(foo >= 0.0.0)", -%% "non_existent_cookbooks":[], -%% "most_constrained_cookbooks:["bar = 2.0.0 -> [(foo > 3.0.0)]"] -%% -impossible_dependency_test() -> - World = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), - [{<<"foo">>, [{<<"1.2.3">>,[{ <<"bar">>, <<"2.0.0">>, gt}]}]}, - {<<"bar">>, [{<<"2.0.0">>, [{ <<"foo">>, <<"3.0.0">>, gt}]}]}]), - Ret = rcl_depsolver:solve(World, [<<"foo">>]), - _ = rcl_depsolver:format_error(Ret), - ?assertMatch({error, - [{[{[<<"foo">>],[{<<"foo">>,{{1,2,3},{[],[]}}}]}], - [{{<<"foo">>,{{1,2,3},{[],[]}}}, - [{<<"bar">>,{{2,0,0},{[],[]}},gt}]}]}]}, Ret). - -%% -%% Formatting tests -%% -format_test_() -> - [{"format constraint", - [equal_bin_string(<<"foo">>, rcl_depsolver:format_constraint(<<"foo">>)), - equal_bin_string(<<"foo">>, rcl_depsolver:format_constraint(foo)), - equal_bin_string(<<"(foo = 1.2.0)">>, rcl_depsolver:format_constraint({<<"foo">>, {{1,2,0}, {[], []}}})), - equal_bin_string(<<"(foo = 1.2.0)">>, rcl_depsolver:format_constraint({<<"foo">>, {{1,2,0}, {[], []}}, '='})), - equal_bin_string(<<"(foo > 1.2.0)">>, - rcl_depsolver:format_constraint({<<"foo">>, {{1,2,0}, {[], []}}, '>'})), - equal_bin_string(<<"(foo > 1.2.0)">>, - rcl_depsolver:format_constraint({<<"foo">>, {{1,2,0}, {[], []}}, gt})), - equal_bin_string(<<"(foo between 1.2.0 and 1.3.0)">>, - rcl_depsolver:format_constraint({<<"foo">>,{{1,2,0}, {[], []}}, - {{1,3,0}, {[], []}}, between})), - equal_bin_string(<<"(foo > 1.2.0-alpha.1+build.36)">>, - rcl_depsolver:format_constraint({<<"foo">>, - {{1,2,0}, {["alpha", 1], ["build", 36]}}, gt})) - ] - }, - {"format roots", - [equal_bin_string(<<"(bar = 1.2.0)">>, - rcl_depsolver:format_roots([ [{<<"bar">>, {{1,2,0},{[],[]}}}] ])), - equal_bin_string(<<"(bar = 1.2.0), foo">>, - rcl_depsolver:format_roots([[<<"foo">>, - {<<"bar">>, {{1,2,0},{[],[]}}}]])), - equal_bin_string(<<"(bar = 1.2.0), foo">>, - rcl_depsolver:format_roots([[<<"foo">>], [{<<"bar">>, {{1,2,0},{[],[]}}}]])) - ] - } - ]. - -%% -%% Internal functions -%% -equal_bin_string(Expected, Got) -> - ?_assertEqual(Expected, erlang:iolist_to_binary(Got)). diff --git a/test/rclt_command_SUITE.erl b/test/rclt_command_SUITE.erl deleted file mode 100644 index 05da548..0000000 --- a/test/rclt_command_SUITE.erl +++ /dev/null @@ -1,97 +0,0 @@ -%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 92 -*- -%%% Copyright 2012 Erlware, LLC. All Rights Reserved. -%%% -%%% This file is provided to you under the Apache License, -%%% Version 2.0 (the "License"); you may not use this file -%%% except in compliance with the License. You may obtain -%%% a copy of the License at -%%% -%%% http://www.apache.org/licenses/LICENSE-2.0 -%%% -%%% Unless required by applicable law or agreed to in writing, -%%% software distributed under the License is distributed on an -%%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -%%% KIND, either express or implied. See the License for the -%%% specific language governing permissions and limitations -%%% under the License. -%%%------------------------------------------------------------------- -%%% @author Eric Merrit -%%% @copyright (C) 2012, Eric Merrit --module(rclt_command_SUITE). - --export([suite/0, - init_per_suite/1, - end_per_suite/1, - all/0, - normal_passing_case/1, - lib_fail_case/1, - spec_parse_fail_case/1, - config_fail_case/1]). - --include_lib("common_test/include/ct.hrl"). --include_lib("eunit/include/eunit.hrl"). - -suite() -> - [{timetrap,{seconds,30}}]. - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -all() -> - [normal_passing_case, lib_fail_case, config_fail_case]. - -normal_passing_case(Config) -> - DataDir = proplists:get_value(data_dir, Config), - Lib1 = filename:join([DataDir, <<"lib1">>]), - Lib2 = filename:join([DataDir, <<"lib2">>]), - Outdir = filename:join([DataDir, "outdir"]), - ok = rcl_util:mkdir_p(Lib1), - ok = rcl_util:mkdir_p(Lib2), - Goal1 = "app1<=33.33+build4", - Goal2 = "app2:btwn:33.22,45.22+build.21", - - LogLevel = "2", - RelName = "foo-release", - RelVsn = "33.222", - CmdLine = ["-V", LogLevel, "-g",Goal1,"-g",Goal2, "-l", Lib1, "-l", Lib2, - "-n", RelName, "-v", RelVsn, "-o", Outdir], - {ok, {Opts, Targets}} = getopt:parse(relcool:opt_spec_list(), CmdLine), - {ok, State} = rcl_cmd_args:args2state(Opts, Targets), - ?assertMatch([Lib1, Lib2], - rcl_state:lib_dirs(State)), - ?assertMatch(Outdir, rcl_state:output_dir(State)), - - ?assertMatch([{app1,{{33,33},{[],[<<"build4">>]}},lte}, - {app2, - {{33,22},{[],[]}}, - {{45,22},{[],[<<"build">>,21]}}, between}], - rcl_state:goals(State)). - - -lib_fail_case(Config) -> - DataDir = proplists:get_value(data_dir, Config), - Lib1 = filename:join([DataDir, "lib1"]), - Lib2 = filename:join([DataDir, "lib3333"]), - ok = rcl_util:mkdir_p(Lib1), - - CmdLine = ["-l", Lib1, "-l", Lib2], - {ok, {Opts, Targets}} = getopt:parse(relcool:opt_spec_list(), CmdLine), - ?assertMatch({error, {_, {not_directory, Lib2}}}, - rcl_cmd_args:args2state(Opts, Targets)). - -spec_parse_fail_case(_Config) -> - Spec = "aaeu:3333:33.22a44", - CmdLine = ["-g", Spec], - {ok, {Opts, Targets}} = getopt:parse(relcool:opt_spec_list(), CmdLine), - ?assertMatch({error, {_, {failed_to_parse, _Spec}}}, - rcl_cmd_args:args2state(Opts, Targets)). - -config_fail_case(_Config) -> - ConfigFile = "does-not-exist", - CmdLine = ["-c", ConfigFile], - {ok, {Opts, Targets}} = getopt:parse(relcool:opt_spec_list(), CmdLine), - ?assertMatch({error, {_, {invalid_config_file, ConfigFile}}}, - rcl_cmd_args:args2state(Opts, Targets)). diff --git a/test/rclt_discover_SUITE.erl b/test/rclt_discover_SUITE.erl deleted file mode 100644 index e3a2861..0000000 --- a/test/rclt_discover_SUITE.erl +++ /dev/null @@ -1,193 +0,0 @@ -%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 92 -*- -%%% Copyright 2012 Erlware, LLC. All Rights Reserved. -%%% -%%% This file is provided to you under the Apache License, -%%% Version 2.0 (the "License"); you may not use this file -%%% except in compliance with the License. You may obtain -%%% a copy of the License at -%%% -%%% http://www.apache.org/licenses/LICENSE-2.0 -%%% -%%% Unless required by applicable law or agreed to in writing, -%%% software distributed under the License is distributed on an -%%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -%%% KIND, either express or implied. See the License for the -%%% specific language governing permissions and limitations -%%% under the License. -%%%------------------------------------------------------------------- -%%% @author Eric Merrit -%%% @copyright (C) 2012, Eric Merrit --module(rclt_discover_SUITE). - --export([suite/0, - init_per_suite/1, - end_per_suite/1, - init_per_testcase/2, - all/0, - normal_case/1, - no_beam_case/1, - bad_ebin_case/1]). - --include_lib("common_test/include/ct.hrl"). --include_lib("eunit/include/eunit.hrl"). - -suite() -> - [{timetrap,{seconds,30}}]. - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -init_per_testcase(_, Config) -> - DataDir = proplists:get_value(data_dir, Config), - LibDir1 = filename:join([DataDir, create_random_name("lib_dir1_")]), - LibDir2 = filename:join([DataDir, create_random_name("lib_dir2_")]), - ok = rcl_util:mkdir_p(LibDir1), - ok = rcl_util:mkdir_p(LibDir2), - State = rcl_state:new([{lib_dirs, [LibDir1, LibDir2]}], release), - [{lib1, LibDir1}, - {lib2, LibDir2}, - {state, State} | Config]. - - -all() -> - [normal_case, no_beam_case, bad_ebin_case]. - -normal_case(Config) -> - LibDir1 = proplists:get_value(lib1, Config), - Apps1 = [(fun({Name, Vsn}) -> - create_app(LibDir1, Name, Vsn) - end)(App) - || - App <- - [{create_random_name("lib_app1_"), create_random_vsn()} - || _ <- lists:seq(1, 100)]], - - LibDir2 = proplists:get_value(lib2, Config), - Apps2 = [(fun({Name, Vsn}) -> - create_app(LibDir2, Name, Vsn) - end)(App) - || App <- - [{create_random_name("lib_app2_"), create_random_vsn()} - || _ <- lists:seq(1, 100)]], - State0 = rcl_state:put(proplists:get_value(state, Config), - disable_default_libs, true), - {DiscoverProvider, {ok, State1}} = rcl_provider:new(rcl_prv_discover, State0), - {ok, State2} = rcl_provider:do(DiscoverProvider, State1), - lists:foreach(fun(App) -> - ?assertMatch(true, lists:member(App, rcl_state:available_apps(State2))) - end, Apps1), - - lists:foreach(fun(App) -> - ?assertMatch(true, lists:member(App, rcl_state:available_apps(State2))) - end, Apps2), - Length = erlang:length(Apps2) + - erlang:length(Apps2), - ?assertMatch(Length, erlang:length(rcl_state:available_apps(State2))). - -no_beam_case(Config) -> - %% We silently ignore apps with no beams - LibDir1 = proplists:get_value(lib1, Config), - _Apps1 = [(fun({Name, Vsn}) -> - create_app(LibDir1, Name, Vsn) - end)(App) - || - App <- - [{create_random_name("lib_app1_"), create_random_vsn()} - || _ <- lists:seq(1, 100)]], - - LibDir2 = proplists:get_value(lib2, Config), - _Apps2 = [(fun({Name, Vsn}) -> - create_app(LibDir2, Name, Vsn) - end)(App) - || App <- - [{create_random_name("lib_app2_"), create_random_vsn()} - || _ <- lists:seq(1, 100)]], - BadName = create_random_name("error_bad"), - BadVsn = create_random_vsn(), - AppDir = filename:join([LibDir2, BadName]), - write_app_file(AppDir, BadName, BadVsn), - State0 = proplists:get_value(state, Config), - {DiscoverProvider, {ok, State1}} = rcl_provider:new(rcl_prv_discover, State0), - EbinDir = filename:join([LibDir2, BadName, <<"ebin">>]), - ?assertMatch({error, {_, [{no_beam_files, EbinDir}]}}, - rcl_provider:do(DiscoverProvider, State1)). - -bad_ebin_case(Config) -> - LibDir1 = proplists:get_value(lib1, Config), - _Apps1 = [(fun({Name, Vsn}) -> - create_app(LibDir1, Name, Vsn) - end)(App) - || - App <- - [{create_random_name("lib_app1_"), create_random_vsn()} - || _ <- lists:seq(1, 100)]], - - LibDir2 = proplists:get_value(lib2, Config), - _Apps2 = [(fun({Name, Vsn}) -> - create_app(LibDir2, Name, Vsn) - end)(App) - || App <- - [{create_random_name("lib_app2_"), create_random_vsn()} - || _ <- lists:seq(1, 100)]], - BadName = create_random_name("error_bad"), - BadVsn = create_random_vsn(), - AppDir = filename:join([LibDir2, BadName]), - Filename = filename:join([AppDir, <<"ebin">>, BadName ++ ".app"]), - ok = filelib:ensure_dir(Filename), - ok = ec_file:write_term(Filename, get_bad_app_metadata(BadName, BadVsn)), - write_beam_file(AppDir, BadName), - State0 = proplists:get_value(state, Config), - {DiscoverProvider, {ok, State1}} = rcl_provider:new(rcl_prv_discover, State0), - ?assertMatch({error, {_, [{invalid_app_file, Filename}]}}, - rcl_provider:do(DiscoverProvider, State1)). - - -%%%=================================================================== -%%% Helper functions -%%%=================================================================== -create_app(Dir, Name, Vsn) -> - AppDir = filename:join([Dir, Name]), - write_app_file(AppDir, Name, Vsn), - write_beam_file(AppDir, Name), - {ok, App} = rcl_app_info:new(erlang:list_to_atom(Name), Vsn, - erlang:iolist_to_binary(AppDir), - [kernel, stdlib], []), - App. - -write_beam_file(Dir, Name) -> - Beam = filename:join([Dir, "ebin", "not_a_real_beam" ++ Name ++ ".beam"]), - ok = filelib:ensure_dir(Beam), - ok = ec_file:write_term(Beam, testing_purposes_only). - -write_app_file(Dir, Name, Version) -> - Filename = filename:join([Dir, "ebin", Name ++ ".app"]), - ok = filelib:ensure_dir(Filename), - ok = ec_file:write_term(Filename, get_app_metadata(Name, Version)). - -get_app_metadata(Name, Vsn) -> - {application, erlang:list_to_atom(Name), - [{description, ""}, - {vsn, Vsn}, - {modules, []}, - {applications, [kernel, stdlib]}]}. - -get_bad_app_metadata(Name, Vsn) -> - ["{application, ", Name, ", - [{description, \"\"}, - {vsn, \"", Vsn, "\"}, - {modules, [], - {applications, [kernel, stdlib]}]}."]. - - -create_random_name(Name) -> - random:seed(erlang:now()), - Name ++ erlang:integer_to_list(random:uniform(1000000)). - -create_random_vsn() -> - random:seed(erlang:now()), - lists:flatten([erlang:integer_to_list(random:uniform(100)), - ".", erlang:integer_to_list(random:uniform(100)), - ".", erlang:integer_to_list(random:uniform(100))]). diff --git a/test/rclt_goal.erl b/test/rclt_goal.erl deleted file mode 100644 index 20fb5e5..0000000 --- a/test/rclt_goal.erl +++ /dev/null @@ -1,63 +0,0 @@ -%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 92 -*- -%%% Copyright 2012 Erlware, LLC. All Rights Reserved. -%%% -%%% This file is provided to you under the Apache License, -%%% Version 2.0 (the "License"); you may not use this file -%%% except in compliance with the License. You may obtain -%%% a copy of the License at -%%% -%%% http://www.apache.org/licenses/LICENSE-2.0 -%%% -%%% Unless required by applicable law or agreed to in writing, -%%% software distributed under the License is distributed on an -%%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -%%% KIND, either express or implied. See the License for the -%%% specific language governing permissions and limitations -%%% under the License. -%%%--------------------------------------------------------------------------- -%%% @author Eric Merritt -%%% @copyright (C) 2012 Erlware, LLC. -%%% @doc test for target spec parsing --module(rclt_goal). - --include_lib("eunit/include/eunit.hrl"). - -parse_test() -> - ?assertMatch({ok, getopt}, - rcl_goal:parse("getopt")), - ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, '='}}, - rcl_goal:parse("getopt=0.5.1")), - ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, '='}}, - rcl_goal:parse("getopt:0.5.1")), - ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, '='}}, - rcl_goal:parse("getopt-0.5.1")), - ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, gte}}, - rcl_goal:parse("getopt >= 0.5.1")), - ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, gte}}, - rcl_goal:parse("getopt:gte:0.5.1")), - ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, gt}}, - rcl_goal:parse("getopt>0.5.1")), - ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, gt}}, - rcl_goal:parse("getopt:gt:0.5.1")), - ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, lte}}, - rcl_goal:parse("getopt<= 0.5.1")), - ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, lte}}, - rcl_goal:parse("getopt:lte:0.5.1")), - ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, lt}}, - rcl_goal:parse("getopt<0.5.1")), - ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, pes}}, - rcl_goal:parse("getopt ~>0.5.1")), - ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, pes}}, - rcl_goal:parse("getopt: pes:0.5.1")), - ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, {{0,6,1},{[],[]}}, between}}, - rcl_goal:parse("getopt:btwn:0.5.1,0.6.1")), - ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, {{0,6,1},{[],[]}}, between}}, - rcl_goal:parse("getopt:between :0.5.1,0.6.1")). - -fail_test() -> - ?assertMatch({fail,_}, - rcl_goal:parse("got:")), - ?assertMatch({fail,_}, - rcl_goal:parse("between:btwn:0.5")), - ?assertMatch({fail,_}, - rcl_goal:parse("between:btwn:0.5,")). diff --git a/test/rclt_release_SUITE.erl b/test/rclt_release_SUITE.erl deleted file mode 100644 index 90d99c9..0000000 --- a/test/rclt_release_SUITE.erl +++ /dev/null @@ -1,837 +0,0 @@ -%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 92 -*- -%%% Copyright 2012 Erlware, LLC. All Rights Reserved. -%%% -%%% This file is provided to you under the Apache License, -%%% Version 2.0 (the "License"); you may not use this file -%%% except in compliance with the License. You may obtain -%%% a copy of the License at -%%% -%%% http://www.apache.org/licenses/LICENSE-2.0 -%%% -%%% Unless required by applicable law or agreed to in writing, -%%% software distributed under the License is distributed on an -%%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -%%% KIND, either express or implied. See the License for the -%%% specific language governing permissions and limitations -%%% under the License. -%%%------------------------------------------------------------------- -%%% @author Eric Merrit -%%% @copyright (C) 2012, Eric Merrit --module(rclt_release_SUITE). - --export([suite/0, - init_per_suite/1, - end_per_suite/1, - init_per_testcase/2, - all/0, - make_release/1, - make_scriptless_release/1, - make_overridden_release/1, - make_skip_app_release/1, - make_rerun_overridden_release/1, - make_implicit_config_release/1, - overlay_release/1, - make_goalless_release/1, - make_depfree_release/1, - make_invalid_config_release/1, - make_relup_release/1, - make_relup_release2/1, - make_one_app_top_level_release/1]). - --include_lib("common_test/include/ct.hrl"). --include_lib("eunit/include/eunit.hrl"). --include_lib("kernel/include/file.hrl"). --include_lib("kernel/include/file.hrl"). - -suite() -> - [{timetrap,{seconds,30}}]. - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -init_per_testcase(_, Config) -> - DataDir = proplists:get_value(data_dir, Config), - LibDir1 = filename:join([DataDir, create_random_name("lib_dir1_")]), - ok = rcl_util:mkdir_p(LibDir1), - State = rcl_state:new([{lib_dirs, [LibDir1]}], release), - [{lib1, LibDir1}, - {state, State} | Config]. - -all() -> - [make_release, make_scriptless_release, make_overridden_release, - make_skip_app_release, - make_implicit_config_release, make_rerun_overridden_release, - overlay_release, make_goalless_release, make_depfree_release, - make_invalid_config_release, make_relup_release, make_relup_release2, - make_one_app_top_level_release]. - -make_release(Config) -> - LibDir1 = proplists:get_value(lib1, Config), - [(fun({Name, Vsn}) -> - create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) - end)(App) - || - App <- - [{create_random_name("lib_app1_"), create_random_vsn()} - || _ <- lists:seq(1, 100)]], - - create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), - create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []), - create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), - create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), - create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), - - ConfigFile = filename:join([LibDir1, "relcool.config"]), - write_config(ConfigFile, - [{release, {foo, "0.0.1"}, - [goal_app_1, - goal_app_2]}]), - OutputDir = filename:join([proplists:get_value(data_dir, Config), - create_random_name("relcool-output")]), - {ok, State} = relcool:do(undefined, undefined, [], [LibDir1], 2, - OutputDir, ConfigFile), - [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rcl_state:realized_releases(State)), - AppSpecs = rcl_release:applications(Release), - ?assert(lists:keymember(stdlib, 1, AppSpecs)), - ?assert(lists:keymember(kernel, 1, AppSpecs)), - ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)), - ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)), - ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)), - ?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)), - ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)). - -make_invalid_config_release(Config) -> - LibDir1 = proplists:get_value(lib1, Config), - [(fun({Name, Vsn}) -> - create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) - end)(App) - || - App <- - [{create_random_name("lib_app1_"), create_random_vsn()} - || _ <- lists:seq(1, 100)]], - - create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), - create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []), - create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), - create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), - create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), - - ConfigFile = filename:join([LibDir1, "relcool.config"]), - ok = ec_file:write(ConfigFile, - "{release, {foo, \"0.0.1\"}, - [goal_app_1, - goal_app_2,]}"), - OutputDir = filename:join([proplists:get_value(data_dir, Config), - create_random_name("relcool-output")]), - {error, {rcl_prv_config, - {consult, _, _}}} = relcool:do(undefined, undefined, [], [LibDir1], 2, - OutputDir, ConfigFile). - -make_scriptless_release(Config) -> - LibDir1 = proplists:get_value(lib1, Config), - [(fun({Name, Vsn}) -> - create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) - end)(App) - || - App <- - [{create_random_name("lib_app1_"), create_random_vsn()} - || _ <- lists:seq(1, 100)]], - - create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), - create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []), - create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), - create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), - create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), - - ConfigFile = filename:join([LibDir1, "relcool.config"]), - write_config(ConfigFile, - [{generate_start_script, false}, - {release, {foo, "0.0.1"}, - [goal_app_1, - goal_app_2]}]), - OutputDir = filename:join([proplists:get_value(data_dir, Config), - create_random_name("relcool-output")]), - {ok, State} = relcool:do(undefined, undefined, [], [LibDir1], 2, - OutputDir, ConfigFile), - - ?assert(not ec_file:exists(filename:join([OutputDir, "bin", "foo"]))), - ?assert(not ec_file:exists(filename:join([OutputDir, "bin", "foo-0.0.1"]))), - - [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rcl_state:realized_releases(State)), - AppSpecs = rcl_release:applications(Release), - ?assert(lists:keymember(stdlib, 1, AppSpecs)), - ?assert(lists:keymember(kernel, 1, AppSpecs)), - ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)), - ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)), - ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)), - ?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)), - ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)). - - -make_overridden_release(Config) -> - DataDir = proplists:get_value(data_dir, Config), - OverrideDir1 = filename:join([DataDir, create_random_name("override_dir_")]), - LibDir1 = proplists:get_value(lib1, Config), - [(fun({Name, Vsn}) -> - create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) - end)(App) - || - App <- - [{create_random_name("lib_app1_"), create_random_vsn()} - || _ <- lists:seq(1, 100)]], - OverrideApp = create_random_name("override_app"), - OverrideVsn = create_random_vsn(), - OverrideAppDir = filename:join(OverrideDir1, OverrideApp ++ "-" ++ OverrideVsn), - OverrideAppName = erlang:list_to_atom(OverrideApp), - - create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), - create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []), - create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), - create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), - create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), - - create_app(OverrideDir1, OverrideApp, OverrideVsn, [stdlib,kernel], []), - - ConfigFile = filename:join([LibDir1, "relcool.config"]), - write_config(ConfigFile, - [{release, {foo, "0.0.1"}, - [goal_app_1, - erlang:list_to_atom(OverrideApp), - goal_app_2]}]), - OutputDir = filename:join([proplists:get_value(data_dir, Config), - create_random_name("relcool-output")]), - {ok, Cwd} = file:get_cwd(), - {ok, State} = relcool:do(Cwd, undefined, undefined, [], [LibDir1], 2, - OutputDir, [{OverrideAppName, OverrideAppDir}], - ConfigFile), - [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rcl_state:realized_releases(State)), - AppSpecs = rcl_release:applications(Release), - ?assert(lists:keymember(stdlib, 1, AppSpecs)), - ?assert(lists:keymember(kernel, 1, AppSpecs)), - ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)), - ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)), - ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)), - ?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)), - ?assert(lists:member({OverrideAppName, OverrideVsn}, AppSpecs)), - ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)), - {ok, Real} = file:read_link(filename:join([OutputDir, "lib", - OverrideApp ++ "-" ++ OverrideVsn])), - ?assertMatch(OverrideAppDir, Real). - -make_skip_app_release(Config) -> - DataDir = proplists:get_value(data_dir, Config), - SkipAppDir1 = filename:join([DataDir, create_random_name("skip_app_dir_")]), - LibDir1 = proplists:get_value(lib1, Config), - [(fun({Name, Vsn}) -> - create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) - end)(App) - || - App <- - [{create_random_name("lib_app1_"), create_random_vsn()} - || _ <- lists:seq(1, 100)]], - SkipAppApp = create_random_name("skip_app_app"), - SkipAppVsn = create_random_vsn(), - SkipAppAppName = erlang:list_to_atom(SkipAppApp), - - create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), - create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []), - create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), - create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), - create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), - - create_empty_app(SkipAppDir1, SkipAppApp, SkipAppVsn, [stdlib,kernel], []), - - ConfigFile = filename:join([LibDir1, "relcool.config"]), - write_config(ConfigFile, - [{release, {foo, "0.0.1"}, - [goal_app_1, - goal_app_2]}, - {skip_apps, [erlang:list_to_atom(SkipAppApp)]}]), - OutputDir = filename:join([proplists:get_value(data_dir, Config), - create_random_name("relcool-output")]), - {ok, Cwd} = file:get_cwd(), - {ok, State} = relcool:do(Cwd, undefined, undefined, [], [LibDir1], 2, - OutputDir, [], - ConfigFile), - [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rcl_state:realized_releases(State)), - AppSpecs = rcl_release:applications(Release), - ?assert(lists:keymember(stdlib, 1, AppSpecs)), - ?assert(lists:keymember(kernel, 1, AppSpecs)), - ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)), - ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)), - ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)), - ?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)), - ?assertNot(lists:member({SkipAppAppName, SkipAppVsn}, AppSpecs)), - ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)). - -make_implicit_config_release(Config) -> - LibDir1 = proplists:get_value(lib1, Config), - FooRoot = filename:join([LibDir1, "foodir1", "foodir2"]), - filelib:ensure_dir(filename:join([FooRoot, "tmp"])), - [(fun({Name, Vsn}) -> - create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) - end)(App) - || - App <- - [{create_random_name("lib_app1_"), create_random_vsn()} - || _ <- lists:seq(1, 100)]], - - create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), - create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []), - create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), - create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), - create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), - - ConfigFile = filename:join([LibDir1, "relcool.config"]), - write_config(ConfigFile, - [{release, {foo, "0.0.1"}, - [goal_app_1, - goal_app_2]}]), - OutputDir = filename:join([proplists:get_value(data_dir, Config), - create_random_name("relcool-output")]), - ok = file:set_cwd(FooRoot), - {ok, FooRoot} = file:get_cwd(), - {ok, State} = relcool:do(undefined, undefined, [], [LibDir1], 2, - OutputDir, undefined), - [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rcl_state:realized_releases(State)), - ?assert(ec_file:exists(OutputDir)), - AppSpecs = rcl_release:applications(Release), - ?assert(lists:keymember(stdlib, 1, AppSpecs)), - ?assert(lists:keymember(kernel, 1, AppSpecs)), - ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)), - ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)), - ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)), - ?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)), - ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)). - -make_rerun_overridden_release(Config) -> - DataDir = proplists:get_value(data_dir, Config), - OverrideDir1 = filename:join([DataDir, create_random_name("override_dir_")]), - LibDir1 = proplists:get_value(lib1, Config), - [(fun({Name, Vsn}) -> - create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) - end)(App) - || - App <- - [{create_random_name("lib_app1_"), create_random_vsn()} - || _ <- lists:seq(1, 100)]], - OverrideApp = create_random_name("override_app"), - OverrideVsn = create_random_vsn(), - OverrideAppDir = filename:join(OverrideDir1, OverrideApp ++ "-" - ++ OverrideVsn), - OverrideAppName = erlang:list_to_atom(OverrideApp), - - create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), - create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []), - create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), - create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), - create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), - - create_app(OverrideDir1, OverrideApp, OverrideVsn, [stdlib,kernel], []), - - ConfigFile = filename:join([LibDir1, "relcool.config"]), - write_config(ConfigFile, - [{release, {foo, "0.0.1"}, - [goal_app_1, - erlang:list_to_atom(OverrideApp), - goal_app_2]}]), - OutputDir = filename:join([proplists:get_value(data_dir, Config), - create_random_name("relcool-output")]), - {ok, Cwd} = file:get_cwd(), - {ok, _} = relcool:do(Cwd, undefined, undefined, [], [LibDir1], 2, - OutputDir, [{OverrideAppName, OverrideAppDir}], - ConfigFile), - - %% Now we run it again to see if it fails. - {ok, State} = relcool:do(Cwd,undefined, undefined, [], [LibDir1], 2, - OutputDir, [{OverrideAppName, OverrideAppDir}], - ConfigFile), - - [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rcl_state:realized_releases(State)), - AppSpecs = rcl_release:applications(Release), - ?assert(lists:keymember(stdlib, 1, AppSpecs)), - ?assert(lists:keymember(kernel, 1, AppSpecs)), - ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)), - ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)), - ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)), - ?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)), - ?assert(lists:member({OverrideAppName, OverrideVsn}, AppSpecs)), - ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)), - {ok, Real} = file:read_link(filename:join([OutputDir, "lib", - OverrideApp ++ "-" ++ OverrideVsn])), - ?assertMatch(OverrideAppDir, Real). - -overlay_release(Config) -> - LibDir1 = proplists:get_value(lib1, Config), - [(fun({Name, Vsn}) -> - create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) - end)(App) - || - App <- - [{create_random_name("lib_app1_"), create_random_vsn()} - || _ <- lists:seq(1, 100)]], - - create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), - create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []), - create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), - create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), - create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), - - ConfigFile = filename:join([LibDir1, "relcool.config"]), - OverlayVars = filename:join([LibDir1, "vars.config"]), - Template = filename:join([LibDir1, "test_template"]), - write_config(ConfigFile, - [{overlay_vars, OverlayVars}, - {overlay, [{mkdir, "{{target_dir}}/fooo"}, - {copy, OverlayVars, - "{{target_dir}}/{{foo_dir}}/vars.config"}, - {copy, OverlayVars, - "{{target_dir}}/{{yahoo}}/"}, - {template, Template, - "{{target_dir}}/test_template_resolved"}]}, - {release, {foo, "0.0.1"}, - [goal_app_1, - goal_app_2]}]), - - VarsFile = filename:join([LibDir1, "vars.config"]), - write_config(VarsFile, [{yahoo, "yahoo"}, - {yahoo2, [{foo, "bar"}]}, - {yahoo3, [{bar, "{{yahoo}}/{{yahoo2.foo}}"}]}, - {foo_dir, "foodir"}]), - - TemplateFile = filename:join([LibDir1, "test_template"]), - ok = file:write_file(TemplateFile, test_template_contents()), - {ok, FileInfo} = file:read_file_info(TemplateFile), - ok = file:write_file_info(TemplateFile, FileInfo#file_info{mode=8#00777}), - - OutputDir = filename:join([proplists:get_value(data_dir, Config), - create_random_name("relcool-output")]), - - {ok, State} = relcool:do(undefined, undefined, [], [LibDir1], 2, - OutputDir, ConfigFile), - - [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rcl_state:realized_releases(State)), - AppSpecs = rcl_release:applications(Release), - ?assert(lists:keymember(stdlib, 1, AppSpecs)), - ?assert(lists:keymember(kernel, 1, AppSpecs)), - ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)), - ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)), - ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)), - ?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)), - ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)), - - ?assert(ec_file:exists(filename:join(OutputDir, "fooo"))), - ?assert(ec_file:exists(filename:join([OutputDir, "foodir", "vars.config"]))), - ?assert(ec_file:exists(filename:join([OutputDir, "yahoo", "vars.config"]))), - - TemplateData = case file:consult(filename:join([OutputDir, "test_template_resolved"])) of - {ok, Details} -> - Details; - Error -> - erlang:throw({failed_to_consult, Error}) - end, - {ok, ReadFileInfo} = file:read_file_info(filename:join([OutputDir, "test_template_resolved"])), - ?assertEqual(8#100777, ReadFileInfo#file_info.mode), - - ?assertEqual(erlang:system_info(version), - proplists:get_value(erts_vsn, TemplateData)), - ?assertEqual(erlang:system_info(version), - proplists:get_value(release_erts_version, TemplateData)), - ?assertEqual("0.0.1", - proplists:get_value(release_version, TemplateData)), - ?assertEqual(foo, - proplists:get_value(release_name, TemplateData)), - ?assertEqual([kernel,stdlib,lib_dep_1,non_goal_2,non_goal_1, - goal_app_1,goal_app_2], - proplists:get_value(release_applications, TemplateData)), - ?assert(proplists:is_defined(std_version, TemplateData)), - ?assert(proplists:is_defined(kernel_version, TemplateData)), - ?assertEqual("0.0.1", - proplists:get_value(non_goal_1_version, TemplateData)), - ?assertEqual("0.0.1", - proplists:get_value(non_goal_2_version, TemplateData)), - ?assertEqual("0.0.1", - proplists:get_value(goal_app_1_version, TemplateData)), - ?assertEqual("0.0.1", - proplists:get_value(goal_app_2_version, TemplateData)), - ?assertEqual("0.0.1", - proplists:get_value(lib_dep_1, TemplateData)), - ?assert(proplists:is_defined(lib_dep_1_dir, TemplateData)), - ?assertEqual([stdlib,kernel], - proplists:get_value(lib_dep_1_active, TemplateData)), - ?assertEqual([], - proplists:get_value(lib_dep_1_library, TemplateData)), - ?assertEqual("false", - proplists:get_value(lib_dep_1_link, TemplateData)), - ?assertEqual("(2:debug)", - proplists:get_value(log, TemplateData)), - ?assertEqual(OutputDir, - proplists:get_value(output_dir, TemplateData)), - ?assertEqual(OutputDir, - proplists:get_value(target_dir, TemplateData)), - ?assertEqual([], - proplists:get_value(overridden, TemplateData)), - ?assertEqual([""], - proplists:get_value(goals, TemplateData)), - ?assert(proplists:is_defined(lib_dirs, TemplateData)), - ?assert(proplists:is_defined(config_file, TemplateData)), - ?assertEqual([""], - proplists:get_value(goals, TemplateData)), - ?assertEqual([], - proplists:get_value(sys_config, TemplateData)), - ?assert(proplists:is_defined(root_dir, TemplateData)), - ?assertEqual(foo, - proplists:get_value(default_release_name, TemplateData)), - ?assertEqual("0.0.1", - proplists:get_value(default_release_version, TemplateData)), - ?assertEqual("foo-0.0.1", - proplists:get_value(default_release, TemplateData)), - ?assertEqual("yahoo", - proplists:get_value(yahoo, TemplateData)), - ?assertEqual("bar", - proplists:get_value(yahoo2_foo, TemplateData)), - ?assertEqual("foodir", - proplists:get_value(foo_dir, TemplateData)), - ?assertEqual("yahoo/bar", - proplists:get_value(yahoo3, TemplateData)). - -make_goalless_release(Config) -> - LibDir1 = proplists:get_value(lib1, Config), - [(fun({Name, Vsn}) -> - create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) - end)(App) - || - App <- - [{create_random_name("lib_app1_"), create_random_vsn()} - || _ <- lists:seq(1, 100)]], - - create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), - create_app(LibDir1, "lib_dep_1", "0.0.1", [], []), - create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), - create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), - create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), - - ConfigFile = filename:join([LibDir1, "relcool.config"]), - write_config(ConfigFile, - [{release, {foo, "0.0.1"}, - []}]), - OutputDir = filename:join([proplists:get_value(data_dir, Config), - create_random_name("relcool-output")]), - ?assertMatch({error,{rcl_prv_release,no_goals_specified}}, - relcool:do(undefined, undefined, [], [LibDir1], 2, - OutputDir, ConfigFile)). - -make_depfree_release(Config) -> - LibDir1 = proplists:get_value(lib1, Config), - [(fun({Name, Vsn}) -> - create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) - end)(App) - || - App <- - [{create_random_name("lib_app1_"), create_random_vsn()} - || _ <- lists:seq(1, 100)]], - - create_app(LibDir1, "goal_app_1", "0.0.1", [kernel,stdlib], []), - create_app(LibDir1, "lib_dep_1", "0.0.1", [kernel,stdlib], []), - create_app(LibDir1, "goal_app_2", "0.0.1", [kernel,stdlib], []), - create_app(LibDir1, "non_goal_1", "0.0.1", [kernel,stdlib], []), - create_app(LibDir1, "non_goal_2", "0.0.1", [kernel,stdlib], []), - - ConfigFile = filename:join([LibDir1, "relcool.config"]), - write_config(ConfigFile, - [{release, {foo, "0.0.1"}, - [goal_app_1]}]), - OutputDir = filename:join([proplists:get_value(data_dir, Config), - create_random_name("relcool-output")]), - {ok, State} = relcool:do(undefined, undefined, [], [LibDir1], 2, - OutputDir, ConfigFile), - [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rcl_state:realized_releases(State)), - AppSpecs = rcl_release:applications(Release), - ?assert(lists:keymember(stdlib, 1, AppSpecs)), - ?assert(lists:keymember(kernel, 1, AppSpecs)). - -make_relup_release(Config) -> - LibDir1 = proplists:get_value(lib1, Config), - [(fun({Name, Vsn}) -> - create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) - end)(App) - || - App <- - [{create_random_name("lib_app1_"), create_random_vsn()} - || _ <- lists:seq(1, 100)]], - - create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), - create_app(LibDir1, "goal_app_1", "0.0.2", [stdlib,kernel,non_goal_1], []), - {ok, GA1} = create_app(LibDir1, "goal_app_1", "0.0.3", [stdlib,kernel,non_goal_1], []), - create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []), - create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), - create_app(LibDir1, "goal_app_2", "0.0.2", [stdlib,kernel,goal_app_1,non_goal_2], []), - {ok, GA2} = create_app(LibDir1, "goal_app_2", "0.0.3", [stdlib,kernel,goal_app_1,non_goal_2], []), - create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), - create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), - - write_appup_file(GA1, "0.0.2"), - write_appup_file(GA2, "0.0.2"), - - ConfigFile = filename:join([LibDir1, "relcool.config"]), - write_config(ConfigFile, - [{release, {foo, "0.0.1"}, - [sasl, - {goal_app_1, "0.0.1"}, - {goal_app_2, "0.0.1"}]}, - {release, {foo, "0.0.2"}, - [sasl, - {goal_app_1, "0.0.2"}, - {goal_app_2, "0.0.2"}]}, - {release, {foo, "0.0.3"}, - [sasl, - {goal_app_1, "0.0.3"}, - {goal_app_2, "0.0.3"}]}]), - OutputDir = filename:join([proplists:get_value(data_dir, Config), - create_random_name("relcool-output")]), - {ok, _} = relcool:do(foo, "0.0.1", [], [LibDir1], 2, - OutputDir, ConfigFile), - {ok, _} = relcool:do(foo, "0.0.2", [], [LibDir1], 2, - OutputDir, ConfigFile), - {ok, State} = relcool:do([{relname, foo}, - {relvsn, "0.0.3"}, - {goals, []}, - {lib_dirs, [LibDir1]}, - {log_level, 2}, - {output_dir, OutputDir}, - {config, ConfigFile}], ["relup"]), - - %% we should have one 'resolved' release and three discovered realized_releases. - ?assertMatch([{foo, "0.0.1"}, - {foo, "0.0.2"}, - {foo, "0.0.3"}], - lists:sort(ec_dictionary:keys(rcl_state:realized_releases(State)))), - Release = ec_dictionary:get({foo, "0.0.3"}, rcl_state:realized_releases(State)), - ?assert(rcl_release:realized(Release)), - ?assert(not rcl_release:realized(ec_dictionary:get({foo, "0.0.2"}, - rcl_state:realized_releases(State)))), - ?assert(not rcl_release:realized(ec_dictionary:get({foo, "0.0.1"}, - rcl_state:realized_releases(State)))), - - ?assertMatch({ok, [{"0.0.3", - [{"0.0.2",[],[point_of_no_return]}], - [{"0.0.2",[],[point_of_no_return]}]}]}, - file:consult(filename:join(filename:dirname(rcl_release:relfile(Release)), - filename:basename(rcl_release:relfile(Release), ".rel") ++ - ".relup"))), - - ?assertMatch(foo, rcl_release:name(Release)), - ?assertMatch("0.0.3", rcl_release:vsn(Release)), - AppSpecs = rcl_release:applications(Release), - ?assert(lists:keymember(stdlib, 1, AppSpecs)), - ?assert(lists:keymember(kernel, 1, AppSpecs)), - ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)), - ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)), - ?assert(lists:member({goal_app_1, "0.0.3"}, AppSpecs)), - ?assert(lists:member({goal_app_2, "0.0.3"}, AppSpecs)), - ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)). - - -make_relup_release2(Config) -> - LibDir1 = proplists:get_value(lib1, Config), - [(fun({Name, Vsn}) -> - create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) - end)(App) - || - App <- - [{create_random_name("lib_app1_"), create_random_vsn()} - || _ <- lists:seq(1, 100)]], - - create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), - create_app(LibDir1, "goal_app_1", "0.0.2", [stdlib,kernel,non_goal_1], []), - {ok, GA1} = create_app(LibDir1, "goal_app_1", "0.0.3", [stdlib,kernel,non_goal_1], []), - create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []), - create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), - create_app(LibDir1, "goal_app_2", "0.0.2", [stdlib,kernel,goal_app_1,non_goal_2], []), - {ok, GA2} = create_app(LibDir1, "goal_app_2", "0.0.3", [stdlib,kernel,goal_app_1,non_goal_2], []), - create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), - create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), - - write_appup_file(GA1, "0.0.1"), - write_appup_file(GA2, "0.0.1"), - - ConfigFile = filename:join([LibDir1, "relcool.config"]), - write_config(ConfigFile, - [{release, {foo, "0.0.1"}, - [sasl, - {goal_app_1, "0.0.1"}, - {goal_app_2, "0.0.1"}]}, - {release, {foo, "0.0.2"}, - [sasl, - {goal_app_1, "0.0.2"}, - {goal_app_2, "0.0.2"}]}, - {release, {foo, "0.0.3"}, - [sasl, - {goal_app_1, "0.0.3"}, - {goal_app_2, "0.0.3"}]}]), - OutputDir = filename:join([proplists:get_value(data_dir, Config), - create_random_name("relcool-output")]), - {ok, _} = relcool:do(foo, "0.0.1", [], [LibDir1], 2, - OutputDir, ConfigFile), - {ok, _} = relcool:do(foo, "0.0.2", [], [LibDir1], 2, - OutputDir, ConfigFile), - {ok, State} = relcool:do([{relname, foo}, - {relvsn, "0.0.3"}, - {upfrom, "0.0.1"}, - {goals, []}, - {lib_dirs, [LibDir1]}, - {log_level, 2}, - {output_dir, OutputDir}, - {config, ConfigFile}], ["relup"]), - - %% we should have one 'resolved' release and three discovered realized_releases. - ?assertMatch([{foo, "0.0.1"}, - {foo, "0.0.2"}, - {foo, "0.0.3"}], - lists:sort(ec_dictionary:keys(rcl_state:realized_releases(State)))), - Release = ec_dictionary:get({foo, "0.0.3"}, rcl_state:realized_releases(State)), - ?assert(rcl_release:realized(Release)), - ?assert(not rcl_release:realized(ec_dictionary:get({foo, "0.0.2"}, - rcl_state:realized_releases(State)))), - ?assert(not rcl_release:realized(ec_dictionary:get({foo, "0.0.1"}, - rcl_state:realized_releases(State)))), - - ?assertMatch({ok, [{"0.0.3", - [{"0.0.1",[],[point_of_no_return]}], - [{"0.0.1",[],[point_of_no_return]}]}]}, - file:consult(filename:join(filename:dirname(rcl_release:relfile(Release)), - filename:basename(rcl_release:relfile(Release), ".rel") ++ - ".relup"))), - - ?assertMatch(foo, rcl_release:name(Release)), - ?assertMatch("0.0.3", rcl_release:vsn(Release)), - AppSpecs = rcl_release:applications(Release), - ?assert(lists:keymember(stdlib, 1, AppSpecs)), - ?assert(lists:keymember(kernel, 1, AppSpecs)), - ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)), - ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)), - ?assert(lists:member({goal_app_1, "0.0.3"}, AppSpecs)), - ?assert(lists:member({goal_app_2, "0.0.3"}, AppSpecs)), - ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)). - - -make_one_app_top_level_release(Config) -> - LibDir1 = proplists:get_value(lib1, Config), - {ok, AppInfo} = create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel], []), - AppDir = rcl_app_info:dir(AppInfo), - ConfigFile = filename:join([AppDir, "relcool.config"]), - write_config(ConfigFile, - [{release, {foo, "0.0.1"}, - [{goal_app_1, "0.0.1"}]}]), - - OutputDir = filename:join([AppDir, - create_random_name("relcool-output")]), - - {ok, Cwd} = file:get_cwd(), - ok = file:set_cwd(AppDir), - {ok, State} = relcool:do(undefined, undefined, [], [], 2, - OutputDir, ConfigFile), - ok = file:set_cwd(Cwd), - [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rcl_state:realized_releases(State)), - AppSpecs = rcl_release:applications(Release), - ?assert(lists:keymember(stdlib, 1, AppSpecs)), - ?assert(lists:keymember(kernel, 1, AppSpecs)), - ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)). - - -%%%=================================================================== -%%% Helper Functions -%%%=================================================================== - -create_app(Dir, Name, Vsn, Deps, LibDeps) -> - AppDir = filename:join([Dir, Name ++ "-" ++ Vsn]), - write_app_file(AppDir, Name, Vsn, Deps, LibDeps), - write_beam_file(AppDir, Name), - rcl_app_info:new(erlang:list_to_atom(Name), Vsn, AppDir, - Deps, []). - -create_empty_app(Dir, Name, Vsn, Deps, LibDeps) -> - AppDir = filename:join([Dir, Name ++ "-" ++ Vsn]), - write_app_file(AppDir, Name, Vsn, Deps, LibDeps), - rcl_app_info:new(erlang:list_to_atom(Name), Vsn, AppDir, - Deps, []). - -write_beam_file(Dir, Name) -> - Beam = filename:join([Dir, "ebin", "not_a_real_beam" ++ Name ++ ".beam"]), - ok = filelib:ensure_dir(Beam), - ok = ec_file:write_term(Beam, testing_purposes_only). - -write_appup_file(AppInfo, DownVsn) -> - Dir = rcl_app_info:dir(AppInfo), - Name = rcl_util:to_string(rcl_app_info:name(AppInfo)), - Vsn = rcl_app_info:vsn_as_string(AppInfo), - Filename = filename:join([Dir, "ebin", Name ++ ".appup"]), - ok = filelib:ensure_dir(Filename), - ok = ec_file:write_term(Filename, {Vsn, [{DownVsn, []}], [{DownVsn, []}]}). - -write_app_file(Dir, Name, Version, Deps, LibDeps) -> - Filename = filename:join([Dir, "ebin", Name ++ ".app"]), - ok = filelib:ensure_dir(Filename), - ok = ec_file:write_term(Filename, get_app_metadata(Name, Version, Deps, LibDeps)). - -get_app_metadata(Name, Vsn, Deps, LibDeps) -> - {application, erlang:list_to_atom(Name), - [{description, ""}, - {vsn, Vsn}, - {modules, []}, - {included_applications, LibDeps}, - {registered, []}, - {applications, Deps}]}. - -create_random_name(Name) -> - random:seed(erlang:now()), - Name ++ erlang:integer_to_list(random:uniform(1000000)). - -create_random_vsn() -> - random:seed(erlang:now()), - lists:flatten([erlang:integer_to_list(random:uniform(100)), - ".", erlang:integer_to_list(random:uniform(100)), - ".", erlang:integer_to_list(random:uniform(100))]). - -write_config(Filename, Values) -> - ok = ec_file:write(Filename, - [io_lib:format("~p.\n", [Val]) || Val <- Values]). - -test_template_contents() -> - "{erts_vsn, \"{{erts_vsn}}\"}.\n" - "{release_erts_version, \"{{release_erts_version}}\"}.\n" - "{release_name, {{release_name}}}.\n" - "{rel_vsn, \"{{release_version}}\"}.\n" - "{release_version, \"{{release_version}}\"}.\n" - "{release_applications, [{{ release_applications|join:\", \" }}]}.\n" - "{std_version, \"{{release.stdlib.version}}\"}.\n" - "{kernel_version, \"{{release.kernel.version}}\"}.\n" - "{non_goal_1_version, \"{{release.non_goal_1.version}}\"}.\n" - "{non_goal_2_version, \"{{release.non_goal_2.version}}\"}.\n" - "{goal_app_1_version, \"{{release.goal_app_1.version}}\"}.\n" - "{goal_app_2_version, \"{{release.goal_app_2.version}}\"}.\n" - "{lib_dep_1, \"{{release.lib_dep_1.version}}\"}.\n" - "{lib_dep_1_dir, \"{{release.lib_dep_1.dir}}\"}.\n" - "{lib_dep_1_active, [{{ release.lib_dep_1.active_dependencies|join:\", \" }}]}.\n" - "{lib_dep_1_library, [{{ release.lib_dep_1.library_dependencies|join:\", \" }}]}.\n" - "{lib_dep_1_link, \"{{release.lib_dep_1.link}}\"}.\n" - "{log, \"{{log}}\"}.\n" - "{output_dir, \"{{output_dir}}\"}.\n" - "{target_dir, \"{{target_dir}}\"}.\n" - "{overridden, [{{ overridden|join:\", \" }}]}.\n" - "{goals, [\"{{ goals|join:\", \" }}\"]}.\n" - "{lib_dirs, [\"{{ lib_dirs|join:\", \" }}\"]}.\n" - "{config_file, \"{{ config_file }}\"}.\n" - "{providers, [{{ providers|join:\", \" }}]}.\n" - "{sys_config, \"{{sys_config}}\"}.\n" - "{root_dir, \"{{root_dir}}\"}.\n" - "{default_release_name, {{default_release_name}}}.\n" - "{default_release_version, \"{{default_release_version}}\"}.\n" - "{default_release, \"{{default_release}}\"}.\n" - "{yahoo, \"{{yahoo}}\"}.\n" - "{yahoo2_foo, \"{{yahoo2.foo}}\"}.\n" - "{foo_dir, \"{{foo_dir}}\"}.\n" - "{yahoo3, \"{{yahoo3.bar}}\"}.\n". diff --git a/test/rlx_command_SUITE.erl b/test/rlx_command_SUITE.erl new file mode 100644 index 0000000..05da548 --- /dev/null +++ b/test/rlx_command_SUITE.erl @@ -0,0 +1,97 @@ +%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 92 -*- +%%% Copyright 2012 Erlware, LLC. All Rights Reserved. +%%% +%%% This file is provided to you under the Apache License, +%%% Version 2.0 (the "License"); you may not use this file +%%% except in compliance with the License. You may obtain +%%% a copy of the License at +%%% +%%% http://www.apache.org/licenses/LICENSE-2.0 +%%% +%%% Unless required by applicable law or agreed to in writing, +%%% software distributed under the License is distributed on an +%%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +%%% KIND, either express or implied. See the License for the +%%% specific language governing permissions and limitations +%%% under the License. +%%%------------------------------------------------------------------- +%%% @author Eric Merrit +%%% @copyright (C) 2012, Eric Merrit +-module(rclt_command_SUITE). + +-export([suite/0, + init_per_suite/1, + end_per_suite/1, + all/0, + normal_passing_case/1, + lib_fail_case/1, + spec_parse_fail_case/1, + config_fail_case/1]). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). + +suite() -> + [{timetrap,{seconds,30}}]. + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +all() -> + [normal_passing_case, lib_fail_case, config_fail_case]. + +normal_passing_case(Config) -> + DataDir = proplists:get_value(data_dir, Config), + Lib1 = filename:join([DataDir, <<"lib1">>]), + Lib2 = filename:join([DataDir, <<"lib2">>]), + Outdir = filename:join([DataDir, "outdir"]), + ok = rcl_util:mkdir_p(Lib1), + ok = rcl_util:mkdir_p(Lib2), + Goal1 = "app1<=33.33+build4", + Goal2 = "app2:btwn:33.22,45.22+build.21", + + LogLevel = "2", + RelName = "foo-release", + RelVsn = "33.222", + CmdLine = ["-V", LogLevel, "-g",Goal1,"-g",Goal2, "-l", Lib1, "-l", Lib2, + "-n", RelName, "-v", RelVsn, "-o", Outdir], + {ok, {Opts, Targets}} = getopt:parse(relcool:opt_spec_list(), CmdLine), + {ok, State} = rcl_cmd_args:args2state(Opts, Targets), + ?assertMatch([Lib1, Lib2], + rcl_state:lib_dirs(State)), + ?assertMatch(Outdir, rcl_state:output_dir(State)), + + ?assertMatch([{app1,{{33,33},{[],[<<"build4">>]}},lte}, + {app2, + {{33,22},{[],[]}}, + {{45,22},{[],[<<"build">>,21]}}, between}], + rcl_state:goals(State)). + + +lib_fail_case(Config) -> + DataDir = proplists:get_value(data_dir, Config), + Lib1 = filename:join([DataDir, "lib1"]), + Lib2 = filename:join([DataDir, "lib3333"]), + ok = rcl_util:mkdir_p(Lib1), + + CmdLine = ["-l", Lib1, "-l", Lib2], + {ok, {Opts, Targets}} = getopt:parse(relcool:opt_spec_list(), CmdLine), + ?assertMatch({error, {_, {not_directory, Lib2}}}, + rcl_cmd_args:args2state(Opts, Targets)). + +spec_parse_fail_case(_Config) -> + Spec = "aaeu:3333:33.22a44", + CmdLine = ["-g", Spec], + {ok, {Opts, Targets}} = getopt:parse(relcool:opt_spec_list(), CmdLine), + ?assertMatch({error, {_, {failed_to_parse, _Spec}}}, + rcl_cmd_args:args2state(Opts, Targets)). + +config_fail_case(_Config) -> + ConfigFile = "does-not-exist", + CmdLine = ["-c", ConfigFile], + {ok, {Opts, Targets}} = getopt:parse(relcool:opt_spec_list(), CmdLine), + ?assertMatch({error, {_, {invalid_config_file, ConfigFile}}}, + rcl_cmd_args:args2state(Opts, Targets)). diff --git a/test/rlx_depsolver_tester.erl b/test/rlx_depsolver_tester.erl new file mode 100644 index 0000000..53f5ac0 --- /dev/null +++ b/test/rlx_depsolver_tester.erl @@ -0,0 +1,474 @@ +%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 92 -*- +%% ex: ts=4 sx=4 et +%%------------------------------------------------------------------- +%% +%% Copyright 2012 Opscode, Inc. All Rights Reserved. +%% +%% This file is provided to you under the Apache License, +%% Version 2.0 (the "License"); you may not use this file +%% except in compliance with the License. You may obtain +%% a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, +%% software distributed under the License is distributed on an +%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +%% KIND, either express or implied. See the License for the +%% specific language governing permissions and limitations +%% under the License. +%% +%% @author Eric Merritt +%% @doc +%% Additional testing for depsolver +%% @end +%%------------------------------------------------------------------- +-module(rcl_depsolver_tester). + +-export([run_data/1, run_log/1]). +-include_lib("eunit/include/eunit.hrl"). + +-define(ADD_PKG, "^DepSelector\\sinst#\\s(\\d+)\\s-\\s" + "Adding\\spackage\\sid\\s(\\d+)\\/(\\d+):\\smin\\s=\\s-1," + "\\smax\\s=\\s(\\d+),\\scurrent\\sversion\\s0$"). +-define(ADD_VC, "^DepSelector\\sinst#\\s(\\d+)\\s-\\sAdding\\sVC\\s" + "for\\s(\\d+)\\s@\\s(\\d+)\\sdepPkg\\s(\\d+)\\s\\[\\s(\\d+)" + "\\s(\\d+)\\s\\]$"). +-define(ADD_GOAL, "^DepSelector\\sinst#\\s(\\d+)\\s-\\s" + "Marking\\sPackage\\sRequired\\s(\\d+)$"). + +%%============================================================================ +%% Public Api +%%============================================================================ +run_data(FileName) -> + {ok, Device} = file:open(FileName, [read]), + run_data_file(Device). + +run_log(FileName) -> + {ok, Device} = file:open(FileName, [read]), + run_log_file(Device). + +data1_test() -> + ExpectedResult = versionify([{"app6","0.0.1"}, + {"dep_pkg13","0.0.2"}, + {"app13","0.0.1"}, + {"dep_pkg2","0.0.5"}, + {"dep_pkg1","0.0.2"}, + {"dep_pkg7","0.1.2"}, + {"app9","0.0.1"}]), + ?assertMatch({ok, ExpectedResult}, + run_data(fix_rebar_brokenness("data1.txt"))). + +data2_test() -> + ExpectedResult = versionify([{"app18","0.0.1"}, + {"app4","0.0.1"}, + {"app1","0.0.1"}, + {"app6","0.0.1"}, + {"dep_pkg13","0.0.2"}, + {"app13","0.0.1"}, + {"dep_pkg5","0.0.2"}, + {"dep_pkg1","0.0.2"}, + {"dep_pkg2","0.0.5"}, + {"dep_pkg7","0.1.2"}, + {"app9","0.0.1"}, + {"dep_pkg16","1.0.2"}]), + ?assertMatch({ok, ExpectedResult}, + run_data(fix_rebar_brokenness("data2.txt"))). + +data3_test() -> + ExpectedResult = versionify([{"app68","0.0.1"}, + {"app58","0.0.1"}, + {"app48","0.0.7"}, + {"app38","0.0.1"}, + {"app28","0.0.1"}, + {"app18","0.0.1"}, + {"app4","0.0.1"}, + {"app1","0.0.1"}, + {"app6","0.0.1"}, + {"dep_pkg13","0.0.2"}, + {"app13","0.0.1"}, + {"dep_pkg5","0.0.2"}, + {"dep_pkg1","0.0.2"}, + {"dep_pkg2","0.0.5"}, + {"dep_pkg7","0.1.2"}, + {"app9","0.0.1"}, + {"dep_pkg16","1.0.2"}]), + ?assertMatch({ok,ExpectedResult}, run_data(fix_rebar_brokenness("data3.txt"))). + +data4_test() -> + ExpectedResult = versionify([{"dep_pkg20","0.0.2"}, + {"app78","0.0.1"}, + {"app68","0.0.1"}, + {"app58","0.0.1"}, + {"app48","0.0.7"}, + {"app38","0.0.1"}, + {"app28","0.0.1"}, + {"app18","0.0.1"}, + {"app4","0.0.1"}, + {"app1","0.0.1"}, + {"app6","0.0.1"}, + {"dep_pkg13","0.0.2"}, + {"app13","0.0.1"}, + {"dep_pkg5","0.0.2"}, + {"dep_pkg1","0.0.2"}, + {"dep_pkg2","0.0.5"}, + {"dep_pkg7","0.1.2"}, + {"app9","0.0.1"}, + {"dep_pkg16","1.0.2"}]), + ?assertMatch({ok, ExpectedResult}, + run_data(fix_rebar_brokenness("data4.txt"))). + +data5_test() -> + ExpectedResult = versionify([{"dep_pkg14","0.0.2"}, + {"dep_pkg22","0.0.2"}, + {"dep_pkg20","0.0.2"}, + {"app78","0.0.1"}, + {"app68","0.0.1"}, + {"app58","0.0.1"}, + {"app48","0.0.7"}, + {"app38","0.0.1"}, + {"app28","0.0.1"}, + {"app18","0.0.1"}, + {"app4","0.0.1"}, + {"app1","0.0.1"}, + {"app6","0.0.1"}, + {"dep_pkg13","0.0.2"}, + {"app13","0.0.1"}, + {"dep_pkg5","0.0.2"}, + {"dep_pkg1","0.0.2"}, + {"dep_pkg2","0.0.5"}, + {"dep_pkg7","0.1.2"}, + {"app9","0.0.1"}, + {"dep_pkg16","1.0.2"}]), + ?assertMatch({ok, ExpectedResult}, + run_data(fix_rebar_brokenness("data5.txt"))). + +data6_test() -> + ExpectedResult = versionify([{"app108","0.0.1"}, + {"app98","0.0.1"}, + {"app88","0.0.1"}, + {"dep_pkg14","0.0.2"}, + {"dep_pkg22","0.0.2"}, + {"dep_pkg20","0.0.2"}, + {"app78","0.0.1"}, + {"app68","0.0.1"}, + {"app58","0.0.1"}, + {"app48","0.0.7"}, + {"app38","0.0.1"}, + {"app28","0.0.1"}, + {"app18","0.0.1"}, + {"app4","0.0.1"}, + {"app1","0.0.1"}, + {"app6","0.0.1"}, + {"dep_pkg13","0.0.2"}, + {"app13","0.0.1"}, + {"dep_pkg5","0.0.2"}, + {"dep_pkg1","0.0.2"}, + {"dep_pkg2","0.0.5"}, + {"dep_pkg7","0.1.2"}, + {"app9","0.0.1"}, + {"dep_pkg16","1.0.2"}]), + ?assertMatch({ok, ExpectedResult}, + run_data(fix_rebar_brokenness("data6.txt"))). + +log_07be9e47_test() -> + Data = run_log(fix_rebar_brokenness("log-07be9e47-6f42-4a5d-b8b5-1d2eae1ad83b.txt")), + ExpectedResult = versionify([{"0","0"}, + {"1","0"}, + {"3","0"}, + {"4","0"}, + {"5","0"}, + {"6","0"}, + {"7","0"}, + {"8","0"}, + {"9","0"}, + {"10","0"}, + {"11","0"}, + {"12","0"}, + {"13","0"}, + {"14","0"}, + {"15","0"}, + {"16","0"}, + {"18","0"}, + {"19","0"}, + {"21","0"}, + {"22","0"}, + {"23","0"}, + {"24","0"}, + {"25","0"}]), + ?assertMatch({ok, ExpectedResult}, + Data). + +log_183998c1_test() -> + ?assertMatch({error, {unreachable_package,<<"9">>}}, + run_log(fix_rebar_brokenness("log-183998c1-2ada-4214-b308-e480345c42f2.txt"))). + + +log_311a15e7_test() -> + {ok, Data} = run_log(fix_rebar_brokenness("log-311a15e7-3378-4c5b-beb7-86a1b9cf0ea9.txt")), + ExpectedResult = lists:sort(versionify([{"45", "22"}, + {"40","1"}, + {"3","5"}, + {"9","0"}, + {"8","0"}, + {"7","0"}, + {"6","2"}, + {"1","5"}, + {"0","2"}, + {"61","1"}, + {"60","0"}, + {"35","4"}, + {"39","0"}, + {"38","2"}, + {"37","2"}, + {"36","3"}, + {"32","24"}, + {"30","0"}, + {"19","1"}, + {"18","0"}, + {"17","2"}, + {"16","0"}, + {"15","0"}, + {"14","1"}, + {"13","0"}, + {"12","1"}, + {"11","0"}, + {"10","1"}, + {"59","0"}, + {"58","1"}, + {"57","0"}, + {"56","0"}, + {"55","4"}, + {"29","2"}, + {"27","2"}, + {"26","0"}, + {"25","5"}, + {"24","3"}, + {"23","1"}, + {"22","3"}, + {"21","2"}, + {"20","0"}])), + ?assertMatch(ExpectedResult, lists:sort(Data)). + +log_382cfe5b_test() -> + {ok, Data} = + run_log(fix_rebar_brokenness("log-382cfe5b-0ac2-48b8-83d1-717cb4620990.txt")), + ExpectedResult = lists:sort(versionify([{"18","0"}, + {"17","0"}, + {"15","1"}, + {"14","0"}, + {"10","0"}, + {"7","0"}, + {"6","0"}, + {"5","0"}, + {"4","0"}, + {"3","0"}, + {"2","1"}, + {"1","0"}, + {"0","0"}])), + ?assertMatch(ExpectedResult, lists:sort(Data)). + +log_d3564ef6_test() -> + {ok, Data} = run_log(fix_rebar_brokenness("log-d3564ef6-6437-41e7-90b6-dbdb849551a6_mod.txt")), + ExpectedResult = lists:sort(versionify([{"57","5"}, + {"56","3"}, + {"55","4"}, + {"54","0"}, + {"53","1"}, + {"82","0"}, + {"81","0"}, + {"80","1"}, + {"29","0"}, + {"28","5"}, + {"27","3"}, + {"26","1"}, + {"25","3"}, + {"24","2"}, + {"23","0"}, + {"22","1"}, + {"21","0"}, + {"20","2"}, + {"75","32"}, + {"79","2"}, + {"78","4"}, + {"74","7"}, + {"73","11"}, + {"72","0"}, + {"70","1"}, + {"47","4"}, + {"45","1"}, + {"44","1"}, + {"43","7"}, + {"42","1"}, + {"41","2"}, + {"40","2"}, + {"19","0"}, + {"18","0"}, + {"17","1"}, + {"16","0"}, + {"15","1"}, + {"14","0"}, + {"13","1"}, + {"12","0"}, + {"11","0"}, + {"10","0"}, + {"9","2"}, + {"4","5"}, + {"3","2"}, + {"0","3"}, + {"69","0"}, + {"68","1"}, + {"67","7"}, + {"39","3"}, + {"35","24"}, + {"33","0"}, + {"32","2"}, + {"30","2"}])), + ?assertMatch(ExpectedResult, lists:sort(Data)). + +log_ea2d264b_test() -> + {ok, Data} = run_log(fix_rebar_brokenness("log-ea2d264b-003e-4611-94ed-14efc7732083.txt")), + ExpectedResult = lists:sort(versionify([{"18","1"}, + {"17","0"}, + {"16","0"}, + {"15","0"}, + {"14","0"}, + {"13","1"}, + {"10","1"}, + {"9","1"}, + {"8","2"}, + {"6","0"}, + {"5","0"}, + {"4","0"}, + {"3","0"}, + {"2","0"}, + {"1","0"}, + {"0","1"}])), + ?assertMatch(ExpectedResult, lists:sort(Data)). + +%%============================================================================ +%% Internal Functions +%%============================================================================ +versionify(X) when erlang:is_list(X) -> + lists:map(fun versionify/1, X); +versionify({K, V}) -> + {erlang:list_to_binary(K), rcl_depsolver:parse_version(V)}. + +fix_rebar_brokenness(Filename) -> + Alt1 = filename:join(["./test", "data", Filename]), + Alt2 = filename:join(["../test", "data", Filename]), + case filelib:is_regular(Alt1) of + true -> + Alt1; + false -> + case filelib:is_regular(Alt2) of + true -> + Alt2; + false -> + io:format("~p~n", [Alt2]), + erlang:throw(unable_to_find_data_files) + end + end. + +run_data_file(Device) -> + Constraints = get_constraints(io:get_line(Device, "")), + rcl_depsolver:solve(process_packages(read_packages(Device)), Constraints). + +goble_lines(_Device, eof, Acc) -> + lists:reverse(Acc); +goble_lines(_Device, {error, Err}, _Acc) -> + erlang:throw(Err); +goble_lines(Device, ValidVal, Acc) -> + goble_lines(Device, io:get_line(Device, ""), [ValidVal | Acc]). + +goble_lines(Device) -> + goble_lines(Device, io:get_line(Device, ""), []). + +run_log_file(Device) -> + State0 = rcl_depsolver:new_graph(), + {Goals, State2} = + lists:foldl(fun(Line, Data) -> + process_add_goal(Line, + process_add_constraint(Line, + process_add_package(Line, Data))) + end, {[], State0}, goble_lines(Device)), + rcl_depsolver:solve(State2, Goals). + +read_packages(Device) -> + process_line(Device, io:get_line(Device, ""), []). + +process_line(Device, eof, Acc) -> + file:close(Device), + Acc; +process_line(Device, [], Acc) -> + process_line(Device, io:get_line(Device, ""), + Acc); +process_line(Device, "\n", Acc) -> + process_line(Device, io:get_line(Device, ""), + Acc); +process_line(Device, [$\s | Rest], [{Pkg, Vsn, Deps} | Acc]) -> + [DepPackage, Type, DepVsn] = string:tokens(Rest, " \n"), + Dep = + case Type of + "=" -> + {DepPackage, DepVsn}; + ">=" -> + {DepPackage, DepVsn, gte} + end, + process_line(Device, io:get_line(Device, ""), + [{Pkg, Vsn, [Dep | Deps]} | Acc]); +process_line(Device, Pkg, Acc) -> + [Package, Vsn] = string:tokens(Pkg, " \n"), + process_line(Device, io:get_line(Device, ""), + [{Package, Vsn, []} | Acc]). + +process_packages(Pkgs) -> + lists:foldl(fun({Pkg, Vsn, Constraints}, Dom0) -> + rcl_depsolver:add_package_version(Dom0, Pkg, Vsn, Constraints) + end, rcl_depsolver:new_graph(), Pkgs). + +get_constraints(ConLine) -> + AppVsns = string:tokens(ConLine, " \n"), + lists:map(fun(AppCon) -> + parse_app(AppCon, []) + end, AppVsns). +parse_app([$= | Rest], Acc) -> + {lists:reverse(Acc), Rest}; +parse_app([$>, $= | Rest], Acc) -> + {lists:reverse(Acc), Rest, gte}; +parse_app([Else | Rest], Acc) -> + parse_app(Rest, [Else | Acc]); +parse_app([], Acc) -> + lists:reverse(Acc). + +process_add_package(Line, {Goals, State0}) -> + case re:run(Line, ?ADD_PKG, [{capture, all, list}]) of + {match, [_All, _InstNumber, PkgName, _PkgCount, VersionCount]} -> + {Goals, + lists:foldl(fun(PkgVsn, State1) -> + rcl_depsolver:add_package_version(State1, + PkgName, + erlang:integer_to_list(PkgVsn), + []) + end, State0, lists:seq(0, + erlang:list_to_integer(VersionCount)))}; + _ -> + {Goals, State0} + end. + +process_add_constraint(Line, {Goals, State0}) -> + case re:run(Line, ?ADD_VC, [{capture, all, list}]) of + {match, [_All, _InstNumber, Pkg, Vsn, Dep, _Ignore, DepVsn]} -> + {Goals, + rcl_depsolver:add_package_version(State0, Pkg, Vsn, [{Dep, DepVsn}])}; + _ -> + {Goals, State0} + end. + +process_add_goal(Line, {Goals, State0}) -> + case re:run(Line, ?ADD_GOAL, [{capture, all, list}]) of + {match,[_All, _InstNumber, NewGoal]} -> + {[NewGoal | Goals], State0}; + _ -> + {Goals, State0} + end. diff --git a/test/rlx_depsolver_tests.erl b/test/rlx_depsolver_tests.erl new file mode 100644 index 0000000..eae31a4 --- /dev/null +++ b/test/rlx_depsolver_tests.erl @@ -0,0 +1,495 @@ +%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 80 -*- +%% ex: ts=4 sx=4 et +%% +%%------------------------------------------------------------------- +%% Copyright 2012 Opscode, Inc. All Rights Reserved. +%% +%% This file is provided to you under the Apache License, +%% Version 2.0 (the "License"); you may not use this file +%% except in compliance with the License. You may obtain +%% a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, +%% software distributed under the License is distributed on an +%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +%% KIND, either express or implied. See the License for the +%% specific language governing permissions and limitations +%% under the License. +%% +%% @author Eric Merritt +%%------------------------------------------------------------------- +-module(rcl_depsolver_tests). + +-include_lib("eunit/include/eunit.hrl"). + +%%============================================================================ +%% Tests +%%============================================================================ + +first_test() -> + Dom0 = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), [{app1, [{"0.1", [{app2, "0.2+build.33"}, + {app3, "0.2", '>='}]}, + {"0.2", []}, + {"0.3", []}]}, + {app2, [{"0.1", []}, + {"0.2+build.33",[{app3, "0.3"}]}, + {"0.3", []}]}, + {app3, [{"0.1", []}, + {"0.2", []}, + {"0.3", []}]}]), + + + case rcl_depsolver:solve(Dom0, [{app1, "0.1"}]) of + {ok,[{app3,{{0,3},{[],[]}}}, + {app2,{{0,2},{[],[<<"build">>,33]}}}, + {app1,{{0,1},{[],[]}}}]} -> + ok; + E -> + erlang:throw({invalid_result, E}) + end. + +second_test() -> + + Dom0 = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), [{app1, [{"0.1", [{app2, "0.1", '>='}, + {app4, "0.2"}, + {app3, "0.2", '>='}]}, + {"0.2", []}, + {"0.3", []}]}, + {app2, [{"0.1", [{app3, "0.2", gte}]}, + {"0.2", [{app3, "0.2", gte}]}, + {"0.3", [{app3, "0.2", '>='}]}]}, + {app3, [{"0.1", [{app4, "0.2", '>='}]}, + {"0.2", [{app4, "0.2"}]}, + {"0.3", []}]}, + {app4, [{"0.1", []}, + {"0.2", [{app2, "0.2", gte}, + {app3, "0.3"}]}, + {"0.3", []}]}]), + + X = rcl_depsolver:solve(Dom0, [{app1, "0.1"}, + {app2, "0.3"}]), + + ?assertMatch({ok, [{app3,{{0,3},{[],[]}}}, + {app2,{{0,3},{[],[]}}}, + {app4,{{0,2},{[],[]}}}, + {app1,{{0,1},{[],[]}}}]}, + X). + +third_test() -> + + Pkg1Deps = [{app2, "0.1.0", '>='}, + {app3, "0.1.1", "0.1.5", between}], + + Pkg2Deps = [{app4, "5.0.0", gte}], + Pkg3Deps = [{app5, "2.0.0", '>='}], + Pkg4Deps = [app5], + + Dom0 = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), [{app1, [{"0.1.0", Pkg1Deps}, + {"0.2", Pkg1Deps}, + {"3.0", Pkg1Deps}]}, + {app2, [{"0.0.1", Pkg2Deps}, + {"0.1", Pkg2Deps}, + {"1.0", Pkg2Deps}, + {"3.0", Pkg2Deps}]}, + {app3, [{"0.1.0", Pkg3Deps}, + {"0.1.3", Pkg3Deps}, + {"2.0.0", Pkg3Deps}, + {"3.0.0", Pkg3Deps}, + {"4.0.0", Pkg3Deps}]}, + {app4, [{"0.1.0", Pkg4Deps}, + {"0.3.0", Pkg4Deps}, + {"5.0.0", Pkg4Deps}, + {"6.0.0", Pkg4Deps}]}, + {app5, [{"0.1.0", []}, + {"0.3.0", []}, + {"2.0.0", []}, + {"6.0.0", []}]}]), + + ?assertMatch({ok, [{app5,{{6,0,0},{[],[]}}}, + {app3,{{0,1,3},{[],[]}}}, + {app4,{{6,0,0},{[],[]}}}, + {app2,{{3,0},{[],[]}}}, + {app1,{{3,0},{[],[]}}}]}, + rcl_depsolver:solve(Dom0, [{app1, "3.0"}])), + + + ?assertMatch({ok, [{app5,{{6,0,0},{[],[]}}}, + {app3,{{0,1,3},{[],[]}}}, + {app4,{{6,0,0},{[],[]}}}, + {app2,{{3,0},{[],[]}}}, + {app1,{{3,0},{[],[]}}}]}, + rcl_depsolver:solve(Dom0, [app1])). + +fail_test() -> + Dom0 = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), + [{app1, [{"0.1", [{app2, "0.2"}, + {app3, "0.2", gte}]}, + {"0.2", []}, + {"0.3", []}]}, + {app2, [{"0.1", []}, + {"0.2",[{app3, "0.1"}]}, + {"0.3", []}]}, + {app3, [{"0.1", []}, + {"0.2", []}, + {"0.3", []}]}]), + + Ret = rcl_depsolver:solve(Dom0, [{app1, "0.1"}]), + %% We do this to make sure all errors can be formated. + _ = rcl_depsolver:format_error(Ret), + ?assertMatch({error, + [{[{[{app1,{{0,1},{[],[]}}}], + [{app1,{{0,1},{[],[]}}},[[{app2,{{0,2},{[],[]}}}]]]}], + [{{app2,{{0,2},{[],[]}}},[{app3,{{0,1},{[],[]}}}]}, + {{app1,{{0,1},{[],[]}}},[{app3,{{0,2},{[],[]}},gte}]}]}]}, + Ret). + +conflicting_passing_test() -> + Pkg1Deps = [{app2, "0.1.0", '>='}, + {app5, "2.0.0"}, + {app4, "0.3.0", "5.0.0", between}, + {app3, "0.1.1", "0.1.5", between}], + + Pkg2Deps = [{app4, "3.0.0", gte}], + Pkg3Deps = [{app5, "2.0.0", '>='}], + + Dom0 = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), [{app1, [{"0.1.0", Pkg1Deps}, + {"0.1.0", Pkg1Deps}, + {"0.2", Pkg1Deps}, + {"3.0", Pkg1Deps}]}, + {app2, [{"0.0.1", Pkg2Deps}, + {"0.1", Pkg2Deps}, + {"1.0", Pkg2Deps}, + {"3.0", Pkg2Deps}]}, + {app3, [{"0.1.0", Pkg3Deps}, + {"0.1.3", Pkg3Deps}, + {"2.0.0", Pkg3Deps}, + {"3.0.0", Pkg3Deps}, + {"4.0.0", Pkg3Deps}]}, + {app4, [{"0.1.0", [{app5, "0.1.0"}]}, + {"0.3.0", [{app5, "0.3.0"}]}, + {"5.0.0", [{app5, "2.0.0"}]}, + {"6.0.0", [{app5, "6.0.0"}]}]}, + {app5, [{"0.1.0", []}, + {"0.3.0", []}, + {"2.0.0", []}, + {"6.0.0", []}]}]), + + ?assertMatch({ok, [{app5,{{2,0,0},{[],[]}}}, + {app3,{{0,1,3},{[],[]}}}, + {app4,{{5,0,0},{[],[]}}}, + {app2,{{3,0},{[],[]}}}, + {app1,{{3,0},{[],[]}}}]}, + rcl_depsolver:solve(Dom0, [{app1, "3.0"}])), + + ?assertMatch({ok, [{app5,{{2,0,0},{[],[]}}}, + {app3,{{0,1,3},{[],[]}}}, + {app4,{{5,0,0},{[],[]}}}, + {app2,{{3,0},{[],[]}}}, + {app1,{{3,0},{[],[]}}}]}, + rcl_depsolver:solve(Dom0, [app1, app2, app5])). + + + +circular_dependencies_test() -> + Dom0 = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), [{app1, [{"0.1.0", [app2]}]}, + {app2, [{"0.0.1", [app1]}]}]), + + ?assertMatch({ok, [{app1,{{0,1,0},{[],[]}}},{app2,{{0,0,1},{[],[]}}}]}, + rcl_depsolver:solve(Dom0, [{app1, "0.1.0"}])). + +conflicting_failing_test() -> + Pkg1Deps = [app2, + {app5, "2.0.0", '='}, + {app4, "0.3.0", "5.0.0", between}], + + Pkg2Deps = [{app4, "5.0.0", gte}], + Pkg3Deps = [{app5, "6.0.0"}], + + + Dom0 = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), [{app1, [{"3.0", Pkg1Deps}]}, + {app2, [{"0.0.1", Pkg2Deps}]}, + {app3, [{"0.1.0", Pkg3Deps}]}, + {app4, [{"5.0.0", [{app5, "2.0.0"}]}]}, + {app5, [{"2.0.0", []}, + {"6.0.0", []}]}]), + Ret = rcl_depsolver:solve(Dom0, [app1, app3]), + _ = rcl_depsolver:format_error(Ret), + ?assertMatch({error, + [{[{[app1], + [{app1,{{3,0},{[],[]}}}, + [[{app4,{{5,0,0},{[],[]}}}], + [{app2,{{0,0,1},{[],[]}}},[[{app4,{{5,0,0},{[],[]}}}]]]]]}, + {[app3], + [{app3,{{0,1,0},{[],[]}}},[[{app5,{{6,0,0},{[],[]}}}]]]}], + [{{app4,{{5,0,0},{[],[]}}},[{app5,{{2,0,0},{[],[]}}}]}, + {{app1,{{3,0},{[],[]}}},[{app5,{{2,0,0},{[],[]}},'='}]}]}]}, + Ret). + + +pessimistic_major_minor_patch_test() -> + + Pkg1Deps = [{app2, "2.1.1", '~>'}, + {app3, "0.1.1", "0.1.5", between}], + + Pkg2Deps = [{app4, "5.0.0", gte}], + Pkg3Deps = [{app5, "2.0.0", '>='}], + Pkg4Deps = [app5], + + Dom0 = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), [{app1, [{"0.1.0", Pkg1Deps}, + {"0.2", Pkg1Deps}, + {"3.0", Pkg1Deps}]}, + {app2, [{"0.0.1", Pkg2Deps}, + {"0.1", Pkg2Deps}, + {"1.0", Pkg2Deps}, + {"2.1.5", Pkg2Deps}, + {"2.2", Pkg2Deps}, + {"3.0", Pkg2Deps}]}, + {app3, [{"0.1.0", Pkg3Deps}, + {"0.1.3", Pkg3Deps}, + {"2.0.0", Pkg3Deps}, + {"3.0.0", Pkg3Deps}, + {"4.0.0", Pkg3Deps}]}, + {app4, [{"0.1.0", Pkg4Deps}, + {"0.3.0", Pkg4Deps}, + {"5.0.0", Pkg4Deps}, + {"6.0.0", Pkg4Deps}]}, + {app5, [{"0.1.0", []}, + {"0.3.0", []}, + {"2.0.0", []}, + {"6.0.0", []}]}]), + ?assertMatch({ok, [{app5,{{6,0,0},{[],[]}}}, + {app3,{{0,1,3},{[],[]}}}, + {app4,{{6,0,0},{[],[]}}}, + {app2,{{2,1,5},{[],[]}}}, + {app1,{{3,0},{[],[]}}}]}, + rcl_depsolver:solve(Dom0, [{app1, "3.0"}])). + +pessimistic_major_minor_test() -> + + Pkg1Deps = [{app2, "2.1", '~>'}, + {app3, "0.1.1", "0.1.5", between}], + + Pkg2Deps = [{app4, "5.0.0", gte}], + Pkg3Deps = [{app5, "2.0.0", '>='}], + Pkg4Deps = [app5], + + Dom0 = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), [{app1, [{"0.1.0", Pkg1Deps}, + {"0.2", Pkg1Deps}, + {"3.0", Pkg1Deps}]}, + {app2, [{"0.0.1", Pkg2Deps}, + {"0.1", Pkg2Deps}, + {"1.0", Pkg2Deps}, + {"2.1.5", Pkg2Deps}, + {"2.2", Pkg2Deps}, + {"3.0", Pkg2Deps}]}, + {app3, [{"0.1.0", Pkg3Deps}, + {"0.1.3", Pkg3Deps}, + {"2.0.0", Pkg3Deps}, + {"3.0.0", Pkg3Deps}, + {"4.0.0", Pkg3Deps}]}, + {app4, [{"0.1.0", Pkg4Deps}, + {"0.3.0", Pkg4Deps}, + {"5.0.0", Pkg4Deps}, + {"6.0.0", Pkg4Deps}]}, + {app5, [{"0.1.0", []}, + {"0.3.0", []}, + {"2.0.0", []}, + {"6.0.0", []}]}]), + ?assertMatch({ok, [{app5,{{6,0,0},{[],[]}}}, + {app3,{{0,1,3},{[],[]}}}, + {app4,{{6,0,0},{[],[]}}}, + {app2,{{2,2},{[],[]}}}, + {app1,{{3,0},{[],[]}}}]}, + rcl_depsolver:solve(Dom0, [{app1, "3.0"}])). + +filter_versions_test() -> + + Cons = [{app2, "2.1", '~>'}, + {app3, "0.1.1", "0.1.5", between}, + {app4, "5.0.0", gte}, + {app5, "2.0.0", '>='}, + app5], + + Packages = [{app1, "0.1.0"}, + {app1, "0.2"}, + {app1, "0.2"}, + {app1, "3.0"}, + {app2, "0.0.1"}, + {app2, "0.1"}, + {app2, "1.0"}, + {app2, "2.1.5"}, + {app2, "2.2"}, + {app2, "3.0"}, + {app3, "0.1.0"}, + {app3, "0.1.3"}, + {app3, "2.0.0"}, + {app3, "3.0.0"}, + {app3, "4.0.0"}, + {app4, "0.1.0"}, + {app4, "0.3.0"}, + {app4, "5.0.0"}, + {app4, "6.0.0"}, + {app5, "0.1.0"}, + {app5, "0.3.0"}, + {app5, "2.0.0"}, + {app5, "6.0.0"}], + + ?assertMatch({ok, [{app1,"0.1.0"}, + {app1,"0.2"}, + {app1,"0.2"}, + {app1,"3.0"}, + {app2,"2.1.5"}, + {app2,"2.2"}, + {app3,"0.1.3"}, + {app4,"5.0.0"}, + {app4,"6.0.0"}, + {app5,"2.0.0"}, + {app5,"6.0.0"}]}, + rcl_depsolver:filter_packages(Packages, Cons)), + + Ret = rcl_depsolver:filter_packages(Packages, + [{"foo", "1.0.0", '~~~~'} | Cons]), + _ = rcl_depsolver:format_error(Ret), + ?assertMatch({error, {invalid_constraints, [{<<"foo">>,{{1,0,0},{[],[]}},'~~~~'}]}}, Ret). + + +-spec missing_test() -> ok. +missing_test() -> + + Dom0 = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), [{app1, [{"0.1", [{app2, "0.2"}, + {app3, "0.2", '>='}, + {app4, "0.2", '='}]}, + {"0.2", [{app4, "0.2"}]}, + {"0.3", [{app4, "0.2", '='}]}]}, + {app2, [{"0.1", []}, + {"0.2",[{app3, "0.3"}]}, + {"0.3", []}]}, + {app3, [{"0.1", []}, + {"0.2", []}, + {"0.3", []}]}]), + Ret1 = rcl_depsolver:solve(Dom0, [{app4, "0.1"}, {app3, "0.1"}]), + _ = rcl_depsolver:format_error(Ret1), + ?assertMatch({error,{unreachable_package,app4}}, Ret1), + + Ret2 = rcl_depsolver:solve(Dom0, [{app1, "0.1"}]), + _ = rcl_depsolver:format_error(Ret2), + ?assertMatch({error,{unreachable_package,app4}}, + Ret2). + + +binary_test() -> + + World = [{<<"foo">>, [{<<"1.2.3">>, [{<<"bar">>, <<"2.0.0">>, gt}]}]}, + {<<"bar">>, [{<<"2.0.0">>, [{<<"foo">>, <<"3.0.0">>, gt}]}]}], + Ret = rcl_depsolver:solve(rcl_depsolver:add_packages(rcl_depsolver:new_graph(), + World), + [<<"foo">>]), + + _ = rcl_depsolver:format_error(Ret), + ?assertMatch({error, + [{[{[<<"foo">>],[{<<"foo">>,{{1,2,3},{[],[]}}}]}], + [{{<<"foo">>,{{1,2,3},{[],[]}}}, + [{<<"bar">>,{{2,0,0},{[],[]}},gt}]}]}]}, Ret). + +%% +%% We don't have bar cookbook +%% +%% Ruby gives +%% "message":"Unable to satisfy constraints on cookbook bar, which does not +%% exist, due to run list item (foo >= 0.0.0). Run list items that may result +%% in a constraint on bar: [(foo = 1.2.3) -> (bar > 2.0.0)]", +%% "unsatisfiable_run_list_item":"(foo >= 0.0.0)", +%% "non_existent_cookbooks":["bar"]," +%% "most_constrained_cookbooks":[]}" +%% +doesnt_exist_test() -> + Constraints = [{<<"foo">>,[{<<"1.2.3">>, [{<<"bar">>, <<"2.0.0">>, gt}]}]}], + World = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), Constraints), + Ret = rcl_depsolver:solve(World, [<<"foo">>]), + _ = rcl_depsolver:format_error(Ret), + ?assertMatch({error,{unreachable_package,<<"bar">>}}, Ret). + +%% +%% We have v 2.0.0 of bar but want > 2.0.0 +%% +%% Ruby gives +%% "message":"Unable to satisfy constraints on cookbook bar due to run list item +%% (foo >= 0.0.0). Run list items that may result in a constraint on bar: [(foo +%% = 1.2.3) -> (bar > 2.0.0)]", +%% "unsatisfiable_run_list_item":"(foo >= 0.0.0)", +%% "non_existent_cookbooks":[], +%% "most_constrained_cookbooks":["bar 2.0.0 -> []"] +%% +not_new_enough_test() -> + + Constraints = [{<<"foo">>, [{<<"1.2.3">>, [{<<"bar">>, <<"2.0.0">>, gt}]}]}, + {<<"bar">>, [{<<"2.0.0">>, []}]}], + World = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), Constraints), + Ret = rcl_depsolver:solve(World, [<<"foo">>]), + _ = rcl_depsolver:format_error(Ret), + ?assertMatch({error, + [{[{[<<"foo">>],[{<<"foo">>,{{1,2,3},{[],[]}}}]}], + [{{<<"foo">>,{{1,2,3},{[],[]}}}, + [{<<"bar">>,{{2,0,0},{[],[]}},gt}]}]}]}, Ret). + +%% +%% circular deps are bad +%% +%% Ruby gives +%% "message":"Unable to satisfy constraints on cookbook bar due to run list item (foo >= 0.0.0). +%% Run list items that may result in a constraint on bar: [(foo = 1.2.3) -> (bar > 2.0.0)]", +%% "unsatisfiable_run_list_item":"(foo >= 0.0.0)", +%% "non_existent_cookbooks":[], +%% "most_constrained_cookbooks:["bar = 2.0.0 -> [(foo > 3.0.0)]"] +%% +impossible_dependency_test() -> + World = rcl_depsolver:add_packages(rcl_depsolver:new_graph(), + [{<<"foo">>, [{<<"1.2.3">>,[{ <<"bar">>, <<"2.0.0">>, gt}]}]}, + {<<"bar">>, [{<<"2.0.0">>, [{ <<"foo">>, <<"3.0.0">>, gt}]}]}]), + Ret = rcl_depsolver:solve(World, [<<"foo">>]), + _ = rcl_depsolver:format_error(Ret), + ?assertMatch({error, + [{[{[<<"foo">>],[{<<"foo">>,{{1,2,3},{[],[]}}}]}], + [{{<<"foo">>,{{1,2,3},{[],[]}}}, + [{<<"bar">>,{{2,0,0},{[],[]}},gt}]}]}]}, Ret). + +%% +%% Formatting tests +%% +format_test_() -> + [{"format constraint", + [equal_bin_string(<<"foo">>, rcl_depsolver:format_constraint(<<"foo">>)), + equal_bin_string(<<"foo">>, rcl_depsolver:format_constraint(foo)), + equal_bin_string(<<"(foo = 1.2.0)">>, rcl_depsolver:format_constraint({<<"foo">>, {{1,2,0}, {[], []}}})), + equal_bin_string(<<"(foo = 1.2.0)">>, rcl_depsolver:format_constraint({<<"foo">>, {{1,2,0}, {[], []}}, '='})), + equal_bin_string(<<"(foo > 1.2.0)">>, + rcl_depsolver:format_constraint({<<"foo">>, {{1,2,0}, {[], []}}, '>'})), + equal_bin_string(<<"(foo > 1.2.0)">>, + rcl_depsolver:format_constraint({<<"foo">>, {{1,2,0}, {[], []}}, gt})), + equal_bin_string(<<"(foo between 1.2.0 and 1.3.0)">>, + rcl_depsolver:format_constraint({<<"foo">>,{{1,2,0}, {[], []}}, + {{1,3,0}, {[], []}}, between})), + equal_bin_string(<<"(foo > 1.2.0-alpha.1+build.36)">>, + rcl_depsolver:format_constraint({<<"foo">>, + {{1,2,0}, {["alpha", 1], ["build", 36]}}, gt})) + ] + }, + {"format roots", + [equal_bin_string(<<"(bar = 1.2.0)">>, + rcl_depsolver:format_roots([ [{<<"bar">>, {{1,2,0},{[],[]}}}] ])), + equal_bin_string(<<"(bar = 1.2.0), foo">>, + rcl_depsolver:format_roots([[<<"foo">>, + {<<"bar">>, {{1,2,0},{[],[]}}}]])), + equal_bin_string(<<"(bar = 1.2.0), foo">>, + rcl_depsolver:format_roots([[<<"foo">>], [{<<"bar">>, {{1,2,0},{[],[]}}}]])) + ] + } + ]. + +%% +%% Internal functions +%% +equal_bin_string(Expected, Got) -> + ?_assertEqual(Expected, erlang:iolist_to_binary(Got)). diff --git a/test/rlx_discover_SUITE.erl b/test/rlx_discover_SUITE.erl new file mode 100644 index 0000000..e3a2861 --- /dev/null +++ b/test/rlx_discover_SUITE.erl @@ -0,0 +1,193 @@ +%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 92 -*- +%%% Copyright 2012 Erlware, LLC. All Rights Reserved. +%%% +%%% This file is provided to you under the Apache License, +%%% Version 2.0 (the "License"); you may not use this file +%%% except in compliance with the License. You may obtain +%%% a copy of the License at +%%% +%%% http://www.apache.org/licenses/LICENSE-2.0 +%%% +%%% Unless required by applicable law or agreed to in writing, +%%% software distributed under the License is distributed on an +%%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +%%% KIND, either express or implied. See the License for the +%%% specific language governing permissions and limitations +%%% under the License. +%%%------------------------------------------------------------------- +%%% @author Eric Merrit +%%% @copyright (C) 2012, Eric Merrit +-module(rclt_discover_SUITE). + +-export([suite/0, + init_per_suite/1, + end_per_suite/1, + init_per_testcase/2, + all/0, + normal_case/1, + no_beam_case/1, + bad_ebin_case/1]). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). + +suite() -> + [{timetrap,{seconds,30}}]. + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_testcase(_, Config) -> + DataDir = proplists:get_value(data_dir, Config), + LibDir1 = filename:join([DataDir, create_random_name("lib_dir1_")]), + LibDir2 = filename:join([DataDir, create_random_name("lib_dir2_")]), + ok = rcl_util:mkdir_p(LibDir1), + ok = rcl_util:mkdir_p(LibDir2), + State = rcl_state:new([{lib_dirs, [LibDir1, LibDir2]}], release), + [{lib1, LibDir1}, + {lib2, LibDir2}, + {state, State} | Config]. + + +all() -> + [normal_case, no_beam_case, bad_ebin_case]. + +normal_case(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + Apps1 = [(fun({Name, Vsn}) -> + create_app(LibDir1, Name, Vsn) + end)(App) + || + App <- + [{create_random_name("lib_app1_"), create_random_vsn()} + || _ <- lists:seq(1, 100)]], + + LibDir2 = proplists:get_value(lib2, Config), + Apps2 = [(fun({Name, Vsn}) -> + create_app(LibDir2, Name, Vsn) + end)(App) + || App <- + [{create_random_name("lib_app2_"), create_random_vsn()} + || _ <- lists:seq(1, 100)]], + State0 = rcl_state:put(proplists:get_value(state, Config), + disable_default_libs, true), + {DiscoverProvider, {ok, State1}} = rcl_provider:new(rcl_prv_discover, State0), + {ok, State2} = rcl_provider:do(DiscoverProvider, State1), + lists:foreach(fun(App) -> + ?assertMatch(true, lists:member(App, rcl_state:available_apps(State2))) + end, Apps1), + + lists:foreach(fun(App) -> + ?assertMatch(true, lists:member(App, rcl_state:available_apps(State2))) + end, Apps2), + Length = erlang:length(Apps2) + + erlang:length(Apps2), + ?assertMatch(Length, erlang:length(rcl_state:available_apps(State2))). + +no_beam_case(Config) -> + %% We silently ignore apps with no beams + LibDir1 = proplists:get_value(lib1, Config), + _Apps1 = [(fun({Name, Vsn}) -> + create_app(LibDir1, Name, Vsn) + end)(App) + || + App <- + [{create_random_name("lib_app1_"), create_random_vsn()} + || _ <- lists:seq(1, 100)]], + + LibDir2 = proplists:get_value(lib2, Config), + _Apps2 = [(fun({Name, Vsn}) -> + create_app(LibDir2, Name, Vsn) + end)(App) + || App <- + [{create_random_name("lib_app2_"), create_random_vsn()} + || _ <- lists:seq(1, 100)]], + BadName = create_random_name("error_bad"), + BadVsn = create_random_vsn(), + AppDir = filename:join([LibDir2, BadName]), + write_app_file(AppDir, BadName, BadVsn), + State0 = proplists:get_value(state, Config), + {DiscoverProvider, {ok, State1}} = rcl_provider:new(rcl_prv_discover, State0), + EbinDir = filename:join([LibDir2, BadName, <<"ebin">>]), + ?assertMatch({error, {_, [{no_beam_files, EbinDir}]}}, + rcl_provider:do(DiscoverProvider, State1)). + +bad_ebin_case(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + _Apps1 = [(fun({Name, Vsn}) -> + create_app(LibDir1, Name, Vsn) + end)(App) + || + App <- + [{create_random_name("lib_app1_"), create_random_vsn()} + || _ <- lists:seq(1, 100)]], + + LibDir2 = proplists:get_value(lib2, Config), + _Apps2 = [(fun({Name, Vsn}) -> + create_app(LibDir2, Name, Vsn) + end)(App) + || App <- + [{create_random_name("lib_app2_"), create_random_vsn()} + || _ <- lists:seq(1, 100)]], + BadName = create_random_name("error_bad"), + BadVsn = create_random_vsn(), + AppDir = filename:join([LibDir2, BadName]), + Filename = filename:join([AppDir, <<"ebin">>, BadName ++ ".app"]), + ok = filelib:ensure_dir(Filename), + ok = ec_file:write_term(Filename, get_bad_app_metadata(BadName, BadVsn)), + write_beam_file(AppDir, BadName), + State0 = proplists:get_value(state, Config), + {DiscoverProvider, {ok, State1}} = rcl_provider:new(rcl_prv_discover, State0), + ?assertMatch({error, {_, [{invalid_app_file, Filename}]}}, + rcl_provider:do(DiscoverProvider, State1)). + + +%%%=================================================================== +%%% Helper functions +%%%=================================================================== +create_app(Dir, Name, Vsn) -> + AppDir = filename:join([Dir, Name]), + write_app_file(AppDir, Name, Vsn), + write_beam_file(AppDir, Name), + {ok, App} = rcl_app_info:new(erlang:list_to_atom(Name), Vsn, + erlang:iolist_to_binary(AppDir), + [kernel, stdlib], []), + App. + +write_beam_file(Dir, Name) -> + Beam = filename:join([Dir, "ebin", "not_a_real_beam" ++ Name ++ ".beam"]), + ok = filelib:ensure_dir(Beam), + ok = ec_file:write_term(Beam, testing_purposes_only). + +write_app_file(Dir, Name, Version) -> + Filename = filename:join([Dir, "ebin", Name ++ ".app"]), + ok = filelib:ensure_dir(Filename), + ok = ec_file:write_term(Filename, get_app_metadata(Name, Version)). + +get_app_metadata(Name, Vsn) -> + {application, erlang:list_to_atom(Name), + [{description, ""}, + {vsn, Vsn}, + {modules, []}, + {applications, [kernel, stdlib]}]}. + +get_bad_app_metadata(Name, Vsn) -> + ["{application, ", Name, ", + [{description, \"\"}, + {vsn, \"", Vsn, "\"}, + {modules, [], + {applications, [kernel, stdlib]}]}."]. + + +create_random_name(Name) -> + random:seed(erlang:now()), + Name ++ erlang:integer_to_list(random:uniform(1000000)). + +create_random_vsn() -> + random:seed(erlang:now()), + lists:flatten([erlang:integer_to_list(random:uniform(100)), + ".", erlang:integer_to_list(random:uniform(100)), + ".", erlang:integer_to_list(random:uniform(100))]). diff --git a/test/rlx_goal_tests.erl b/test/rlx_goal_tests.erl new file mode 100644 index 0000000..20fb5e5 --- /dev/null +++ b/test/rlx_goal_tests.erl @@ -0,0 +1,63 @@ +%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 92 -*- +%%% Copyright 2012 Erlware, LLC. All Rights Reserved. +%%% +%%% This file is provided to you under the Apache License, +%%% Version 2.0 (the "License"); you may not use this file +%%% except in compliance with the License. You may obtain +%%% a copy of the License at +%%% +%%% http://www.apache.org/licenses/LICENSE-2.0 +%%% +%%% Unless required by applicable law or agreed to in writing, +%%% software distributed under the License is distributed on an +%%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +%%% KIND, either express or implied. See the License for the +%%% specific language governing permissions and limitations +%%% under the License. +%%%--------------------------------------------------------------------------- +%%% @author Eric Merritt +%%% @copyright (C) 2012 Erlware, LLC. +%%% @doc test for target spec parsing +-module(rclt_goal). + +-include_lib("eunit/include/eunit.hrl"). + +parse_test() -> + ?assertMatch({ok, getopt}, + rcl_goal:parse("getopt")), + ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, '='}}, + rcl_goal:parse("getopt=0.5.1")), + ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, '='}}, + rcl_goal:parse("getopt:0.5.1")), + ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, '='}}, + rcl_goal:parse("getopt-0.5.1")), + ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, gte}}, + rcl_goal:parse("getopt >= 0.5.1")), + ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, gte}}, + rcl_goal:parse("getopt:gte:0.5.1")), + ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, gt}}, + rcl_goal:parse("getopt>0.5.1")), + ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, gt}}, + rcl_goal:parse("getopt:gt:0.5.1")), + ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, lte}}, + rcl_goal:parse("getopt<= 0.5.1")), + ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, lte}}, + rcl_goal:parse("getopt:lte:0.5.1")), + ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, lt}}, + rcl_goal:parse("getopt<0.5.1")), + ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, pes}}, + rcl_goal:parse("getopt ~>0.5.1")), + ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, pes}}, + rcl_goal:parse("getopt: pes:0.5.1")), + ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, {{0,6,1},{[],[]}}, between}}, + rcl_goal:parse("getopt:btwn:0.5.1,0.6.1")), + ?assertMatch({ok, {getopt, {{0,5,1},{[],[]}}, {{0,6,1},{[],[]}}, between}}, + rcl_goal:parse("getopt:between :0.5.1,0.6.1")). + +fail_test() -> + ?assertMatch({fail,_}, + rcl_goal:parse("got:")), + ?assertMatch({fail,_}, + rcl_goal:parse("between:btwn:0.5")), + ?assertMatch({fail,_}, + rcl_goal:parse("between:btwn:0.5,")). diff --git a/test/rlx_release_SUITE.erl b/test/rlx_release_SUITE.erl new file mode 100644 index 0000000..90d99c9 --- /dev/null +++ b/test/rlx_release_SUITE.erl @@ -0,0 +1,837 @@ +%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 92 -*- +%%% Copyright 2012 Erlware, LLC. All Rights Reserved. +%%% +%%% This file is provided to you under the Apache License, +%%% Version 2.0 (the "License"); you may not use this file +%%% except in compliance with the License. You may obtain +%%% a copy of the License at +%%% +%%% http://www.apache.org/licenses/LICENSE-2.0 +%%% +%%% Unless required by applicable law or agreed to in writing, +%%% software distributed under the License is distributed on an +%%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +%%% KIND, either express or implied. See the License for the +%%% specific language governing permissions and limitations +%%% under the License. +%%%------------------------------------------------------------------- +%%% @author Eric Merrit +%%% @copyright (C) 2012, Eric Merrit +-module(rclt_release_SUITE). + +-export([suite/0, + init_per_suite/1, + end_per_suite/1, + init_per_testcase/2, + all/0, + make_release/1, + make_scriptless_release/1, + make_overridden_release/1, + make_skip_app_release/1, + make_rerun_overridden_release/1, + make_implicit_config_release/1, + overlay_release/1, + make_goalless_release/1, + make_depfree_release/1, + make_invalid_config_release/1, + make_relup_release/1, + make_relup_release2/1, + make_one_app_top_level_release/1]). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). +-include_lib("kernel/include/file.hrl"). +-include_lib("kernel/include/file.hrl"). + +suite() -> + [{timetrap,{seconds,30}}]. + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_testcase(_, Config) -> + DataDir = proplists:get_value(data_dir, Config), + LibDir1 = filename:join([DataDir, create_random_name("lib_dir1_")]), + ok = rcl_util:mkdir_p(LibDir1), + State = rcl_state:new([{lib_dirs, [LibDir1]}], release), + [{lib1, LibDir1}, + {state, State} | Config]. + +all() -> + [make_release, make_scriptless_release, make_overridden_release, + make_skip_app_release, + make_implicit_config_release, make_rerun_overridden_release, + overlay_release, make_goalless_release, make_depfree_release, + make_invalid_config_release, make_relup_release, make_relup_release2, + make_one_app_top_level_release]. + +make_release(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + [(fun({Name, Vsn}) -> + create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) + end)(App) + || + App <- + [{create_random_name("lib_app1_"), create_random_vsn()} + || _ <- lists:seq(1, 100)]], + + create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), + create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []), + create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), + create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), + create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), + + ConfigFile = filename:join([LibDir1, "relcool.config"]), + write_config(ConfigFile, + [{release, {foo, "0.0.1"}, + [goal_app_1, + goal_app_2]}]), + OutputDir = filename:join([proplists:get_value(data_dir, Config), + create_random_name("relcool-output")]), + {ok, State} = relcool:do(undefined, undefined, [], [LibDir1], 2, + OutputDir, ConfigFile), + [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rcl_state:realized_releases(State)), + AppSpecs = rcl_release:applications(Release), + ?assert(lists:keymember(stdlib, 1, AppSpecs)), + ?assert(lists:keymember(kernel, 1, AppSpecs)), + ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)), + ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)), + ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)), + ?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)), + ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)). + +make_invalid_config_release(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + [(fun({Name, Vsn}) -> + create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) + end)(App) + || + App <- + [{create_random_name("lib_app1_"), create_random_vsn()} + || _ <- lists:seq(1, 100)]], + + create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), + create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []), + create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), + create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), + create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), + + ConfigFile = filename:join([LibDir1, "relcool.config"]), + ok = ec_file:write(ConfigFile, + "{release, {foo, \"0.0.1\"}, + [goal_app_1, + goal_app_2,]}"), + OutputDir = filename:join([proplists:get_value(data_dir, Config), + create_random_name("relcool-output")]), + {error, {rcl_prv_config, + {consult, _, _}}} = relcool:do(undefined, undefined, [], [LibDir1], 2, + OutputDir, ConfigFile). + +make_scriptless_release(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + [(fun({Name, Vsn}) -> + create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) + end)(App) + || + App <- + [{create_random_name("lib_app1_"), create_random_vsn()} + || _ <- lists:seq(1, 100)]], + + create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), + create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []), + create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), + create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), + create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), + + ConfigFile = filename:join([LibDir1, "relcool.config"]), + write_config(ConfigFile, + [{generate_start_script, false}, + {release, {foo, "0.0.1"}, + [goal_app_1, + goal_app_2]}]), + OutputDir = filename:join([proplists:get_value(data_dir, Config), + create_random_name("relcool-output")]), + {ok, State} = relcool:do(undefined, undefined, [], [LibDir1], 2, + OutputDir, ConfigFile), + + ?assert(not ec_file:exists(filename:join([OutputDir, "bin", "foo"]))), + ?assert(not ec_file:exists(filename:join([OutputDir, "bin", "foo-0.0.1"]))), + + [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rcl_state:realized_releases(State)), + AppSpecs = rcl_release:applications(Release), + ?assert(lists:keymember(stdlib, 1, AppSpecs)), + ?assert(lists:keymember(kernel, 1, AppSpecs)), + ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)), + ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)), + ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)), + ?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)), + ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)). + + +make_overridden_release(Config) -> + DataDir = proplists:get_value(data_dir, Config), + OverrideDir1 = filename:join([DataDir, create_random_name("override_dir_")]), + LibDir1 = proplists:get_value(lib1, Config), + [(fun({Name, Vsn}) -> + create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) + end)(App) + || + App <- + [{create_random_name("lib_app1_"), create_random_vsn()} + || _ <- lists:seq(1, 100)]], + OverrideApp = create_random_name("override_app"), + OverrideVsn = create_random_vsn(), + OverrideAppDir = filename:join(OverrideDir1, OverrideApp ++ "-" ++ OverrideVsn), + OverrideAppName = erlang:list_to_atom(OverrideApp), + + create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), + create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []), + create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), + create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), + create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), + + create_app(OverrideDir1, OverrideApp, OverrideVsn, [stdlib,kernel], []), + + ConfigFile = filename:join([LibDir1, "relcool.config"]), + write_config(ConfigFile, + [{release, {foo, "0.0.1"}, + [goal_app_1, + erlang:list_to_atom(OverrideApp), + goal_app_2]}]), + OutputDir = filename:join([proplists:get_value(data_dir, Config), + create_random_name("relcool-output")]), + {ok, Cwd} = file:get_cwd(), + {ok, State} = relcool:do(Cwd, undefined, undefined, [], [LibDir1], 2, + OutputDir, [{OverrideAppName, OverrideAppDir}], + ConfigFile), + [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rcl_state:realized_releases(State)), + AppSpecs = rcl_release:applications(Release), + ?assert(lists:keymember(stdlib, 1, AppSpecs)), + ?assert(lists:keymember(kernel, 1, AppSpecs)), + ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)), + ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)), + ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)), + ?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)), + ?assert(lists:member({OverrideAppName, OverrideVsn}, AppSpecs)), + ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)), + {ok, Real} = file:read_link(filename:join([OutputDir, "lib", + OverrideApp ++ "-" ++ OverrideVsn])), + ?assertMatch(OverrideAppDir, Real). + +make_skip_app_release(Config) -> + DataDir = proplists:get_value(data_dir, Config), + SkipAppDir1 = filename:join([DataDir, create_random_name("skip_app_dir_")]), + LibDir1 = proplists:get_value(lib1, Config), + [(fun({Name, Vsn}) -> + create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) + end)(App) + || + App <- + [{create_random_name("lib_app1_"), create_random_vsn()} + || _ <- lists:seq(1, 100)]], + SkipAppApp = create_random_name("skip_app_app"), + SkipAppVsn = create_random_vsn(), + SkipAppAppName = erlang:list_to_atom(SkipAppApp), + + create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), + create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []), + create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), + create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), + create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), + + create_empty_app(SkipAppDir1, SkipAppApp, SkipAppVsn, [stdlib,kernel], []), + + ConfigFile = filename:join([LibDir1, "relcool.config"]), + write_config(ConfigFile, + [{release, {foo, "0.0.1"}, + [goal_app_1, + goal_app_2]}, + {skip_apps, [erlang:list_to_atom(SkipAppApp)]}]), + OutputDir = filename:join([proplists:get_value(data_dir, Config), + create_random_name("relcool-output")]), + {ok, Cwd} = file:get_cwd(), + {ok, State} = relcool:do(Cwd, undefined, undefined, [], [LibDir1], 2, + OutputDir, [], + ConfigFile), + [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rcl_state:realized_releases(State)), + AppSpecs = rcl_release:applications(Release), + ?assert(lists:keymember(stdlib, 1, AppSpecs)), + ?assert(lists:keymember(kernel, 1, AppSpecs)), + ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)), + ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)), + ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)), + ?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)), + ?assertNot(lists:member({SkipAppAppName, SkipAppVsn}, AppSpecs)), + ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)). + +make_implicit_config_release(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + FooRoot = filename:join([LibDir1, "foodir1", "foodir2"]), + filelib:ensure_dir(filename:join([FooRoot, "tmp"])), + [(fun({Name, Vsn}) -> + create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) + end)(App) + || + App <- + [{create_random_name("lib_app1_"), create_random_vsn()} + || _ <- lists:seq(1, 100)]], + + create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), + create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []), + create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), + create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), + create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), + + ConfigFile = filename:join([LibDir1, "relcool.config"]), + write_config(ConfigFile, + [{release, {foo, "0.0.1"}, + [goal_app_1, + goal_app_2]}]), + OutputDir = filename:join([proplists:get_value(data_dir, Config), + create_random_name("relcool-output")]), + ok = file:set_cwd(FooRoot), + {ok, FooRoot} = file:get_cwd(), + {ok, State} = relcool:do(undefined, undefined, [], [LibDir1], 2, + OutputDir, undefined), + [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rcl_state:realized_releases(State)), + ?assert(ec_file:exists(OutputDir)), + AppSpecs = rcl_release:applications(Release), + ?assert(lists:keymember(stdlib, 1, AppSpecs)), + ?assert(lists:keymember(kernel, 1, AppSpecs)), + ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)), + ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)), + ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)), + ?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)), + ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)). + +make_rerun_overridden_release(Config) -> + DataDir = proplists:get_value(data_dir, Config), + OverrideDir1 = filename:join([DataDir, create_random_name("override_dir_")]), + LibDir1 = proplists:get_value(lib1, Config), + [(fun({Name, Vsn}) -> + create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) + end)(App) + || + App <- + [{create_random_name("lib_app1_"), create_random_vsn()} + || _ <- lists:seq(1, 100)]], + OverrideApp = create_random_name("override_app"), + OverrideVsn = create_random_vsn(), + OverrideAppDir = filename:join(OverrideDir1, OverrideApp ++ "-" + ++ OverrideVsn), + OverrideAppName = erlang:list_to_atom(OverrideApp), + + create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), + create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []), + create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), + create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), + create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), + + create_app(OverrideDir1, OverrideApp, OverrideVsn, [stdlib,kernel], []), + + ConfigFile = filename:join([LibDir1, "relcool.config"]), + write_config(ConfigFile, + [{release, {foo, "0.0.1"}, + [goal_app_1, + erlang:list_to_atom(OverrideApp), + goal_app_2]}]), + OutputDir = filename:join([proplists:get_value(data_dir, Config), + create_random_name("relcool-output")]), + {ok, Cwd} = file:get_cwd(), + {ok, _} = relcool:do(Cwd, undefined, undefined, [], [LibDir1], 2, + OutputDir, [{OverrideAppName, OverrideAppDir}], + ConfigFile), + + %% Now we run it again to see if it fails. + {ok, State} = relcool:do(Cwd,undefined, undefined, [], [LibDir1], 2, + OutputDir, [{OverrideAppName, OverrideAppDir}], + ConfigFile), + + [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rcl_state:realized_releases(State)), + AppSpecs = rcl_release:applications(Release), + ?assert(lists:keymember(stdlib, 1, AppSpecs)), + ?assert(lists:keymember(kernel, 1, AppSpecs)), + ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)), + ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)), + ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)), + ?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)), + ?assert(lists:member({OverrideAppName, OverrideVsn}, AppSpecs)), + ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)), + {ok, Real} = file:read_link(filename:join([OutputDir, "lib", + OverrideApp ++ "-" ++ OverrideVsn])), + ?assertMatch(OverrideAppDir, Real). + +overlay_release(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + [(fun({Name, Vsn}) -> + create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) + end)(App) + || + App <- + [{create_random_name("lib_app1_"), create_random_vsn()} + || _ <- lists:seq(1, 100)]], + + create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), + create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []), + create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), + create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), + create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), + + ConfigFile = filename:join([LibDir1, "relcool.config"]), + OverlayVars = filename:join([LibDir1, "vars.config"]), + Template = filename:join([LibDir1, "test_template"]), + write_config(ConfigFile, + [{overlay_vars, OverlayVars}, + {overlay, [{mkdir, "{{target_dir}}/fooo"}, + {copy, OverlayVars, + "{{target_dir}}/{{foo_dir}}/vars.config"}, + {copy, OverlayVars, + "{{target_dir}}/{{yahoo}}/"}, + {template, Template, + "{{target_dir}}/test_template_resolved"}]}, + {release, {foo, "0.0.1"}, + [goal_app_1, + goal_app_2]}]), + + VarsFile = filename:join([LibDir1, "vars.config"]), + write_config(VarsFile, [{yahoo, "yahoo"}, + {yahoo2, [{foo, "bar"}]}, + {yahoo3, [{bar, "{{yahoo}}/{{yahoo2.foo}}"}]}, + {foo_dir, "foodir"}]), + + TemplateFile = filename:join([LibDir1, "test_template"]), + ok = file:write_file(TemplateFile, test_template_contents()), + {ok, FileInfo} = file:read_file_info(TemplateFile), + ok = file:write_file_info(TemplateFile, FileInfo#file_info{mode=8#00777}), + + OutputDir = filename:join([proplists:get_value(data_dir, Config), + create_random_name("relcool-output")]), + + {ok, State} = relcool:do(undefined, undefined, [], [LibDir1], 2, + OutputDir, ConfigFile), + + [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rcl_state:realized_releases(State)), + AppSpecs = rcl_release:applications(Release), + ?assert(lists:keymember(stdlib, 1, AppSpecs)), + ?assert(lists:keymember(kernel, 1, AppSpecs)), + ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)), + ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)), + ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)), + ?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)), + ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)), + + ?assert(ec_file:exists(filename:join(OutputDir, "fooo"))), + ?assert(ec_file:exists(filename:join([OutputDir, "foodir", "vars.config"]))), + ?assert(ec_file:exists(filename:join([OutputDir, "yahoo", "vars.config"]))), + + TemplateData = case file:consult(filename:join([OutputDir, "test_template_resolved"])) of + {ok, Details} -> + Details; + Error -> + erlang:throw({failed_to_consult, Error}) + end, + {ok, ReadFileInfo} = file:read_file_info(filename:join([OutputDir, "test_template_resolved"])), + ?assertEqual(8#100777, ReadFileInfo#file_info.mode), + + ?assertEqual(erlang:system_info(version), + proplists:get_value(erts_vsn, TemplateData)), + ?assertEqual(erlang:system_info(version), + proplists:get_value(release_erts_version, TemplateData)), + ?assertEqual("0.0.1", + proplists:get_value(release_version, TemplateData)), + ?assertEqual(foo, + proplists:get_value(release_name, TemplateData)), + ?assertEqual([kernel,stdlib,lib_dep_1,non_goal_2,non_goal_1, + goal_app_1,goal_app_2], + proplists:get_value(release_applications, TemplateData)), + ?assert(proplists:is_defined(std_version, TemplateData)), + ?assert(proplists:is_defined(kernel_version, TemplateData)), + ?assertEqual("0.0.1", + proplists:get_value(non_goal_1_version, TemplateData)), + ?assertEqual("0.0.1", + proplists:get_value(non_goal_2_version, TemplateData)), + ?assertEqual("0.0.1", + proplists:get_value(goal_app_1_version, TemplateData)), + ?assertEqual("0.0.1", + proplists:get_value(goal_app_2_version, TemplateData)), + ?assertEqual("0.0.1", + proplists:get_value(lib_dep_1, TemplateData)), + ?assert(proplists:is_defined(lib_dep_1_dir, TemplateData)), + ?assertEqual([stdlib,kernel], + proplists:get_value(lib_dep_1_active, TemplateData)), + ?assertEqual([], + proplists:get_value(lib_dep_1_library, TemplateData)), + ?assertEqual("false", + proplists:get_value(lib_dep_1_link, TemplateData)), + ?assertEqual("(2:debug)", + proplists:get_value(log, TemplateData)), + ?assertEqual(OutputDir, + proplists:get_value(output_dir, TemplateData)), + ?assertEqual(OutputDir, + proplists:get_value(target_dir, TemplateData)), + ?assertEqual([], + proplists:get_value(overridden, TemplateData)), + ?assertEqual([""], + proplists:get_value(goals, TemplateData)), + ?assert(proplists:is_defined(lib_dirs, TemplateData)), + ?assert(proplists:is_defined(config_file, TemplateData)), + ?assertEqual([""], + proplists:get_value(goals, TemplateData)), + ?assertEqual([], + proplists:get_value(sys_config, TemplateData)), + ?assert(proplists:is_defined(root_dir, TemplateData)), + ?assertEqual(foo, + proplists:get_value(default_release_name, TemplateData)), + ?assertEqual("0.0.1", + proplists:get_value(default_release_version, TemplateData)), + ?assertEqual("foo-0.0.1", + proplists:get_value(default_release, TemplateData)), + ?assertEqual("yahoo", + proplists:get_value(yahoo, TemplateData)), + ?assertEqual("bar", + proplists:get_value(yahoo2_foo, TemplateData)), + ?assertEqual("foodir", + proplists:get_value(foo_dir, TemplateData)), + ?assertEqual("yahoo/bar", + proplists:get_value(yahoo3, TemplateData)). + +make_goalless_release(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + [(fun({Name, Vsn}) -> + create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) + end)(App) + || + App <- + [{create_random_name("lib_app1_"), create_random_vsn()} + || _ <- lists:seq(1, 100)]], + + create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), + create_app(LibDir1, "lib_dep_1", "0.0.1", [], []), + create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), + create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), + create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), + + ConfigFile = filename:join([LibDir1, "relcool.config"]), + write_config(ConfigFile, + [{release, {foo, "0.0.1"}, + []}]), + OutputDir = filename:join([proplists:get_value(data_dir, Config), + create_random_name("relcool-output")]), + ?assertMatch({error,{rcl_prv_release,no_goals_specified}}, + relcool:do(undefined, undefined, [], [LibDir1], 2, + OutputDir, ConfigFile)). + +make_depfree_release(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + [(fun({Name, Vsn}) -> + create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) + end)(App) + || + App <- + [{create_random_name("lib_app1_"), create_random_vsn()} + || _ <- lists:seq(1, 100)]], + + create_app(LibDir1, "goal_app_1", "0.0.1", [kernel,stdlib], []), + create_app(LibDir1, "lib_dep_1", "0.0.1", [kernel,stdlib], []), + create_app(LibDir1, "goal_app_2", "0.0.1", [kernel,stdlib], []), + create_app(LibDir1, "non_goal_1", "0.0.1", [kernel,stdlib], []), + create_app(LibDir1, "non_goal_2", "0.0.1", [kernel,stdlib], []), + + ConfigFile = filename:join([LibDir1, "relcool.config"]), + write_config(ConfigFile, + [{release, {foo, "0.0.1"}, + [goal_app_1]}]), + OutputDir = filename:join([proplists:get_value(data_dir, Config), + create_random_name("relcool-output")]), + {ok, State} = relcool:do(undefined, undefined, [], [LibDir1], 2, + OutputDir, ConfigFile), + [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rcl_state:realized_releases(State)), + AppSpecs = rcl_release:applications(Release), + ?assert(lists:keymember(stdlib, 1, AppSpecs)), + ?assert(lists:keymember(kernel, 1, AppSpecs)). + +make_relup_release(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + [(fun({Name, Vsn}) -> + create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) + end)(App) + || + App <- + [{create_random_name("lib_app1_"), create_random_vsn()} + || _ <- lists:seq(1, 100)]], + + create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), + create_app(LibDir1, "goal_app_1", "0.0.2", [stdlib,kernel,non_goal_1], []), + {ok, GA1} = create_app(LibDir1, "goal_app_1", "0.0.3", [stdlib,kernel,non_goal_1], []), + create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []), + create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), + create_app(LibDir1, "goal_app_2", "0.0.2", [stdlib,kernel,goal_app_1,non_goal_2], []), + {ok, GA2} = create_app(LibDir1, "goal_app_2", "0.0.3", [stdlib,kernel,goal_app_1,non_goal_2], []), + create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), + create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), + + write_appup_file(GA1, "0.0.2"), + write_appup_file(GA2, "0.0.2"), + + ConfigFile = filename:join([LibDir1, "relcool.config"]), + write_config(ConfigFile, + [{release, {foo, "0.0.1"}, + [sasl, + {goal_app_1, "0.0.1"}, + {goal_app_2, "0.0.1"}]}, + {release, {foo, "0.0.2"}, + [sasl, + {goal_app_1, "0.0.2"}, + {goal_app_2, "0.0.2"}]}, + {release, {foo, "0.0.3"}, + [sasl, + {goal_app_1, "0.0.3"}, + {goal_app_2, "0.0.3"}]}]), + OutputDir = filename:join([proplists:get_value(data_dir, Config), + create_random_name("relcool-output")]), + {ok, _} = relcool:do(foo, "0.0.1", [], [LibDir1], 2, + OutputDir, ConfigFile), + {ok, _} = relcool:do(foo, "0.0.2", [], [LibDir1], 2, + OutputDir, ConfigFile), + {ok, State} = relcool:do([{relname, foo}, + {relvsn, "0.0.3"}, + {goals, []}, + {lib_dirs, [LibDir1]}, + {log_level, 2}, + {output_dir, OutputDir}, + {config, ConfigFile}], ["relup"]), + + %% we should have one 'resolved' release and three discovered realized_releases. + ?assertMatch([{foo, "0.0.1"}, + {foo, "0.0.2"}, + {foo, "0.0.3"}], + lists:sort(ec_dictionary:keys(rcl_state:realized_releases(State)))), + Release = ec_dictionary:get({foo, "0.0.3"}, rcl_state:realized_releases(State)), + ?assert(rcl_release:realized(Release)), + ?assert(not rcl_release:realized(ec_dictionary:get({foo, "0.0.2"}, + rcl_state:realized_releases(State)))), + ?assert(not rcl_release:realized(ec_dictionary:get({foo, "0.0.1"}, + rcl_state:realized_releases(State)))), + + ?assertMatch({ok, [{"0.0.3", + [{"0.0.2",[],[point_of_no_return]}], + [{"0.0.2",[],[point_of_no_return]}]}]}, + file:consult(filename:join(filename:dirname(rcl_release:relfile(Release)), + filename:basename(rcl_release:relfile(Release), ".rel") ++ + ".relup"))), + + ?assertMatch(foo, rcl_release:name(Release)), + ?assertMatch("0.0.3", rcl_release:vsn(Release)), + AppSpecs = rcl_release:applications(Release), + ?assert(lists:keymember(stdlib, 1, AppSpecs)), + ?assert(lists:keymember(kernel, 1, AppSpecs)), + ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)), + ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)), + ?assert(lists:member({goal_app_1, "0.0.3"}, AppSpecs)), + ?assert(lists:member({goal_app_2, "0.0.3"}, AppSpecs)), + ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)). + + +make_relup_release2(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + [(fun({Name, Vsn}) -> + create_app(LibDir1, Name, Vsn, [kernel, stdlib], []) + end)(App) + || + App <- + [{create_random_name("lib_app1_"), create_random_vsn()} + || _ <- lists:seq(1, 100)]], + + create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []), + create_app(LibDir1, "goal_app_1", "0.0.2", [stdlib,kernel,non_goal_1], []), + {ok, GA1} = create_app(LibDir1, "goal_app_1", "0.0.3", [stdlib,kernel,non_goal_1], []), + create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []), + create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []), + create_app(LibDir1, "goal_app_2", "0.0.2", [stdlib,kernel,goal_app_1,non_goal_2], []), + {ok, GA2} = create_app(LibDir1, "goal_app_2", "0.0.3", [stdlib,kernel,goal_app_1,non_goal_2], []), + create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]), + create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []), + + write_appup_file(GA1, "0.0.1"), + write_appup_file(GA2, "0.0.1"), + + ConfigFile = filename:join([LibDir1, "relcool.config"]), + write_config(ConfigFile, + [{release, {foo, "0.0.1"}, + [sasl, + {goal_app_1, "0.0.1"}, + {goal_app_2, "0.0.1"}]}, + {release, {foo, "0.0.2"}, + [sasl, + {goal_app_1, "0.0.2"}, + {goal_app_2, "0.0.2"}]}, + {release, {foo, "0.0.3"}, + [sasl, + {goal_app_1, "0.0.3"}, + {goal_app_2, "0.0.3"}]}]), + OutputDir = filename:join([proplists:get_value(data_dir, Config), + create_random_name("relcool-output")]), + {ok, _} = relcool:do(foo, "0.0.1", [], [LibDir1], 2, + OutputDir, ConfigFile), + {ok, _} = relcool:do(foo, "0.0.2", [], [LibDir1], 2, + OutputDir, ConfigFile), + {ok, State} = relcool:do([{relname, foo}, + {relvsn, "0.0.3"}, + {upfrom, "0.0.1"}, + {goals, []}, + {lib_dirs, [LibDir1]}, + {log_level, 2}, + {output_dir, OutputDir}, + {config, ConfigFile}], ["relup"]), + + %% we should have one 'resolved' release and three discovered realized_releases. + ?assertMatch([{foo, "0.0.1"}, + {foo, "0.0.2"}, + {foo, "0.0.3"}], + lists:sort(ec_dictionary:keys(rcl_state:realized_releases(State)))), + Release = ec_dictionary:get({foo, "0.0.3"}, rcl_state:realized_releases(State)), + ?assert(rcl_release:realized(Release)), + ?assert(not rcl_release:realized(ec_dictionary:get({foo, "0.0.2"}, + rcl_state:realized_releases(State)))), + ?assert(not rcl_release:realized(ec_dictionary:get({foo, "0.0.1"}, + rcl_state:realized_releases(State)))), + + ?assertMatch({ok, [{"0.0.3", + [{"0.0.1",[],[point_of_no_return]}], + [{"0.0.1",[],[point_of_no_return]}]}]}, + file:consult(filename:join(filename:dirname(rcl_release:relfile(Release)), + filename:basename(rcl_release:relfile(Release), ".rel") ++ + ".relup"))), + + ?assertMatch(foo, rcl_release:name(Release)), + ?assertMatch("0.0.3", rcl_release:vsn(Release)), + AppSpecs = rcl_release:applications(Release), + ?assert(lists:keymember(stdlib, 1, AppSpecs)), + ?assert(lists:keymember(kernel, 1, AppSpecs)), + ?assert(lists:member({non_goal_1, "0.0.1"}, AppSpecs)), + ?assert(lists:member({non_goal_2, "0.0.1"}, AppSpecs)), + ?assert(lists:member({goal_app_1, "0.0.3"}, AppSpecs)), + ?assert(lists:member({goal_app_2, "0.0.3"}, AppSpecs)), + ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)). + + +make_one_app_top_level_release(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + {ok, AppInfo} = create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel], []), + AppDir = rcl_app_info:dir(AppInfo), + ConfigFile = filename:join([AppDir, "relcool.config"]), + write_config(ConfigFile, + [{release, {foo, "0.0.1"}, + [{goal_app_1, "0.0.1"}]}]), + + OutputDir = filename:join([AppDir, + create_random_name("relcool-output")]), + + {ok, Cwd} = file:get_cwd(), + ok = file:set_cwd(AppDir), + {ok, State} = relcool:do(undefined, undefined, [], [], 2, + OutputDir, ConfigFile), + ok = file:set_cwd(Cwd), + [{{foo, "0.0.1"}, Release}] = ec_dictionary:to_list(rcl_state:realized_releases(State)), + AppSpecs = rcl_release:applications(Release), + ?assert(lists:keymember(stdlib, 1, AppSpecs)), + ?assert(lists:keymember(kernel, 1, AppSpecs)), + ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)). + + +%%%=================================================================== +%%% Helper Functions +%%%=================================================================== + +create_app(Dir, Name, Vsn, Deps, LibDeps) -> + AppDir = filename:join([Dir, Name ++ "-" ++ Vsn]), + write_app_file(AppDir, Name, Vsn, Deps, LibDeps), + write_beam_file(AppDir, Name), + rcl_app_info:new(erlang:list_to_atom(Name), Vsn, AppDir, + Deps, []). + +create_empty_app(Dir, Name, Vsn, Deps, LibDeps) -> + AppDir = filename:join([Dir, Name ++ "-" ++ Vsn]), + write_app_file(AppDir, Name, Vsn, Deps, LibDeps), + rcl_app_info:new(erlang:list_to_atom(Name), Vsn, AppDir, + Deps, []). + +write_beam_file(Dir, Name) -> + Beam = filename:join([Dir, "ebin", "not_a_real_beam" ++ Name ++ ".beam"]), + ok = filelib:ensure_dir(Beam), + ok = ec_file:write_term(Beam, testing_purposes_only). + +write_appup_file(AppInfo, DownVsn) -> + Dir = rcl_app_info:dir(AppInfo), + Name = rcl_util:to_string(rcl_app_info:name(AppInfo)), + Vsn = rcl_app_info:vsn_as_string(AppInfo), + Filename = filename:join([Dir, "ebin", Name ++ ".appup"]), + ok = filelib:ensure_dir(Filename), + ok = ec_file:write_term(Filename, {Vsn, [{DownVsn, []}], [{DownVsn, []}]}). + +write_app_file(Dir, Name, Version, Deps, LibDeps) -> + Filename = filename:join([Dir, "ebin", Name ++ ".app"]), + ok = filelib:ensure_dir(Filename), + ok = ec_file:write_term(Filename, get_app_metadata(Name, Version, Deps, LibDeps)). + +get_app_metadata(Name, Vsn, Deps, LibDeps) -> + {application, erlang:list_to_atom(Name), + [{description, ""}, + {vsn, Vsn}, + {modules, []}, + {included_applications, LibDeps}, + {registered, []}, + {applications, Deps}]}. + +create_random_name(Name) -> + random:seed(erlang:now()), + Name ++ erlang:integer_to_list(random:uniform(1000000)). + +create_random_vsn() -> + random:seed(erlang:now()), + lists:flatten([erlang:integer_to_list(random:uniform(100)), + ".", erlang:integer_to_list(random:uniform(100)), + ".", erlang:integer_to_list(random:uniform(100))]). + +write_config(Filename, Values) -> + ok = ec_file:write(Filename, + [io_lib:format("~p.\n", [Val]) || Val <- Values]). + +test_template_contents() -> + "{erts_vsn, \"{{erts_vsn}}\"}.\n" + "{release_erts_version, \"{{release_erts_version}}\"}.\n" + "{release_name, {{release_name}}}.\n" + "{rel_vsn, \"{{release_version}}\"}.\n" + "{release_version, \"{{release_version}}\"}.\n" + "{release_applications, [{{ release_applications|join:\", \" }}]}.\n" + "{std_version, \"{{release.stdlib.version}}\"}.\n" + "{kernel_version, \"{{release.kernel.version}}\"}.\n" + "{non_goal_1_version, \"{{release.non_goal_1.version}}\"}.\n" + "{non_goal_2_version, \"{{release.non_goal_2.version}}\"}.\n" + "{goal_app_1_version, \"{{release.goal_app_1.version}}\"}.\n" + "{goal_app_2_version, \"{{release.goal_app_2.version}}\"}.\n" + "{lib_dep_1, \"{{release.lib_dep_1.version}}\"}.\n" + "{lib_dep_1_dir, \"{{release.lib_dep_1.dir}}\"}.\n" + "{lib_dep_1_active, [{{ release.lib_dep_1.active_dependencies|join:\", \" }}]}.\n" + "{lib_dep_1_library, [{{ release.lib_dep_1.library_dependencies|join:\", \" }}]}.\n" + "{lib_dep_1_link, \"{{release.lib_dep_1.link}}\"}.\n" + "{log, \"{{log}}\"}.\n" + "{output_dir, \"{{output_dir}}\"}.\n" + "{target_dir, \"{{target_dir}}\"}.\n" + "{overridden, [{{ overridden|join:\", \" }}]}.\n" + "{goals, [\"{{ goals|join:\", \" }}\"]}.\n" + "{lib_dirs, [\"{{ lib_dirs|join:\", \" }}\"]}.\n" + "{config_file, \"{{ config_file }}\"}.\n" + "{providers, [{{ providers|join:\", \" }}]}.\n" + "{sys_config, \"{{sys_config}}\"}.\n" + "{root_dir, \"{{root_dir}}\"}.\n" + "{default_release_name, {{default_release_name}}}.\n" + "{default_release_version, \"{{default_release_version}}\"}.\n" + "{default_release, \"{{default_release}}\"}.\n" + "{yahoo, \"{{yahoo}}\"}.\n" + "{yahoo2_foo, \"{{yahoo2.foo}}\"}.\n" + "{foo_dir, \"{{foo_dir}}\"}.\n" + "{yahoo3, \"{{yahoo3.bar}}\"}.\n". -- cgit v1.2.3