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.

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