Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

285 wiersze
10 KiB

  1. -module(rebar_install_deps_SUITE).
  2. -compile(export_all).
  3. -include_lib("common_test/include/ct.hrl").
  4. -include_lib("eunit/include/eunit.hrl").
  5. -include_lib("kernel/include/file.hrl").
  6. all() -> [{group, git}, {group, pkg}].
  7. groups() ->
  8. [{all, [], [flat, pick_highest_left, pick_highest_right,
  9. pick_smallest1, pick_smallest2,
  10. circular1, circular2, circular_skip,
  11. fail_conflict, default_profile, nondefault_profile]},
  12. {git, [], [{group, all}]},
  13. {pkg, [], [{group, all}]}].
  14. init_per_suite(Config) ->
  15. application:start(meck),
  16. Config.
  17. end_per_suite(_Config) ->
  18. application:stop(meck).
  19. init_per_group(git, Config) ->
  20. [{deps_type, git} | Config];
  21. init_per_group(pkg, Config) ->
  22. [{deps_type, pkg} | Config];
  23. init_per_group(_, Config) ->
  24. Config.
  25. end_per_group(_, Config) ->
  26. Config.
  27. init_per_testcase(Case, Config) ->
  28. {Deps, Warnings, Expect} = deps(Case),
  29. Expected = case Expect of
  30. {ok, List} -> {ok, format_expected_deps(List)};
  31. Other -> Other
  32. end,
  33. DepsType = ?config(deps_type, Config),
  34. mock_warnings(),
  35. [{expect, Expected},
  36. {warnings, Warnings}
  37. | setup_project(Case, Config, rebar_test_utils:expand_deps(DepsType, Deps))].
  38. end_per_testcase(_, Config) ->
  39. meck:unload(),
  40. Config.
  41. format_expected_deps(Deps) ->
  42. [case Dep of
  43. {N,V} -> {dep, N, V};
  44. N -> {dep, N}
  45. end || Dep <- Deps].
  46. %% format:
  47. %% {Spec,
  48. %% [Warning],
  49. %% {ok, Result} | {error, Reason}}
  50. %%
  51. %% Spec is a list of levelled dependencies of two possible forms:
  52. %% - {"Name", Spec}
  53. %% - {"Name", "Vsn", Spec}
  54. %%
  55. %% Warnings are going to match on mocked ?WARN(...)
  56. %% calls to be evaluated. An empty list means we do not care about
  57. %% warnings, not that no warnings will be printed. This means
  58. %% the list of warning isn't interpreted to be exhaustive, and more
  59. %% warnings may be generated than are listed.
  60. deps(flat) ->
  61. {[{"B", []},
  62. {"C", []}],
  63. [],
  64. {ok, ["B", "C"]}};
  65. deps(pick_highest_left) ->
  66. {[{"B", [{"C", "2", []}]},
  67. {"C", "1", []}],
  68. [{"C","2"}],
  69. {ok, ["B", {"C", "1"}]}};
  70. deps(pick_highest_right) ->
  71. {[{"B", "1", []},
  72. {"C", [{"B", "2", []}]}],
  73. [{"B","2"}],
  74. {ok, [{"B","1"}, "C"]}};
  75. deps(pick_smallest1) ->
  76. {[{"B", [{"D", "1", []}]},
  77. {"C", [{"D", "2", []}]}],
  78. [{"D","2"}],
  79. %% we pick D1 because B < C
  80. {ok, ["B","C",{"D","1"}]}};
  81. deps(pick_smallest2) ->
  82. {[{"C", [{"D", "2", []}]},
  83. {"B", [{"D", "1", []}]}],
  84. [{"D","2"}],
  85. %% we pick D1 because B < C
  86. {ok, ["B","C",{"D","1"}]}};
  87. deps(circular1) ->
  88. {[{"B", [{"A", []}]}, % A is the top-level app
  89. {"C", []}],
  90. [],
  91. {error, {rebar_prv_install_deps, {cycles, [[<<"A">>,<<"B">>]]}}}};
  92. deps(circular2) ->
  93. {[{"B", [{"C", [{"B", []}]}]},
  94. {"C", []}],
  95. [],
  96. {error, {rebar_prv_install_deps, {cycles, [[<<"B">>,<<"C">>]]}}}};
  97. deps(circular_skip) ->
  98. %% Never spot the circular dep due to being to low in the deps tree
  99. %% in source deps
  100. {[{"B", [{"C", "2", [{"B", []}]}]},
  101. {"C", "1", [{"D",[]}]}],
  102. [{"C","2"}],
  103. {ok, ["B", {"C","1"}, "D"]}};
  104. deps(fail_conflict) ->
  105. {[{"B", [{"C", "2", []}]},
  106. {"C", "1", []}],
  107. [{"C","2"}],
  108. rebar_abort};
  109. deps(default_profile) ->
  110. {[{"B", []},
  111. {"C", []}],
  112. [],
  113. {ok, ["B", "C"]}};
  114. deps(nondefault_profile) ->
  115. {[{"B", []},
  116. {"C", []}],
  117. [],
  118. {ok, ["B", "C"]}}.
  119. setup_project(fail_conflict, Config0, Deps) ->
  120. DepsType = ?config(deps_type, Config0),
  121. Config = rebar_test_utils:init_rebar_state(
  122. Config0,
  123. "fail_conflict_"++atom_to_list(DepsType)++"_"
  124. ),
  125. AppDir = ?config(apps, Config),
  126. rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]),
  127. TopDeps = rebar_test_utils:top_level_deps(Deps),
  128. RebarConf = rebar_test_utils:create_config(AppDir, [{deps, TopDeps},
  129. {deps_error_on_conflict, true}]),
  130. case DepsType of
  131. git ->
  132. mock_git_resource:mock([{deps, rebar_test_utils:flat_deps(Deps)}]);
  133. pkg ->
  134. mock_pkg_resource:mock([{pkgdeps, rebar_test_utils:flat_pkgdeps(Deps)}])
  135. end,
  136. [{rebarconfig, RebarConf} | Config];
  137. setup_project(nondefault_profile, Config0, Deps) ->
  138. DepsType = ?config(deps_type, Config0),
  139. Config = rebar_test_utils:init_rebar_state(
  140. Config0,
  141. "nondefault_profile_"++atom_to_list(DepsType)++"_"
  142. ),
  143. AppDir = ?config(apps, Config),
  144. rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]),
  145. TopDeps = rebar_test_utils:top_level_deps(Deps),
  146. RebarConf = rebar_test_utils:create_config(AppDir, [{profiles, [
  147. {nondef, [{deps, TopDeps}]}
  148. ]}]),
  149. case DepsType of
  150. git ->
  151. mock_git_resource:mock([{deps, rebar_test_utils:flat_deps(Deps)}]);
  152. pkg ->
  153. mock_pkg_resource:mock([{pkgdeps, rebar_test_utils:flat_pkgdeps(Deps)}])
  154. end,
  155. [{rebarconfig, RebarConf} | Config];
  156. setup_project(Case, Config0, Deps) ->
  157. DepsType = ?config(deps_type, Config0),
  158. Config = rebar_test_utils:init_rebar_state(
  159. Config0,
  160. atom_to_list(Case)++"_installdeps_"++atom_to_list(DepsType)++"_"
  161. ),
  162. AppDir = ?config(apps, Config),
  163. rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]),
  164. TopDeps = rebar_test_utils:top_level_deps(Deps),
  165. RebarConf = rebar_test_utils:create_config(AppDir, [{deps, TopDeps}]),
  166. case DepsType of
  167. git ->
  168. mock_git_resource:mock([{deps, rebar_test_utils:flat_deps(Deps)}]);
  169. pkg ->
  170. mock_pkg_resource:mock([{pkgdeps, rebar_test_utils:flat_pkgdeps(Deps)}])
  171. end,
  172. [{rebarconfig, RebarConf} | Config].
  173. mock_warnings() ->
  174. %% just let it do its thing, we check warnings through
  175. %% the call log.
  176. meck:new(rebar_log, [no_link, passthrough]).
  177. %%% TESTS %%%
  178. flat(Config) -> run(Config).
  179. pick_highest_left(Config) -> run(Config).
  180. pick_highest_right(Config) -> run(Config).
  181. pick_smallest1(Config) -> run(Config).
  182. pick_smallest2(Config) -> run(Config).
  183. circular1(Config) -> run(Config).
  184. circular2(Config) -> run(Config).
  185. circular_skip(Config) -> run(Config).
  186. fail_conflict(Config) ->
  187. {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
  188. rebar_test_utils:run_and_check(
  189. Config, RebarConfig, ["install_deps"], ?config(expect, Config)
  190. ),
  191. check_warnings(error_calls(), ?config(warnings, Config), ?config(deps_type, Config)).
  192. default_profile(Config) ->
  193. {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
  194. AppDir = ?config(apps, Config),
  195. {ok, Apps} = Expect = ?config(expect, Config),
  196. rebar_test_utils:run_and_check(
  197. Config, RebarConfig, ["as", "profile", "install_deps"], Expect
  198. ),
  199. check_warnings(error_calls(), ?config(warnings, Config), ?config(deps_type, Config)),
  200. BuildDir = filename:join([AppDir, "_build"]),
  201. [?assertMatch({ok, #file_info{type=directory}},
  202. file:read_file_info(filename:join([BuildDir, "default", "lib", App])))
  203. || {dep, App} <- Apps],
  204. [?assertMatch({ok, #file_info{type=directory}}, % somehow symlinks return dirs
  205. file:read_file_info(filename:join([BuildDir, "profile", "lib", App])))
  206. || {dep, App} <- Apps],
  207. %% A second run to another profile also links default to the right spot
  208. rebar_test_utils:run_and_check(
  209. Config, RebarConfig, ["as", "other", "install_deps"], Expect
  210. ),
  211. [?assertMatch({ok, #file_info{type=directory}}, % somehow symlinks return dirs
  212. file:read_file_info(filename:join([BuildDir, "other", "lib", App])))
  213. || {dep, App} <- Apps].
  214. nondefault_profile(Config) ->
  215. {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
  216. AppDir = ?config(apps, Config),
  217. {ok, Apps} = Expect = ?config(expect, Config),
  218. rebar_test_utils:run_and_check(
  219. Config, RebarConfig, ["as", "nondef", "install_deps"], Expect
  220. ),
  221. check_warnings(error_calls(), ?config(warnings, Config), ?config(deps_type, Config)),
  222. BuildDir = filename:join([AppDir, "_build"]),
  223. [?assertMatch({error, enoent},
  224. file:read_file_info(filename:join([BuildDir, "default", "lib", App])))
  225. || {dep, App} <- Apps],
  226. [?assertMatch({ok, #file_info{type=directory}},
  227. file:read_file_info(filename:join([BuildDir, "nondef", "lib", App])))
  228. || {dep, App} <- Apps],
  229. %% A second run to another profile doesn't link dependencies
  230. rebar_test_utils:run_and_check(
  231. Config, RebarConfig, ["as", "other", "install_deps"], Expect
  232. ),
  233. [?assertMatch({error, enoent},
  234. file:read_file_info(filename:join([BuildDir, "default", "lib", App])))
  235. || {dep, App} <- Apps].
  236. run(Config) ->
  237. {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
  238. rebar_test_utils:run_and_check(
  239. Config, RebarConfig, ["install_deps"], ?config(expect, Config)
  240. ),
  241. check_warnings(warning_calls(), ?config(warnings, Config), ?config(deps_type, Config)).
  242. warning_calls() ->
  243. History = meck:history(rebar_log),
  244. [{Str, Args} || {_, {rebar_log, log, [warn, Str, Args]}, _} <- History].
  245. error_calls() ->
  246. History = meck:history(rebar_log),
  247. [{Str, Args} || {_, {rebar_log, log, [error, Str, Args]}, _} <- History].
  248. check_warnings(_, [], _) ->
  249. ok;
  250. check_warnings(Warns, [{Name, Vsn} | Rest], Type) ->
  251. ct:pal("Checking for warning ~p in ~p", [{Name,Vsn},Warns]),
  252. ?assert(in_warnings(Type, Warns, Name, Vsn)),
  253. check_warnings(Warns, Rest, Type).
  254. in_warnings(git, Warns, NameRaw, VsnRaw) ->
  255. Name = iolist_to_binary(NameRaw),
  256. 1 =< length([1 || {_, [AppName, {git, _, {_, Vsn}}]} <- Warns,
  257. AppName =:= Name, Vsn =:= VsnRaw]);
  258. in_warnings(pkg, Warns, NameRaw, VsnRaw) ->
  259. Name = iolist_to_binary(NameRaw),
  260. Vsn = iolist_to_binary(VsnRaw),
  261. 1 =< length([1 || {_, [AppName, AppVsn]} <- Warns,
  262. AppName =:= Name, AppVsn =:= Vsn]).