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.

297 rivejä
10 KiB

10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
  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. lists:append([case Dep of
  43. {N,V} -> [{dep, N, V}, {lock, N, V}];
  44. N -> [{dep, N}, {lock, 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, ["lock"], ?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", "lock"], 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", "lock"], 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. %% The dependencies here are saved directly to the
  216. {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
  217. AppDir = ?config(apps, Config),
  218. {ok, AppLocks} = ?config(expect, Config),
  219. try
  220. rebar_test_utils:run_and_check(
  221. Config, RebarConfig, ["as", "nondef", "lock"], {ok, AppLocks}
  222. ),
  223. error(generated_locks)
  224. catch
  225. error:generated_locks -> error(generated_locks);
  226. _:_ -> ok
  227. end,
  228. Apps = [App || App = {dep, _} <- AppLocks],
  229. Expect = {ok, Apps},
  230. rebar_test_utils:run_and_check(
  231. Config, RebarConfig, ["as", "nondef", "lock"], Expect
  232. ),
  233. check_warnings(error_calls(), ?config(warnings, Config), ?config(deps_type, Config)),
  234. BuildDir = filename:join([AppDir, "_build"]),
  235. [?assertMatch({error, enoent},
  236. file:read_file_info(filename:join([BuildDir, "default", "lib", App])))
  237. || {dep, App} <- Apps],
  238. [?assertMatch({ok, #file_info{type=directory}},
  239. file:read_file_info(filename:join([BuildDir, "nondef", "lib", App])))
  240. || {dep, App} <- Apps],
  241. %% A second run to another profile doesn't link dependencies
  242. rebar_test_utils:run_and_check(
  243. Config, RebarConfig, ["as", "other", "lock"], Expect
  244. ),
  245. [?assertMatch({error, enoent},
  246. file:read_file_info(filename:join([BuildDir, "default", "lib", App])))
  247. || {dep, App} <- Apps].
  248. run(Config) ->
  249. {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
  250. rebar_test_utils:run_and_check(
  251. Config, RebarConfig, ["lock"], ?config(expect, Config)
  252. ),
  253. check_warnings(warning_calls(), ?config(warnings, Config), ?config(deps_type, Config)).
  254. warning_calls() ->
  255. History = meck:history(rebar_log),
  256. [{Str, Args} || {_, {rebar_log, log, [warn, Str, Args]}, _} <- History].
  257. error_calls() ->
  258. History = meck:history(rebar_log),
  259. [{Str, Args} || {_, {rebar_log, log, [error, Str, Args]}, _} <- History].
  260. check_warnings(_, [], _) ->
  261. ok;
  262. check_warnings(Warns, [{Name, Vsn} | Rest], Type) ->
  263. ct:pal("Checking for warning ~p in ~p", [{Name,Vsn},Warns]),
  264. ?assert(in_warnings(Type, Warns, Name, Vsn)),
  265. check_warnings(Warns, Rest, Type).
  266. in_warnings(git, Warns, NameRaw, VsnRaw) ->
  267. Name = iolist_to_binary(NameRaw),
  268. 1 =< length([1 || {_, [AppName, {git, _, {_, Vsn}}]} <- Warns,
  269. AppName =:= Name, Vsn =:= VsnRaw]);
  270. in_warnings(pkg, Warns, NameRaw, VsnRaw) ->
  271. Name = iolist_to_binary(NameRaw),
  272. Vsn = iolist_to_binary(VsnRaw),
  273. 1 =< length([1 || {_, [AppName, AppVsn]} <- Warns,
  274. AppName =:= Name, AppVsn =:= Vsn]).