Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

295 rader
11 KiB

  1. -module(rebar_paths_SUITE).
  2. -include_lib("eunit/include/eunit.hrl").
  3. -include_lib("common_test/include/ct.hrl").
  4. -compile(export_all).
  5. all() ->
  6. [clashing_apps,
  7. check_modules,
  8. set_paths,
  9. misloaded_mods
  10. ].
  11. %%%%%%%%%%%%%%%%%%
  12. %%% TEST SETUP %%%
  13. %%%%%%%%%%%%%%%%%%
  14. init_per_testcase(Case, Config) ->
  15. BasePaths = code:get_path(),
  16. %% This test checks that the right module sets get loaded; however, we must
  17. %% ensure that we do not have clashes with other test suites' loaded modules,
  18. %% which we cannot track. As such, we have to ensure all module names here are
  19. %% unique.
  20. %%
  21. %% This is done by hand; if you see this test suite failing on its own, you
  22. %% probably wrote a test suite that clashes!
  23. Dir = filename:join([?config(priv_dir, Config), atom_to_list(?MODULE),
  24. atom_to_list(Case)]),
  25. InDir = fun(Path) -> filename:join([Dir, Path]) end,
  26. ADep = fake_app(<<"rp_a">>, <<"1.0.0">>, InDir("_build/default/lib/rp_a/")),
  27. BDep = fake_app(<<"rp_b">>, <<"1.0.0">>, InDir("_build/default/lib/rp_b/")),
  28. CDep = fake_app(<<"rp_c">>, <<"1.0.0">>, InDir("_build/default/lib/rp_c/")),
  29. DDep = fake_app(<<"rp_d">>, <<"1.0.0">>, InDir("_build/default/lib/rp_d/")),
  30. RelxDep = fake_app(<<"relx">>, <<"1.0.0">>, InDir("_build/default/lib/relx/")),
  31. APlug = fake_app(<<"rp_a">>, <<"1.0.0">>,
  32. InDir("_build/default/plugins/lib/rp_a/")),
  33. RelxPlug = fake_app(<<"relx">>, <<"1.1.1">>,
  34. InDir("_build/default/plugins/lib/relx")),
  35. EPlug = fake_app(<<"rp_e">>, <<"1.0.0">>,
  36. InDir("_build/default/plugins/lib/rp_e/")),
  37. TopApp0 = fake_app(<<"top_app">>, <<"1.0.0">>, InDir("_build/default/lib/top_app/"), [<<"rp_a">>, <<"rp_b">>]),
  38. TopApp1 = rebar_app_info:applications(TopApp0, ['rp_a', 'rp_b']),
  39. S0 = rebar_state:new(),
  40. S1 = rebar_state:all_deps(S0, [ADep, BDep, CDep, DDep, RelxDep]),
  41. S2 = rebar_state:all_plugin_deps(S1, [APlug, RelxPlug]),
  42. S3 = rebar_state:project_apps(S2, [TopApp1]),
  43. S4 = rebar_state:code_paths(S3, default, code:get_path()),
  44. S5 = rebar_state:code_paths(
  45. S4,
  46. all_deps,
  47. [rebar_app_info:ebin_dir(A) || A <- [ADep, BDep, CDep, DDep, RelxDep]]
  48. ),
  49. S6 = rebar_state:code_paths(
  50. S5,
  51. all_plugin_deps,
  52. [rebar_app_info:ebin_dir(A) || A <- [APlug, RelxPlug, EPlug]]
  53. ),
  54. [{base_paths, BasePaths}, {root_dir, Dir}, {state, S6} | Config].
  55. end_per_testcase(_, Config) ->
  56. %% this is deeply annoying because we interfere with rebar3's own
  57. %% path handling!
  58. rebar_paths:unset_paths([plugins, deps], ?config(state, Config)),
  59. Config.
  60. fake_app(Name, Vsn, OutDir) ->
  61. {ok, App} = rebar_app_info:new(Name, Vsn, OutDir),
  62. compile_fake_appmod(App, []),
  63. App.
  64. fake_app(Name, Vsn, OutDir, Apps) ->
  65. {ok, App} = rebar_app_info:new(Name, Vsn, OutDir),
  66. compile_fake_appmod(App, Apps),
  67. App.
  68. compile_fake_appmod(App, Apps) ->
  69. OutDir = rebar_app_info:ebin_dir(App),
  70. Vsn = rebar_app_info:original_vsn(App),
  71. Name = rebar_app_info:name(App),
  72. AppsStr = apps_to_str(Apps),
  73. ok = filelib:ensure_dir(filename:join([OutDir, ".touch"])),
  74. AppFile = [
  75. "{application,", Name, ", "
  76. " [{description, \"some app\"}, "
  77. " {vsn, \"", Vsn, "\"}, "
  78. " {modules, [",Name,"]}, "
  79. " {registered, []}, "
  80. " {applications, [" ++ AppsStr ++ "]} "
  81. " ]}. "],
  82. ok = file:write_file(filename:join([OutDir, <<Name/binary, ".app">>]), AppFile),
  83. Mod = [{attribute, 1, module, binary_to_atom(Name, utf8)},
  84. {attribute, 2, export, [{f,0}]},
  85. {function,3,f,0,
  86. [{clause,3, [], [],
  87. [{string,3,OutDir}]
  88. }]}
  89. ],
  90. {ok, _, Bin} = compile:forms(Mod),
  91. ok = file:write_file(filename:join([OutDir, <<Name/binary, ".beam">>]), Bin).
  92. %%%%%%%%%%%%%
  93. %%% TESTS %%%
  94. %%%%%%%%%%%%%
  95. clashing_apps(Config) ->
  96. Clashes = rebar_paths:clashing_apps([deps, plugins],
  97. ?config(state, Config)),
  98. ct:pal("Clashes: ~p", [Clashes]),
  99. ?assertEqual([<<"relx">>, <<"rp_a">>], lists:sort(proplists:get_value(deps, Clashes))),
  100. ?assertEqual([], proplists:get_value(plugins, Clashes)),
  101. ok.
  102. set_paths(Config) ->
  103. State = ?config(state, Config),
  104. RootDir = filename:split(?config(root_dir, Config)),
  105. %% Take a snapshot of runtime deps being set; to see if your test is valid, this should fail
  106. %% when you set the [deps] paths here
  107. rebar_paths:set_paths([runtime], State),
  108. RuntimePaths = code:get_path(),
  109. %% Revert back to regular dep paths
  110. rebar_paths:set_paths([plugins, deps], State),
  111. PluginPaths = code:get_path(),
  112. rebar_paths:set_paths([deps, plugins], State),
  113. DepPaths = code:get_path(),
  114. %% Plugin related paths checks
  115. ?assertEqual(
  116. RootDir ++ ["_build", "default", "plugins", "lib", "rp_a", "ebin"],
  117. find_first_instance(RootDir, "rp_a", PluginPaths)
  118. ),
  119. ?assertEqual(
  120. RootDir ++ ["_build", "default", "lib", "rp_b", "ebin"],
  121. find_first_instance(RootDir, "rp_b", PluginPaths)
  122. ),
  123. ?assertEqual(
  124. RootDir ++ ["_build", "default", "lib", "rp_c", "ebin"],
  125. find_first_instance(RootDir, "rp_c", PluginPaths)
  126. ),
  127. ?assertEqual(
  128. RootDir ++ ["_build", "default", "lib", "rp_d", "ebin"],
  129. find_first_instance(RootDir, "rp_d", PluginPaths)
  130. ),
  131. ?assertEqual(
  132. RootDir ++ ["_build", "default", "plugins", "lib", "rp_e", "ebin"],
  133. find_first_instance(RootDir, "rp_e", PluginPaths)
  134. ),
  135. ?assertEqual(
  136. RootDir ++ ["_build", "default", "plugins", "lib", "relx", "ebin"],
  137. find_first_instance(RootDir, "relx", PluginPaths)
  138. ),
  139. %% Dependency related paths checks
  140. ?assertEqual(
  141. RootDir ++ ["_build", "default", "lib", "rp_a", "ebin"],
  142. find_first_instance(RootDir, "rp_a", DepPaths)
  143. ),
  144. ?assertEqual(
  145. RootDir ++ ["_build", "default", "lib", "rp_b", "ebin"],
  146. find_first_instance(RootDir, "rp_b", DepPaths)
  147. ),
  148. ?assertEqual(
  149. RootDir ++ ["_build", "default", "lib", "rp_c", "ebin"],
  150. find_first_instance(RootDir, "rp_c", DepPaths)
  151. ),
  152. ?assertEqual(
  153. RootDir ++ ["_build", "default", "lib", "rp_d", "ebin"],
  154. find_first_instance(RootDir, "rp_d", DepPaths)
  155. ),
  156. ?assertEqual(
  157. RootDir ++ ["_build", "default", "plugins", "lib", "rp_e", "ebin"],
  158. find_first_instance(RootDir, "rp_e", DepPaths)
  159. ),
  160. ?assertEqual(
  161. RootDir ++ ["_build", "default", "lib", "relx", "ebin"],
  162. find_first_instance(RootDir, "relx", DepPaths)
  163. ),
  164. %% Runtime related paths checks
  165. ?assertEqual(
  166. RootDir ++ ["_build", "default", "lib", "rp_a", "ebin"],
  167. find_first_instance(RootDir, "rp_a", RuntimePaths)
  168. ),
  169. ?assertEqual(
  170. RootDir ++ ["_build", "default", "lib", "rp_b", "ebin"],
  171. find_first_instance(RootDir, "rp_b", RuntimePaths)
  172. ),
  173. ?assertMatch(
  174. {not_found, _},
  175. find_first_instance(RootDir, "rp_c", RuntimePaths)
  176. ),
  177. ?assertMatch(
  178. {not_found, _},
  179. find_first_instance(RootDir, "rp_d", RuntimePaths)
  180. ),
  181. ?assertMatch(
  182. {not_found, _},
  183. find_first_instance(RootDir, "rp_e", RuntimePaths)
  184. ),
  185. ?assertMatch(
  186. {not_found, _},
  187. find_first_instance(RootDir, "relx", RuntimePaths)
  188. ),
  189. ok.
  190. check_modules(Config) ->
  191. State = ?config(state, Config),
  192. RootDir = ?config(root_dir, Config)++"/",
  193. rebar_paths:set_paths([plugins, deps], State),
  194. ct:pal("code:get_path() -> ~p", [code:get_path()]),
  195. ?assertEqual(RootDir ++ "_build/default/plugins/lib/rp_a/ebin", rp_a:f()),
  196. ct:pal("~p", [catch file:list_dir(RootDir ++ "_build/default/lib/")]),
  197. ct:pal("~p", [catch file:list_dir(RootDir ++ "_build/default/lib/rp_b/")]),
  198. ct:pal("~p", [catch file:list_dir(RootDir ++ "_build/default/lib/rp_b/ebin")]),
  199. ct:pal("~p", [catch b:module_info()]),
  200. ?assertEqual(RootDir ++ "_build/default/lib/rp_b/ebin", rp_b:f()),
  201. ?assertEqual(RootDir ++ "_build/default/lib/rp_c/ebin", rp_c:f()),
  202. ?assertEqual(RootDir ++ "_build/default/lib/rp_d/ebin", rp_d:f()),
  203. ?assertEqual(RootDir ++ "_build/default/plugins/lib/rp_e/ebin", rp_e:f()),
  204. ?assertEqual(RootDir ++ "_build/default/plugins/lib/relx/ebin", relx:f()),
  205. ?assertEqual(3, length(relx:module_info(exports))), % can't replace bundled
  206. rebar_paths:set_paths([deps, plugins], State),
  207. ct:pal("code:get_path() -> ~p", [code:get_path()]),
  208. ?assertEqual(RootDir ++ "_build/default/lib/rp_a/ebin", rp_a:f()),
  209. ?assertEqual(RootDir ++ "_build/default/lib/rp_b/ebin", rp_b:f()),
  210. ?assertEqual(RootDir ++ "_build/default/lib/rp_c/ebin", rp_c:f()),
  211. ?assertEqual(RootDir ++ "_build/default/lib/rp_d/ebin", rp_d:f()),
  212. ?assertEqual(RootDir ++ "_build/default/plugins/lib/rp_e/ebin", rp_e:f()),
  213. ?assertEqual(RootDir ++ "_build/default/lib/relx/ebin", relx:f()),
  214. ?assertEqual(3, length(relx:module_info(exports))), % can't replace bundled
  215. %% once again
  216. rebar_paths:set_paths([plugins, deps], State),
  217. ct:pal("code:get_path() -> ~p", [code:get_path()]),
  218. ?assertEqual(RootDir ++ "_build/default/plugins/lib/rp_a/ebin", rp_a:f()),
  219. ?assertEqual(RootDir ++ "_build/default/lib/rp_b/ebin", rp_b:f()),
  220. ?assertEqual(RootDir ++ "_build/default/lib/rp_c/ebin", rp_c:f()),
  221. ?assertEqual(RootDir ++ "_build/default/lib/rp_d/ebin", rp_d:f()),
  222. ?assertEqual(RootDir ++ "_build/default/plugins/lib/rp_e/ebin", rp_e:f()),
  223. ?assertEqual(RootDir ++ "_build/default/plugins/lib/relx/ebin", relx:f()),
  224. ?assertEqual(3, length(relx:module_info(exports))), % can't replace bundled
  225. ok.
  226. misloaded_mods(_Config) ->
  227. Res = rebar_paths:misloaded_modules(
  228. ["/1/2/3/4",
  229. "/1/2/4",
  230. "/2/1/1",
  231. "/3/4/5"],
  232. [{a, "/0/1/2/file.beam"},
  233. {b, "/1/2/3/4/file.beam"},
  234. {c, "/2/1/file.beam"},
  235. {f, preloaded},
  236. {d, "/3/5/7/file.beam"},
  237. {e, "/3/4/5/file.beam"}]
  238. ),
  239. ?assertEqual([a,c,d], Res),
  240. ok.
  241. %%%%%%%%%%%%%%%
  242. %%% HELPERS %%%
  243. %%%%%%%%%%%%%%%
  244. find_first_instance(_RootDir, Frag, []) ->
  245. {not_found, Frag};
  246. find_first_instance(RootDir, Frag, [Path|Rest]) ->
  247. Frags = filename:split(Path),
  248. case lists:member(Frag, Frags) of
  249. true ->
  250. %% When testing the runtime deps the paths would have
  251. %% apps such as `relx' that were not from within the root dir.
  252. case re:run(Frags, RootDir) of
  253. nomatch -> find_first_instance(RootDir, Frag, Rest);
  254. {match, _} -> Frags
  255. end;
  256. false -> find_first_instance(RootDir, Frag, Rest)
  257. end.
  258. apps_to_str([]) ->
  259. "stdlib, kernel";
  260. apps_to_str(Apps) ->
  261. AppsStr = unicode:characters_to_list(lists:join(", ", Apps)),
  262. "stdlib, kernel, " ++ AppsStr.