You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

252 lines
8.8 KiB

пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
  1. -module(rebar_deps_SUITE).
  2. -compile(export_all).
  3. -include_lib("common_test/include/ct.hrl").
  4. -include_lib("eunit/include/eunit.hrl").
  5. all() -> [sub_app_deps, newly_added_dep, {group, git}, {group, pkg}].
  6. groups() ->
  7. [{all, [], [flat, pick_highest_left, pick_highest_right,
  8. pick_smallest1, pick_smallest2,
  9. circular1, circular2, circular_skip]},
  10. {git, [], [{group, all}]},
  11. {pkg, [], [{group, all}]}].
  12. init_per_suite(Config) ->
  13. application:start(meck),
  14. Config.
  15. end_per_suite(_Config) ->
  16. application:stop(meck).
  17. init_per_group(git, Config) ->
  18. [{deps_type, git} | Config];
  19. init_per_group(pkg, Config) ->
  20. [{deps_type, pkg} | Config];
  21. init_per_group(_, Config) ->
  22. Config.
  23. end_per_group(_, Config) ->
  24. Config.
  25. init_per_testcase(newly_added_dep, Config) ->
  26. rebar_test_utils:init_rebar_state(Config);
  27. init_per_testcase(sub_app_deps, Config) ->
  28. rebar_test_utils:init_rebar_state(Config);
  29. init_per_testcase(Case, Config) ->
  30. {Deps, Warnings, Expect} = deps(Case),
  31. Expected = case Expect of
  32. {ok, List} -> {ok, format_expected_deps(List)};
  33. {error, Reason} -> {error, Reason}
  34. end,
  35. DepsType = ?config(deps_type, Config),
  36. mock_warnings(),
  37. [{expect, Expected},
  38. {warnings, Warnings}
  39. | setup_project(Case, Config, rebar_test_utils:expand_deps(DepsType, Deps))].
  40. end_per_testcase(_, Config) ->
  41. meck:unload(),
  42. Config.
  43. format_expected_deps(Deps) ->
  44. [case Dep of
  45. {N,V} -> {dep, N, V};
  46. N -> {dep, N}
  47. end || Dep <- Deps].
  48. %% format:
  49. %% {Spec,
  50. %% [Warning],
  51. %% {ok, Result} | {error, Reason}}
  52. %%
  53. %% Spec is a list of levelled dependencies of two possible forms:
  54. %% - {"Name", Spec}
  55. %% - {"Name", "Vsn", Spec}
  56. %%
  57. %% Warnings are going to match on mocked ?WARN(...)
  58. %% calls to be evaluated. An empty list means we do not care about
  59. %% warnings, not that no warnings will be printed. This means
  60. %% the list of warning isn't interpreted to be exhaustive, and more
  61. %% warnings may be generated than are listed.
  62. deps(flat) ->
  63. {[{"B", []},
  64. {"C", []}],
  65. [],
  66. {ok, ["B", "C"]}};
  67. deps(pick_highest_left) ->
  68. {[{"B", [{"C", "2", []}]},
  69. {"C", "1", []}],
  70. [{"C","2"}],
  71. {ok, ["B", {"C", "1"}]}};
  72. deps(pick_highest_right) ->
  73. {[{"B", "1", []},
  74. {"C", [{"B", "2", []}]}],
  75. [{"B","2"}],
  76. {ok, [{"B","1"}, "C"]}};
  77. deps(pick_smallest1) ->
  78. {[{"B", [{"D", "1", []}]},
  79. {"C", [{"D", "2", []}]}],
  80. [{"D","2"}],
  81. %% we pick D1 because B < C
  82. {ok, ["B","C",{"D","1"}]}};
  83. deps(pick_smallest2) ->
  84. {[{"C", [{"D", "2", []}]},
  85. {"B", [{"D", "1", []}]}],
  86. [{"D","2"}],
  87. %% we pick D1 because B < C
  88. {ok, ["B","C",{"D","1"}]}};
  89. deps(circular1) ->
  90. {[{"B", [{"A", []}]}, % A is the top-level app
  91. {"C", []}],
  92. [],
  93. {error, {rebar_prv_install_deps, {cycles, [[<<"A">>,<<"B">>]]}}}};
  94. deps(circular2) ->
  95. {[{"B", [{"C", [{"B", []}]}]},
  96. {"C", []}],
  97. [],
  98. {error, {rebar_prv_install_deps, {cycles, [[<<"B">>,<<"C">>]]}}}};
  99. deps(circular_skip) ->
  100. %% Never spot the circular dep due to being to low in the deps tree
  101. %% in source deps
  102. {[{"B", [{"C", "2", [{"B", []}]}]},
  103. {"C", "1", [{"D",[]}]}],
  104. [{"C","2"}],
  105. {ok, ["B", {"C","1"}, "D"]}}.
  106. setup_project(Case, Config0, Deps) ->
  107. DepsType = ?config(deps_type, Config0),
  108. Config = rebar_test_utils:init_rebar_state(
  109. Config0,
  110. atom_to_list(Case)++"_"++atom_to_list(DepsType)++"_"
  111. ),
  112. AppDir = ?config(apps, Config),
  113. rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]),
  114. TopDeps = rebar_test_utils:top_level_deps(Deps),
  115. RebarConf = rebar_test_utils:create_config(AppDir, [{deps, TopDeps}]),
  116. case DepsType of
  117. git ->
  118. mock_git_resource:mock([{deps, rebar_test_utils:flat_deps(Deps)}]);
  119. pkg ->
  120. mock_pkg_resource:mock([{pkgdeps, flat_pkgdeps(Deps)}])
  121. end,
  122. [{rebarconfig, RebarConf} | Config].
  123. flat_pkgdeps([]) -> [];
  124. flat_pkgdeps([{{pkg, Name, Vsn}, Deps} | Rest]) ->
  125. [{{iolist_to_binary(Name),iolist_to_binary(Vsn)}, rebar_test_utils:top_level_deps(Deps)}]
  126. ++
  127. flat_pkgdeps(Deps)
  128. ++
  129. flat_pkgdeps(Rest).
  130. app_vsn([]) -> [];
  131. app_vsn([{Source, Deps} | Rest]) ->
  132. {Name, Vsn} = case Source of
  133. {pkg, N, V} -> {N,V};
  134. {N,V,_Ref} -> {N,V}
  135. end,
  136. [{Name, Vsn}] ++ app_vsn(Deps) ++ app_vsn(Rest).
  137. mock_warnings() ->
  138. %% just let it do its thing, we check warnings through
  139. %% the call log.
  140. meck:new(rebar_log, [no_link, passthrough]).
  141. %%% TESTS %%%
  142. flat(Config) -> run(Config).
  143. pick_highest_left(Config) -> run(Config).
  144. pick_highest_right(Config) -> run(Config).
  145. pick_smallest1(Config) -> run(Config).
  146. pick_smallest2(Config) -> run(Config).
  147. circular1(Config) -> run(Config).
  148. circular2(Config) -> run(Config).
  149. circular_skip(Config) -> run(Config).
  150. %% Test that the deps of project apps that have their own rebar.config
  151. %% are included, but that top level rebar.config deps take precedence
  152. sub_app_deps(Config) ->
  153. AppDir = ?config(apps, Config),
  154. Deps = rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}
  155. ,{"b", "1.0.0", []}
  156. ,{"b", "2.0.0", []}]),
  157. mock_git_resource:mock([{deps, rebar_test_utils:flat_deps(Deps)}]),
  158. Name = rebar_test_utils:create_random_name("sub_app1_"),
  159. Vsn = rebar_test_utils:create_random_vsn(),
  160. SubAppsDir = filename:join([AppDir, Name]),
  161. SubDeps = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}
  162. ,{"b", "2.0.0", []}])),
  163. rebar_test_utils:create_app(SubAppsDir, Name, Vsn, [kernel, stdlib]),
  164. rebar_test_utils:create_config(SubAppsDir, [{deps, SubDeps}]),
  165. TopDeps = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [{"b", "1.0.0", []}])),
  166. {ok, RebarConfig} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, TopDeps}])),
  167. rebar_test_utils:run_and_check(
  168. Config, RebarConfig, ["compile"],
  169. {ok, [{app, Name}, {dep, "a"}, {dep, "b", "1.0.0"}]}).
  170. %% Newly added dependency after locking
  171. newly_added_dep(Config) ->
  172. AppDir = ?config(apps, Config),
  173. Deps = rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}
  174. ,{"b", "1.0.0", [{"c", "1.0.0", []}]}
  175. ,{"c", "2.0.0", []}]),
  176. mock_git_resource:mock([{deps, rebar_test_utils:flat_deps(Deps)}]),
  177. Name = rebar_test_utils:create_random_name("app_"),
  178. Vsn = rebar_test_utils:create_random_vsn(),
  179. SubAppsDir = filename:join([AppDir, Name]),
  180. rebar_test_utils:create_app(SubAppsDir, Name, Vsn, [kernel, stdlib]),
  181. TopDeps = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [{"b", "1.0.0", []}])),
  182. {ok, RebarConfig} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, TopDeps}])),
  183. rebar_test_utils:run_and_check(
  184. Config, RebarConfig, ["compile"],
  185. {ok, [{app, Name}, {dep, "b", "1.0.0"}, {dep, "c", "1.0.0"}]}),
  186. %% Add a and c to top level
  187. TopDeps2 = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}
  188. ,{"c", "2.0.0", []}
  189. ,{"b", "1.0.0", []}])),
  190. {ok, RebarConfig2} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, TopDeps2}])),
  191. LockFile = filename:join(AppDir, "rebar.lock"),
  192. RebarConfig3 = rebar_config:merge_locks(RebarConfig2,
  193. rebar_config:consult_file(LockFile)),
  194. %% a should now be installed and c should not change
  195. rebar_test_utils:run_and_check(
  196. Config, RebarConfig3, ["compile"],
  197. {ok, [{app, Name}, {dep, "a"}, {dep, "b", "1.0.0"}, {dep, "c", "1.0.0"}]}).
  198. run(Config) ->
  199. {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
  200. rebar_test_utils:run_and_check(
  201. Config, RebarConfig, ["install_deps"], ?config(expect, Config)
  202. ),
  203. check_warnings(warning_calls(), ?config(warnings, Config), ?config(deps_type, Config)).
  204. warning_calls() ->
  205. History = meck:history(rebar_log),
  206. [{Str, Args} || {_, {rebar_log, log, [warn, Str, Args]}, _} <- History].
  207. check_warnings(_, [], _) ->
  208. ok;
  209. check_warnings(Warns, [{Name, Vsn} | Rest], Type) ->
  210. ct:pal("Checking for warning ~p in ~p", [{Name,Vsn},Warns]),
  211. ?assert(in_warnings(Type, Warns, Name, Vsn)),
  212. check_warnings(Warns, Rest, Type).
  213. in_warnings(git, Warns, NameRaw, VsnRaw) ->
  214. Name = iolist_to_binary(NameRaw),
  215. 1 =< length([1 || {_, [AppName, {git, _, {_, Vsn}}]} <- Warns,
  216. AppName =:= Name, Vsn =:= VsnRaw]);
  217. in_warnings(pkg, Warns, NameRaw, VsnRaw) ->
  218. Name = iolist_to_binary(NameRaw),
  219. Vsn = iolist_to_binary(VsnRaw),
  220. 1 =< length([1 || {_, [AppName, AppVsn]} <- Warns,
  221. AppName =:= Name, AppVsn =:= Vsn]).