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.

301 lines
11 KiB

пре 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, http_proxy_settings, https_proxy_settings, {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(http_proxy_settings, Config) ->
  30. %% Create private rebar.config
  31. Priv = ?config(priv_dir, Config),
  32. GlobalDir = filename:join(Priv, "global"),
  33. GlobalConfigDir = filename:join([GlobalDir, ".config", "rebar3"]),
  34. GlobalConfig = filename:join([GlobalDir, ".config", "rebar3", "rebar.config"]),
  35. meck:new(rebar_dir, [passthrough]),
  36. meck:expect(rebar_dir, global_config, fun() -> GlobalConfig end),
  37. meck:expect(rebar_dir, global_cache_dir, fun(_) -> GlobalDir end),
  38. %% Insert proxy variables into config
  39. rebar_test_utils:create_config(GlobalConfigDir,
  40. [{http_proxy, "http://localhost:1234"}
  41. ]),
  42. rebar_test_utils:init_rebar_state(Config);
  43. init_per_testcase(https_proxy_settings, Config) ->
  44. SupportsHttpsProxy = case erlang:system_info(otp_release) of
  45. "R16"++_ -> true;
  46. "R"++_ -> false;
  47. _ -> true % 17 and up don't have a "R" in the version
  48. end,
  49. if not SupportsHttpsProxy ->
  50. {skip, https_proxy_unsupported_before_R16};
  51. SupportsHttpsProxy ->
  52. %% Create private rebar.config
  53. Priv = ?config(priv_dir, Config),
  54. GlobalDir = filename:join(Priv, "global"),
  55. GlobalConfigDir = filename:join([GlobalDir, ".config", "rebar3"]),
  56. GlobalConfig = filename:join([GlobalDir, ".config", "rebar3", "rebar.config"]),
  57. meck:new(rebar_dir, [passthrough]),
  58. meck:expect(rebar_dir, global_config, fun() -> GlobalConfig end),
  59. meck:expect(rebar_dir, global_cache_dir, fun(_) -> GlobalDir end),
  60. %% Insert proxy variables into config
  61. rebar_test_utils:create_config(GlobalConfigDir,
  62. [{https_proxy, "http://localhost:1234"}
  63. ]),
  64. rebar_test_utils:init_rebar_state(Config)
  65. end;
  66. init_per_testcase(Case, Config) ->
  67. {Deps, Warnings, Expect} = deps(Case),
  68. Expected = case Expect of
  69. {ok, List} -> {ok, format_expected_deps(List)};
  70. {error, Reason} -> {error, Reason}
  71. end,
  72. DepsType = ?config(deps_type, Config),
  73. mock_warnings(),
  74. [{expect, Expected},
  75. {warnings, Warnings}
  76. | setup_project(Case, Config, rebar_test_utils:expand_deps(DepsType, Deps))].
  77. end_per_testcase(https_proxy_settings, Config) ->
  78. meck:unload(rebar_dir),
  79. Config;
  80. end_per_testcase(http_proxy_settings, Config) ->
  81. meck:unload(rebar_dir),
  82. Config;
  83. end_per_testcase(_, Config) ->
  84. meck:unload(),
  85. Config.
  86. format_expected_deps(Deps) ->
  87. [case Dep of
  88. {N,V} -> {dep, N, V};
  89. N -> {dep, N}
  90. end || Dep <- Deps].
  91. %% format:
  92. %% {Spec,
  93. %% [Warning],
  94. %% {ok, Result} | {error, Reason}}
  95. %%
  96. %% Spec is a list of levelled dependencies of two possible forms:
  97. %% - {"Name", Spec}
  98. %% - {"Name", "Vsn", Spec}
  99. %%
  100. %% Warnings are going to match on mocked ?WARN(...)
  101. %% calls to be evaluated. An empty list means we do not care about
  102. %% warnings, not that no warnings will be printed. This means
  103. %% the list of warning isn't interpreted to be exhaustive, and more
  104. %% warnings may be generated than are listed.
  105. deps(flat) ->
  106. {[{"B", []},
  107. {"C", []}],
  108. [],
  109. {ok, ["B", "C"]}};
  110. deps(pick_highest_left) ->
  111. {[{"B", [{"C", "2", []}]},
  112. {"C", "1", []}],
  113. [{"C","2"}],
  114. {ok, ["B", {"C", "1"}]}};
  115. deps(pick_highest_right) ->
  116. {[{"B", "1", []},
  117. {"C", [{"B", "2", []}]}],
  118. [{"B","2"}],
  119. {ok, [{"B","1"}, "C"]}};
  120. deps(pick_smallest1) ->
  121. {[{"B", [{"D", "1", []}]},
  122. {"C", [{"D", "2", []}]}],
  123. [{"D","2"}],
  124. %% we pick D1 because B < C
  125. {ok, ["B","C",{"D","1"}]}};
  126. deps(pick_smallest2) ->
  127. {[{"C", [{"D", "2", []}]},
  128. {"B", [{"D", "1", []}]}],
  129. [{"D","2"}],
  130. %% we pick D1 because B < C
  131. {ok, ["B","C",{"D","1"}]}};
  132. deps(circular1) ->
  133. {[{"B", [{"A", []}]}, % A is the top-level app
  134. {"C", []}],
  135. [],
  136. {error, {rebar_prv_install_deps, {cycles, [[<<"A">>,<<"B">>]]}}}};
  137. deps(circular2) ->
  138. {[{"B", [{"C", [{"B", []}]}]},
  139. {"C", []}],
  140. [],
  141. {error, {rebar_prv_install_deps, {cycles, [[<<"B">>,<<"C">>]]}}}};
  142. deps(circular_skip) ->
  143. %% Never spot the circular dep due to being to low in the deps tree
  144. %% in source deps
  145. {[{"B", [{"C", "2", [{"B", []}]}]},
  146. {"C", "1", [{"D",[]}]}],
  147. [{"C","2"}],
  148. {ok, ["B", {"C","1"}, "D"]}}.
  149. setup_project(Case, Config0, Deps) ->
  150. DepsType = ?config(deps_type, Config0),
  151. Config = rebar_test_utils:init_rebar_state(
  152. Config0,
  153. atom_to_list(Case)++"_"++atom_to_list(DepsType)++"_"
  154. ),
  155. AppDir = ?config(apps, Config),
  156. rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]),
  157. TopDeps = rebar_test_utils:top_level_deps(Deps),
  158. RebarConf = rebar_test_utils:create_config(AppDir, [{deps, TopDeps}]),
  159. {SrcDeps, PkgDeps} = rebar_test_utils:flat_deps(Deps),
  160. mock_git_resource:mock([{deps, SrcDeps}]),
  161. mock_pkg_resource:mock([{pkgdeps, PkgDeps}]),
  162. [{rebarconfig, RebarConf} | Config].
  163. mock_warnings() ->
  164. %% just let it do its thing, we check warnings through
  165. %% the call log.
  166. meck:new(rebar_log, [no_link, passthrough]).
  167. %%% TESTS %%%
  168. flat(Config) -> run(Config).
  169. pick_highest_left(Config) -> run(Config).
  170. pick_highest_right(Config) -> run(Config).
  171. pick_smallest1(Config) -> run(Config).
  172. pick_smallest2(Config) -> run(Config).
  173. circular1(Config) -> run(Config).
  174. circular2(Config) -> run(Config).
  175. circular_skip(Config) -> run(Config).
  176. %% Test that the deps of project apps that have their own rebar.config
  177. %% are included, but that top level rebar.config deps take precedence
  178. sub_app_deps(Config) ->
  179. AppDir = ?config(apps, Config),
  180. Deps = rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}
  181. ,{"b", "1.0.0", []}
  182. ,{"b", "2.0.0", []}]),
  183. {SrcDeps, _} = rebar_test_utils:flat_deps(Deps),
  184. mock_git_resource:mock([{deps, SrcDeps}]),
  185. Name = rebar_test_utils:create_random_name("sub_app1_"),
  186. Vsn = rebar_test_utils:create_random_vsn(),
  187. SubAppsDir = filename:join([AppDir, "apps", Name]),
  188. SubDeps = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}
  189. ,{"b", "2.0.0", []}])),
  190. rebar_test_utils:create_app(SubAppsDir, Name, Vsn, [kernel, stdlib]),
  191. rebar_test_utils:create_config(SubAppsDir, [{deps, SubDeps}]),
  192. TopDeps = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [{"b", "1.0.0", []}])),
  193. {ok, RebarConfig} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, TopDeps}])),
  194. rebar_test_utils:run_and_check(
  195. Config, RebarConfig, ["compile"],
  196. {ok, [{app, Name}, {dep, "a"}, {dep, "b", "1.0.0"}]}).
  197. %% Newly added dependency after locking
  198. newly_added_dep(Config) ->
  199. AppDir = ?config(apps, Config),
  200. Deps = rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}
  201. ,{"b", "1.0.0", [{"c", "1.0.0", []}]}
  202. ,{"c", "2.0.0", []}]),
  203. {SrcDeps, _} = rebar_test_utils:flat_deps(Deps),
  204. mock_git_resource:mock([{deps, SrcDeps}]),
  205. Name = rebar_test_utils:create_random_name("app_"),
  206. Vsn = rebar_test_utils:create_random_vsn(),
  207. SubAppsDir = filename:join([AppDir, "apps", Name]),
  208. rebar_test_utils:create_app(SubAppsDir, Name, Vsn, [kernel, stdlib]),
  209. TopDeps = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [{"b", "1.0.0", []}])),
  210. {ok, RebarConfig} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, TopDeps}])),
  211. rebar_test_utils:run_and_check(
  212. Config, RebarConfig, ["compile"],
  213. {ok, [{app, Name}, {dep, "b", "1.0.0"}, {dep, "c", "1.0.0"}]}),
  214. %% Add a and c to top level
  215. TopDeps2 = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}
  216. ,{"c", "2.0.0", []}
  217. ,{"b", "1.0.0", []}])),
  218. {ok, RebarConfig2} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, TopDeps2}])),
  219. LockFile = filename:join(AppDir, "rebar.lock"),
  220. RebarConfig3 = rebar_config:merge_locks(RebarConfig2,
  221. rebar_config:consult_lock_file(LockFile)),
  222. %% a should now be installed and c should not change
  223. rebar_test_utils:run_and_check(
  224. Config, RebarConfig3, ["compile"],
  225. {ok, [{app, Name}, {dep, "a"}, {dep, "b", "1.0.0"}, {dep, "c", "1.0.0"}]}).
  226. http_proxy_settings(_Config) ->
  227. %% Load config
  228. rebar_utils:set_httpc_options(),
  229. rebar3:init_config(),
  230. %% Assert variable is right
  231. ?assertEqual({ok,{{"localhost", 1234}, []}},
  232. httpc:get_option(proxy, rebar)).
  233. https_proxy_settings(_Config) ->
  234. %% Load config
  235. rebar_utils:set_httpc_options(),
  236. rebar3:init_config(),
  237. %% Assert variable is right
  238. ?assertEqual({ok,{{"localhost", 1234}, []}},
  239. httpc:get_option(https_proxy, rebar)).
  240. run(Config) ->
  241. {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
  242. rebar_test_utils:run_and_check(
  243. Config, RebarConfig, ["install_deps"], ?config(expect, Config)
  244. ),
  245. check_warnings(warning_calls(), ?config(warnings, Config), ?config(deps_type, Config)).
  246. warning_calls() ->
  247. History = meck:history(rebar_log),
  248. [{Str, Args} || {_, {rebar_log, log, [warn, Str, Args]}, _} <- History].
  249. check_warnings(_, [], _) ->
  250. ok;
  251. check_warnings(Warns, [{Name, Vsn} | Rest], Type) ->
  252. ct:pal("Checking for warning ~p in ~p", [{Name,Vsn},Warns]),
  253. ?assert(in_warnings(Type, Warns, Name, Vsn)),
  254. check_warnings(Warns, Rest, Type).
  255. in_warnings(git, Warns, NameRaw, VsnRaw) ->
  256. Name = iolist_to_binary(NameRaw),
  257. 1 =< length([1 || {_, [AppName, {git, _, {_, Vsn}}]} <- Warns,
  258. AppName =:= Name, Vsn =:= VsnRaw]);
  259. in_warnings(pkg, Warns, NameRaw, VsnRaw) ->
  260. Name = iolist_to_binary(NameRaw),
  261. Vsn = iolist_to_binary(VsnRaw),
  262. 1 =< length([1 || {_, [AppName, {pkg, _, AppVsn}]} <- Warns,
  263. AppName =:= Name, AppVsn =:= Vsn]).